|
- {
- TextSuite (C) Steffen Xonna (aka Lossy eX)
- http://www.opengl24.de/
- -----------------------------------------------------------------------
- For copyright informations see file copyright.txt.
- }
-
- {$WARNINGS OFF}
- {$HINTS OFF}
-
- {$I TextSuiteOptions.inc}
-
- unit TextSuiteClasses;
-
- interface
-
-
- uses
- Classes,
-
- TextSuite,
- TextSuiteWideUtils,
- TextSuiteImports;
-
-
- { intern types for Renderer }
- const
- TS_BLOCK_FONT = $1;
- TS_BLOCK_COLOR = $2;
- TS_BLOCK_WORD = $3;
- TS_BLOCK_SPACE = $4;
- TS_BLOCK_LINEBREAK = $5;
- TS_BLOCK_TAB = $6;
-
-
- type
- TtsFontStyle = (tsStyleBold, tsStyleItalic, tsStyleUnderline, tsStyleStrikeout);
- TtsFontStyles = set of TtsFontStyle;
-
- TtsAntiAliasing = (tsAANone, tsAANormal);
- TtsFormat = (tsFormatEmpty, tsFormatRGBA8);
-
- TtsImageMode = (tsModeRed, tsModeGreen, tsModeBlue, tsModeAlpha, tsModeLuminance);
- TtsImageModes = array [TtsImageMode] of tsEnum;
-
-
- tsQuad = array[0..3] of tsPoint;
-
- tsPointFloat = packed record
- X: Single;
- Y: Single;
- end;
- tsQuadFloat = array[0..3] of tsPointFloat;
-
-
- const
- cModesReplace : TtsImageModes = (TS_MODE_REPLACE, TS_MODE_REPLACE, TS_MODE_REPLACE, TS_MODE_REPLACE, TS_MODE_REPLACE);
- cModesNormal : TtsImageModes = (TS_MODE_REPLACE, TS_MODE_REPLACE, TS_MODE_REPLACE, TS_MODE_MODULATE, TS_MODE_REPLACE);
-
- type
- PtsHashEntry = ^TtsHashEntry;
- TtsHashEntry = record
- Name: Integer;
- Value: Pointer;
- Next: PtsHashEntry;
- end;
-
- TtsHash = class(TObject)
- private
- fHashArray: array of PtsHashEntry;
- fHashEntrys: Integer;
- fCount: Integer;
-
- function IntToPos(Name: Integer): Integer;
- public
- property Count: Integer read fCount;
-
- constructor Create(HashEntrys: Integer);
- destructor Destroy; override;
-
- procedure Add(Name: Integer; Value: Pointer);
- procedure Delete(Name: Integer);
- procedure Clear;
-
- function Get(Name: Integer): Pointer;
- procedure GetNames(const NameList: TList);
- procedure GetValues(const ValueList: TList);
- end;
-
-
- PtsStringHashEntry = ^TtsStringHashEntry;
- TtsStringHashEntry = record
- pString: pWideChar;
- Next: PtsStringHashEntry;
- end;
-
- TtsStringHash = class(TObject)
- private
- fHashArray: array of PtsStringHashEntry;
- fHashEntrys: Cardinal;
- public
- constructor Create(HashEntrys: Integer);
- destructor Destroy; override;
-
- procedure Add(pString: pWideChar);
- function Delete(pString: pWideChar): Boolean;
- end;
-
-
- TtsKernel1DItem = packed record
- Offset: Integer;
- Value: Single;
-
- DataOffset: Integer;
- end;
-
- TtsKernel1D = class
- public
- Size: Integer;
- ValueSum: Double;
-
- Items: array of TtsKernel1DItem;
- ItemCount: Integer;
-
- constructor Create(Radius, Strength: Single);
-
- procedure UpdateDataOffset(DataSize: Integer);
- end;
-
-
- TtsKernel2DItem = packed record
- OffsetX: Integer;
- OffsetY: Integer;
- Value: Single;
-
- DataOffset: Integer;
- end;
-
- TtsKernel2D = class
- public
- SizeX: Integer;
- SizeY: Integer;
-
- MidSizeX: Integer;
- MidSizeY: Integer;
-
- ValueSum: Double;
-
- Items: array of TtsKernel2DItem;
- ItemCount: Integer;
-
- constructor Create(Radius, Strength: Single);
-
- procedure UpdateDataOffset(DataSizeX, DataSizeY: Integer);
- end;
-
-
- TtsImage = class;
- TtsRenderer = class;
- TtsRendererImageReference = class;
- TtsContext = class;
- TtsChar = class;
-
-
- TtsImageFunc = procedure(Image: TtsImage; X, Y: Integer; var Pixel: tsColor; Data: Pointer);
-
- TtsImage = class
- private
- fWidth: Integer;
- fHeight: Integer;
- fFormat: TtsFormat;
-
- fData: Pointer;
- fScanLinesValid: Boolean;
- fScanLines: array of Pointer;
-
- procedure SetDataPtr(aData: Pointer; aFormat: TtsFormat = tsFormatEmpty; aWidth: Integer = 0; aHeight: Integer = 0);
-
- function GetFormatSize(Format: TtsFormat): Integer;
-
- procedure UpdateScanLines;
- function GetScanLine(Index: Integer): pointer;
- function GetEmpty: Boolean;
- public
- procedure BeforeDestruction; override;
-
- procedure AssignFrom(Image: TtsImage);
- procedure CreateEmpty(Format: TtsFormat; aWidth, aHeight: Integer);
- procedure LoadFromFile(FileName: PAnsiChar);
-
- procedure Resize(NewWidth, NewHeight, X, Y: Integer);
- procedure FindMinMax(var MinMaxInfo: tsRect);
-
- procedure AddFunc(Func: TtsImageFunc; Data: Pointer);
-
- procedure FillColor(Red, Green, Blue, Alpha: Single; ChannelMask: tsBitmask; Modes: TtsImageModes);
- procedure FillPattern(Pattern: TtsImage; X, Y: Integer; ChannelMask: tsBitmask; Modes: TtsImageModes);
-
- procedure BlendImage(Image: TtsImage; X, Y: Integer; AutoExpand: Boolean = True);
- procedure Blur(HorzKernel, VertKernel: TtsKernel1D; ChannelMask: tsBitmask);
-
- procedure AddResizingBorder(tsChar: TtsChar);
-
- property Empty: Boolean read GetEmpty;
-
- property Data: Pointer read fData;
- property Width: Integer read fWidth;
- property Height: Integer read fHeight;
- property Format: TtsFormat read fFormat;
-
- property ScanLine[Index: Integer]: pointer read GetScanline;
- end;
-
-
- TtsChar = class
- protected
- // CharCode
- fCharCode: WideChar;
- public
- // Position of char
- GlyphOriginX: Smallint;
- GlyphOriginY: Smallint;
- Advance: SmallInt;
- GlyphRect: tsRect;
-
- HasResizingBorder: Boolean;
-
- // Kerning
- // KerningValuesLeft: array of WORD;
- // KerningValuesRight: array of WORD;
-
- // Renderer data for Imagehandling
- RendererImageReference: TtsRendererImageReference;
-
- constructor Create(CharCode: WideChar);
- destructor Destroy; override;
-
- procedure ExpandRect(Left, Top, Right, Bottom: Integer);
-
- // Kerning
- // procedure CalculateKerningData(CharImage: TtsImage);
- // function CalculateKerningValue(LastChar: TtsChar): Smallint;
-
- // CharCode
- property CharCode: WideChar read fCharCode;
- end;
-
-
- PtsFontCharArray = ^TtsFontCharArray;
- TtsFontCharArray = packed record
- Chars: array [Byte] of TtsChar;
- CharCount: Byte;
- end;
-
-
- TtsTextMetric = record
- Ascent: Integer;
- Descent: Integer;
- LineSkip: Integer;
- LineSkip_with_LineSpace: Integer;
- end;
-
-
- TtsFont = class
- private
- // Strings
- fCopyright: AnsiString;
- fFaceName: AnsiString;
- fStyleName: AnsiString;
- fFullName: AnsiString;
-
- // font styles
- fSize: Integer;
- fStyle: TtsFontStyles;
- fFormat: TtsFormat;
- fAntiAliasing: TtsAntiAliasing;
-
- // font settings
- fAscent: Integer;
- fDescent: Integer;
- fExternalLeading: Integer;
- fBaselineOffset: Integer;
-
- fDefaultChar: WideChar;
-
- fFontFileStyle: Integer;
- fFixedWidth: Boolean;
-
- fCharSpacing: Integer;
- fLineSpacing: Integer;
-
- fUnderlinePosition: Integer;
- fUnderlineSize: Integer;
- fStrikeoutPosition: Integer;
- fStrikeoutSize: Integer;
-
- // chars
- fChars: array [Byte] of PtsFontCharArray;
- protected
- fRenderer: TtsRenderer;
-
- function Validate(CharCode: WideChar): Boolean; virtual;
-
- procedure AddChar(CharCode: WideChar; Char: TtsChar);
- function GetChar(CharCode: WideChar): TtsChar;
- public
- // chars
- property Char[CharCode: WideChar]: TtsChar read GetChar;
-
- // strings
- property Copyright: AnsiString read fCopyright write fCopyright;
- property FaceName: AnsiString read fFaceName write fFaceName;
- property StyleName: AnsiString read fStyleName write fStyleName;
- property FullName: AnsiString read fFullName write fFullName;
-
- property Size: Integer read fSize write fSize;
- property Style: TtsFontStyles read fStyle write fStyle;
- property Format: TtsFormat read fFormat write fFormat;
- property AntiAliasing: TtsAntiAliasing read fAntiAliasing write fAntiAliasing;
-
- // Font propertys
- property Ascent: Integer read fAscent write fAscent;
- property Descent: Integer read fDescent write fDescent;
- property ExternalLeading: Integer read fExternalLeading write fExternalLeading;
- property BaselineOffset: Integer read fBaselineOffset write fBaselineOffset;
-
- property DefaultChar: WideChar read fDefaultChar write fDefaultChar;
-
- property FontFileStyle: Integer read fFontFileStyle write fFontFileStyle;
- property FixedWidth: Boolean read fFixedWidth write fFixedWidth;
-
- property CharSpacing: Integer read fCharSpacing write fCharSpacing;
- property LineSpacing: Integer read fLineSpacing write fLineSpacing;
-
- property UnderlinePosition: Integer read fUnderlinePosition write fUnderlinePosition;
- property UnderlineSize: Integer read fUnderlineSize write fUnderlineSize;
- property StrikeoutPosition: Integer read fStrikeoutPosition write fStrikeoutPosition;
- property StrikeoutSize: Integer read fStrikeoutSize write fStrikeoutSize;
-
- constructor Create(Renderer: TtsRenderer; Size: Integer; Style: TtsFontStyles; Format: TtsFormat; AntiAliasing: TtsAntiAliasing);
- destructor Destroy; override;
-
- procedure ClearChars;
-
- procedure DeleteChar(CharCode: WideChar);
-
- procedure GetTextMetric(var Metric: TtsTextMetric);
- end;
-
-
- PtsPostProcessStepRange = ^TtsPostProcessStepRange;
- TtsPostProcessStepRange = record
- StartChar: WideChar;
- EndChar: WideChar;
- end;
-
- TtsFontProcessStepUsage = (tsUInclude, tsUExclude);
-
- TtsPostProcessStep = class
- protected
- fIncludeCharRange: TList;
- fExcludeCharRange: TList;
-
- procedure ClearList(List: TList);
-
- procedure PostProcess(const CharImage: TtsImage; const Char: TtsChar); virtual; abstract;
- public
- constructor Create;
- destructor Destroy; override;
-
- function IsInRange(CharCode: WideChar): Boolean;
- procedure AddUsageRange(Usage: TtsFontProcessStepUsage; StartChar, EndChar: WideChar);
- procedure AddUsageChars(Usage: TtsFontProcessStepUsage; Chars: pWideChar);
-
- procedure ClearIncludeRange;
- procedure ClearExcludeRange;
- end;
-
-
- TtsFontCreator = class(TtsFont)
- private
- fPostProcessSteps: TList;
-
- function GetPostProcessStepCount: Integer;
- function GetPostProcessStep(Index: Integer): TtsPostProcessStep;
- protected
- fCreateChars: Boolean;
- fAddResizingBorder: Boolean;
-
- function Validate(CharCode: WideChar): Boolean; override;
-
- function GetGlyphMetrics(CharCode: WideChar; var GlyphOriginX, GlyphOriginY, GlyphWidth, GlyphHeight, Advance: Integer): Boolean; virtual; abstract;
-
- procedure GetCharImage(CharCode: WideChar; const CharImage: TtsImage); virtual; abstract;
-
- procedure DrawLine(Char: TtsChar; CharImage: TtsImage; LinePosition, LineSize: Integer);
- procedure DoPostProcess(var CharImage: TtsImage; const tsChar: TtsChar);
- public
- property CreateChars: Boolean read fCreateChars write fCreateChars;
- property AddResizingBorder: Boolean read fAddResizingBorder write fAddResizingBorder;
-
- constructor Create(Renderer: TtsRenderer; Size: Integer; Style: TtsFontStyles; Format: TtsFormat; AntiAliasing: TtsAntiAliasing);
- destructor Destroy; override;
-
- procedure AddChar(CharCode: WideChar); overload;
-
- function AddPostProcessStep(PostProcessStep: TtsPostProcessStep): TtsPostProcessStep;
- procedure DeletePostProcessStep(Index: Integer);
- procedure ClearPostProcessSteps;
-
- property PostProcessStepCount: Integer read GetPostProcessStepCount;
- property PostProcessStep[Index: Integer]: TtsPostProcessStep read GetPostProcessStep;
- end;
-
-
- TtsFontCreatorSDL = class(TtsFontCreator)
- protected
- fSDLFont: PTTF_Font;
-
- function GetGlyphMetrics(CharCode: WideChar; var GlyphOriginX, GlyphOriginY, GlyphWidth, GlyphHeight, Advance: Integer): Boolean; override;
-
- procedure GetCharImage(CharCode: WideChar; const CharImage: TtsImage); override;
- public
- constructor Create(Renderer: TtsRenderer; const Filename: AnsiString; Size: Integer; Style: TtsFontStyles; Format: TtsFormat; AntiAliasing: TtsAntiAliasing);
- destructor Destroy; override;
- end;
-
-
- TtsFontCreatorGDIFontFace = class(TtsFontCreator)
- protected
- fFontHandle: THandle;
- fMat2: TMat2;
-
- fFontname: AnsiString;
-
- function GetGlyphIndex(CharCode: WideChar): Integer;
-
- function GetGlyphMetrics(CharCode: WideChar; var GlyphOriginX, GlyphOriginY, GlyphWidth, GlyphHeight, Advance: Integer): Boolean; override;
-
- procedure GetCharImageAntialiased(DC: HDC; CharCode: WideChar; const CharImage: TtsImage);
- procedure GetCharImageNone(DC: HDC; CharCode: WideChar; const CharImage: TtsImage);
-
- procedure GetCharImage(CharCode: WideChar; const CharImage: TtsImage); override;
- public
- constructor Create(Renderer: TtsRenderer; const Fontname: AnsiString; Size: Integer; Style: TtsFontStyles; Format: TtsFormat; AntiAliasing: TtsAntiAliasing);
- destructor Destroy; override;
- end;
-
-
- TtsFontCreatorGDIFile = class(TtsFontCreatorGDIFontFace)
- protected
- fFilename: pAnsiChar;
- fFontRegistred: Boolean;
-
- function RegisterFont(Filename: pAnsiChar; RegisterPublic: Boolean): boolean;
- function UnRegisterFont(Filename: pAnsiChar; RegisterPublic: Boolean): boolean;
-
- function GetFaceName(Filename: pAnsiChar; var Face: AnsiString): boolean;
- public
- constructor Create(Renderer: TtsRenderer; const Filename: AnsiString; Size: Integer; Style: TtsFontStyles; Format: TtsFormat; AntiAliasing: TtsAntiAliasing);
- destructor Destroy; override;
- end;
-
- TtsFontCreatorGDIStream = class(TtsFontCreatorGDIFontFace)
- protected
- fFontRegistred: Boolean;
- fHandle: THandle;
-
- function RegisterFont(Data: TStream): boolean;
- function UnRegisterFont(): boolean;
-
- function GetFaceName(Stream: TStream; var Face: AnsiString): boolean;
- public
- constructor Create(Renderer: TtsRenderer; const Source: TStream; Size: Integer; Style: TtsFontStyles; Format: TtsFormat; AntiAliasing: TtsAntiAliasing);
- destructor Destroy; override;
- end;
-
- PtsLineItem = ^TtsLineItem;
- TtsLineItem = record
- NextItem: PtsLineItem;
- PrevItem: PtsLineItem;
-
- ItemType: Integer;
- case Integer of
- TS_BLOCK_FONT: (
- Font: TtsFont;
- FontID: tsFontID;
- );
-
- TS_BLOCK_COLOR: (
- Red: Single;
- Green: Single;
- Blue: Single;
- Alpha: Single;
- );
-
- TS_BLOCK_WORD, TS_BLOCK_SPACE: (
- Word: PWideChar;
- WordLength: Integer;
- );
- end;
-
- PtsLinesItem = ^TtsLinesItem;
- TtsLinesItem = record
- NextLine: PtsLinesItem;
-
- LineItemFirst: PtsLineItem;
- LineItemLast: PtsLineItem;
-
- LineLength: Integer;
- LineAutoBreak: Boolean;
- end;
-
- TtsTempLines = record
- Lines: PtsLinesItem;
- Empty: Boolean;
- end;
-
-
- { *** *** }
- TtsRendererImageReference = class
- end;
-
-
- TtsRenderer = class
- private
- fContext: TtsContext;
-
- fSaveImages: Boolean;
-
- fisBlock: Boolean;
- fBlockLeft: Integer;
- fBlockTop: Integer;
- fBlockWidth: Integer;
- fBlockHeight: Integer;
- fFlags: Integer;
-
- fWordWrap: Boolean;
- // fSingleLine: Boolean;
-
- fActiveFont: TtsFont;
- fActiveFontID: Cardinal;
- fLastActiveFont: TtsFont;
- fLastActiveFontID: Cardinal;
-
- fLinesFirst: PtsLinesItem;
- fLinesLast: PtsLinesItem;
- fLinesTemp: TtsTempLines;
-
- // drawings
- fLineTop: Integer;
- fTextOffsetY: Integer;
- fTextOffsetX: Integer;
-
- function GetActiveFont: TtsFont;
- function GetActiveFontID: Cardinal;
-
- function SplitText(pText: PWideChar): PtsLineItem;
- procedure CalculateWordLength(Font: TtsFont; pWord: PtsLineItem);
- procedure SplitIntoLines(pItemList: PtsLineItem);
-
- procedure DrawLine(pLine: PtsLineItem; LineLength: Integer; LineBreak: Boolean);
- procedure DrawLines(pLinesItem: PtsLinesItem);
- function CalculateLinesHeight(pLinesItem: PtsLinesItem): Integer;
-
- procedure GetLineMetric(pLine: PtsLineItem; var Metric: TtsTextMetric);
-
- procedure PushLineItem(pLine: PtsLineItem);
- procedure FreeLineItems(var pLine: PtsLineItem);
-
- procedure PushTempLines;
- procedure FreeLines(var pLinesItem: PtsLinesItem);
- procedure TrimSpaces(pLinesItem: PtsLinesItem);
- protected
- procedure DrawChar(Font: TtsFont; Char: TtsChar); virtual; abstract;
- procedure DrawSetPosition(X, Y: Integer); virtual; abstract;
- procedure DrawSetPositionRelative(X, Y: Integer); virtual; abstract;
- procedure DrawSetColor(Red, Green, Blue, Alpha: Single); virtual; abstract;
-
- function AddImage(Char: TtsChar; CharImage: TtsImage): TtsRendererImageReference; virtual; abstract;
- procedure RemoveImageReference(ImageReference: TtsRendererImageReference); virtual; abstract;
- public
- property ActiveFont: TtsFont read GetActiveFont;
- property ActiveFontID: Cardinal read GetActiveFontID;
-
- property SaveImages: Boolean read fSaveImages write fSaveImages;
-
- property isBlock: Boolean read FisBlock;
-
- constructor Create(Context: TtsContext);
- destructor Destroy; override;
-
- procedure BeginBlock(Left, Top, Width, Height: Integer; Flags: tsBitmask); virtual;
- procedure EndBlock;
-
- procedure FontActivate(FontID: Cardinal);
- procedure Color(Red, Green, Blue, Alpha: Single);
- procedure TextOut(pText: pWideChar);
-
- function TextGetWidth(pText: pWideChar): Integer;
- function TextGetDrawWidth: Integer;
- function TextGetDrawHeight: Integer;
-
- procedure CharOut(CharCode: WideChar);
- end;
-
-
- TtsRendererNULLImageReference = class(TtsRendererImageReference)
- Image: TtsImage;
- end;
-
-
- TtsRendererNULL = class(TtsRenderer)
- protected
- procedure DrawChar(Font: TtsFont; Char: TtsChar); override;
- procedure DrawSetPosition(X, Y: Integer); override;
- procedure DrawSetPositionRelative(X, Y: Integer); override;
- procedure DrawSetColor(Red, Green, Blue, Alpha: Single); override;
-
- function AddImage(Char: TtsChar; CharImage: TtsImage): TtsRendererImageReference; override;
- procedure RemoveImageReference(ImageReference: TtsRendererImageReference); override;
- end;
-
-
-
- TtsRendererOpenGLImageReference = class(TtsRendererImageReference)
- TexID: Integer;
- Coordinates: tsRect;
-
- TexCoords: tsQuadFloat;
- Vertex: tsQuadFloat;
- end;
-
-
- PtsRendererOpenGLTexture = ^TtsRendererOpenGLTexture;
- TtsRendererOpenGLTexture = record
- glTextureID: Cardinal;
-
- Width: Integer;
- Height: Integer;
- end;
-
-
- PtsRendererOpenGLManagedEntry = ^TtsRendererOpenGLManagedEntry;
- TtsRendererOpenGLManagedEntry = record
- Start: Word;
- Count: Word;
-
- NextEntry: PtsRendererOpenGLManagedEntry;
- end;
-
-
- PtsRendererOpenGLTextureEntry = ^TtsRendererOpenGLTextureEntry;
- TtsRendererOpenGLTextureEntry = record
- ID: Integer;
- Texture: PtsRendererOpenGLTexture;
-
- Lines: array of PtsRendererOpenGLManagedEntry;
- Usage: Integer;
- end;
-
-
- TtsRendererOpenGL = class(TtsRenderer)
- private
- fPos: tsPoint;
-
- fTextureSize: Integer;
-
- // Texture
- fTextures: TList;
-
- procedure AllocSpace(var FirstManaged: PtsRendererOpenGLManagedEntry; Start, Count: Word);
- procedure FreeSpace(var FirstManaged: PtsRendererOpenGLManagedEntry; Start, Count: Word);
-
- function GetTextureByID(ID: Integer): PtsRendererOpenGLTexture;
-
- function AddImageToTexture(Texture: PtsRendererOpenGLTextureEntry; Image: TtsImage; var TextureID: Integer; var Coordinates: tsRect): boolean;
- function CreateNewTexture: PtsRendererOpenGLTextureEntry;
-
- procedure DeleteTexture(Idx: Integer);
- procedure ClearTextures;
- protected
- procedure DrawChar(Font: TtsFont; Char: TtsChar); override;
- procedure DrawSetPosition(X, Y: Integer); override;
- procedure DrawSetPositionRelative(X, Y: Integer); override;
- procedure DrawSetColor(Red, Green, Blue, Alpha: Single); override;
-
- function AddImage(Char: TtsChar; CharImage: TtsImage): TtsRendererImageReference; override;
- procedure RemoveImageReference(ImageReference: TtsRendererImageReference); override;
- public
- property TextureSize: Integer read fTextureSize write fTextureSize;
-
- procedure BeginBlock(Left, Top, Width, Height: Integer; Flags: tsBitmask); override;
-
- procedure AfterConstruction; override;
- procedure BeforeDestruction; override;
- end;
-
-
- // context structures/types for use in unit TextSuite
- TtsContext = class
- private
- fContextID: Cardinal;
-
- // Fonts
- fFonts: TtsHash;
- fLastFontID: Cardinal;
-
- // Images
- fImages: TtsHash;
- fLastImageID: Cardinal;
-
- function GetIsLocked: boolean;
-
- procedure ClearFonts;
- procedure ClearImages;
- function GetActiveFont: TtsFont;
- public
- // ThreadID
- gBoundThreadID: Cardinal;
-
- // error
- Error: Cardinal;
-
- // globals settings
- Renderer: TtsRenderer;
- gCreator: tsEnum;
- gGlobalFormat: tsEnum;
- gGlobalAntiAliasing: tsEnum;
-
- gDebugDrawCharRects: Boolean;
-
- gEmptyCodePageEntry: tsEnum;
- gCodePage: tsEnum;
- gCodePagePtr: Pointer;
- gCodePageFunc: TtsAnsiToWideCharFunc;
-
- gSingleLine: tsEnum;
- gAlign: tsEnum;
- gVAlign: tsEnum;
- gClip: tsEnum;
- gBlockOffsetX: tsInt;
- gBlockOffsetY: tsInt;
-
- gImageMode: TtsImageModes;
- gImageLibrary: tsEnum;
-
- { Tab: tsEnum;
- TabWidth: tsInt; }
-
- // context specific / helper
- property ContextID: Cardinal read fContextID;
-
- property IsLocked: boolean read GetIsLocked;
-
- property ActiveFont: TtsFont read GetActiveFont;
-
- // helper functions
- function ImageAdd(Image: TtsImage): Cardinal;
- function ImageGet(Image: Cardinal): TtsImage;
- procedure ImageDelete(Image: Cardinal);
- function ImageCount: Cardinal;
-
- function FontAdd(Font: TtsFont): Cardinal;
- function FontGet(Font: Cardinal): TtsFont;
- procedure FontDelete(Font: Cardinal);
- function FontCount: Cardinal;
-
- function AnsiToWide(pText: pAnsiChar): pWideChar;
-
- constructor Create;
- destructor Destroy; override;
- end;
-
-
- PtsContextFontEntry = ^TtsContextFontEntry;
- TtsContextFontEntry = record
- FontID: tsFontID;
- Font: TtsFont;
- end;
-
-
- PtsContextImageEntry = ^TtsContextImageEntry;
- TtsContextImageEntry = record
- ImageID: tsImageID;
- Image: TtsImage;
- end;
-
-
- // Helper
- function MakeColor(Red: Byte = 0; Green: Byte = 0; Blue: Byte = 0; Alpha: Byte = 0): tsColor;
-
-
- implementation
-
-
- uses
- Math,
- SysUtils,
- SyncObjs,
- TextSuitePostProcess,
- TextSuiteTTFUtils;
-
-
- var
- gLastContextID: Cardinal;
-
-
- // Helper
- function MakeColor(Red, Green, Blue, Alpha: Byte): tsColor;
- begin
- Result.Red := Red;
- Result.Green := Green;
- Result.Blue := Blue;
- Result.Alpha := Alpha;
- end;
-
-
- procedure TranslateQuad(var Dest: tsQuadFloat; const Source: tsQuadFloat; const Translate: tsPoint);
- begin
- Dest[0].X := Source[0].X + Translate.X;
- Dest[0].Y := Source[0].Y + Translate.Y;
-
- Dest[1].X := Source[1].X + Translate.X;
- Dest[1].Y := Source[1].Y + Translate.Y;
-
- Dest[2].X := Source[2].X + Translate.X;
- Dest[2].Y := Source[2].Y + Translate.Y;
-
- Dest[3].X := Source[3].X + Translate.X;
- Dest[3].Y := Source[3].Y + Translate.Y;
- end;
-
-
- { TtsHash }
-
- procedure TtsHash.Add(Name: Integer; Value: Pointer);
- var
- Pos: Integer;
- Entry, HashEntry: PtsHashEntry;
- begin
- if Name <> 0 then begin
- Pos := IntToPos(Name);
- HashEntry := fHashArray[Pos];
- Entry := fHashArray[Pos];
-
- if (HashEntry = nil) then begin
- if (Value = nil) then
- Exit;
-
- New(HashEntry);
- HashEntry^.Name := Name;
- HashEntry^.Value := Value;
- HashEntry^.Next := nil;
- fHashArray[Pos] := HashEntry;
- Inc(fCount);
-
- Exit;
- end;
-
- while HashEntry <> nil do begin
- if Name = HashEntry^.Name then begin
- if Value = nil then begin
- if (HashEntry = fHashArray[Pos]) then
- fHashArray[Pos] := fHashArray[Pos]^.Next
- else
- Entry^.Next := HashEntry^.Next;
-
- Dispose(HashEntry);
- Dec(fCount);
- Exit;
- end;
-
- HashEntry^.Value := Value;
- Exit;
- end;
-
- if HashEntry^.Next = nil
- then break;
-
- Entry := HashEntry;
- HashEntry := HashEntry^.Next;
- end;
-
- if (Value = nil)
- then Exit;
-
- New(Entry);
- Entry^.Name := Name;
- Entry^.Value := Value;
- Entry^.Next := nil;
- Inc(fCount);
-
- HashEntry^.Next := Entry;
- end;
- end;
-
-
- procedure TtsHash.Clear;
- var
- Idx: Integer;
- TempEntry, Entry: PtsHashEntry;
- begin
- for Idx := Low(fHashArray) to High(fHashArray) do begin
- Entry := fHashArray[Idx];
-
- while Entry <> nil do begin
- TempEntry := Entry;
- Entry := Entry^.Next;
-
- Dispose(TempEntry);
- end;
-
- fHashArray[Idx] := nil;
- end;
-
- fCount := 0;
- end;
-
-
- constructor TtsHash.Create(HashEntrys: Integer);
- begin
- inherited Create;
-
- fHashEntrys := Max(1, HashEntrys);
- SetLength(fHashArray, fHashEntrys);
- end;
-
-
- procedure TtsHash.Delete(Name: Integer);
- begin
- // Add with an empty value is enough
- Add(Name, nil);
- end;
-
-
- destructor TtsHash.Destroy;
- begin
- Clear;
-
- inherited;
- end;
-
-
- function TtsHash.Get(Name: Integer): Pointer;
- var
- Pos: Integer;
- Entry: PtsHashEntry;
- begin
- Result := nil;
-
- if Name <> 0 then begin
- Pos := IntToPos(Name);
- Entry := fHashArray[Pos];
-
- if Entry <> nil then begin
- while Entry <> nil do begin
- if Name = Entry^.Name then begin
- Result := Entry^.Value;
-
- Break;
- end;
-
- Entry := Entry^.Next;
- end;
- end;
- end;
- end;
-
-
- procedure TtsHash.GetNames(const NameList: TList);
- var
- Idx: Integer;
- Entry: PtsHashEntry;
- begin
- Assert(NameList <> nil, 'TtsHash.GetNames - NameList is undefined');
-
- NameList.Clear;
-
- for Idx := Low(fHashArray) to High(fHashArray) do begin
- Entry := fHashArray[Idx];
-
- while Entry <> nil do begin
- NameList.Add({%H-}Pointer(Entry^.Name));
-
- Entry := Entry^.Next;
- end;
- end;
- end;
-
-
- procedure TtsHash.GetValues(const ValueList: TList);
- var
- Idx: Integer;
- Entry: PtsHashEntry;
- begin
- Assert(ValueList <> nil, 'TtsHash.GetValues - ValuesList is undefined');
-
- ValueList.Clear;
-
- for Idx := Low(fHashArray) to High(fHashArray) do begin
- Entry := fHashArray[Idx];
-
- while Entry <> nil do begin
- ValueList.Add(Entry^.Value);
-
- Entry := Entry^.Next;
- end;
- end;
- end;
-
-
- function TtsHash.IntToPos(Name: Integer): Integer;
- begin
- if Name < 0 then
- Result := -Name
- else
- Result := Name;
-
- Result := Result mod fHashEntrys;
- end;
-
-
- { TtsStringHash }
-
- procedure TtsStringHash.Add(pString: pWideChar);
- var
- Pos: Integer;
- Entry, HashEntry: PtsStringHashEntry;
- begin
- if pString <> nil then begin
- Pos := {%H-}Cardinal(pString) mod fHashEntrys;
- Entry := fHashArray[Pos];
- HashEntry := Entry;
-
- // is empty field
- if (Entry = nil) then begin
- New(Entry);
- Entry^.pString := pString;
- Entry^.Next := nil;
- fHashArray[Pos] := Entry;
-
- Exit;
- end;
-
- // search last
- while HashEntry <> nil do begin
- if HashEntry^.Next = nil
- then break;
-
- HashEntry := HashEntry^.Next;
- end;
-
- New(Entry);
- Entry^.pString := pString;
- Entry^.Next := nil;
-
- HashEntry^.Next := Entry;
- end;
- end;
-
-
- constructor TtsStringHash.Create(HashEntrys: Integer);
- begin
- inherited Create;
-
- fHashEntrys := Max(1, HashEntrys);
- SetLength(fHashArray, fHashEntrys);
- end;
-
-
- function TtsStringHash.Delete(pString: pWideChar) : Boolean;
- var
- Pos: Integer;
- Entry, HashEntry: PtsStringHashEntry;
- begin
- Result := False;
-
- if pString <> nil then begin
- Pos := {%H-}Cardinal(pString) mod fHashEntrys;
- HashEntry := fHashArray[Pos];
- Entry := nil;
-
- while HashEntry <> nil do begin
- if pString = HashEntry^.pString then begin
- if (HashEntry = fHashArray[Pos]) then
- fHashArray[Pos] := fHashArray[Pos]^.Next
- else
- Entry^.Next := HashEntry^.Next;
-
- Dispose(HashEntry);
-
- Result := True;
-
- Exit;
- end;
-
- Entry := HashEntry;
- HashEntry := HashEntry^.Next;
- end;
- end;
- end;
-
-
- destructor TtsStringHash.Destroy;
- var
- Idx: Integer;
- Temp: PtsStringHashEntry;
- begin
- for Idx := Low(fHashArray) to High(fHashArray) do begin
- while fHashArray[Idx] <> nil do begin
- Temp := fHashArray[Idx];
-
- fHashArray[Idx] := fHashArray[Idx]^.Next;
-
- tsStrDispose(Temp^.pString);
- Dispose(Temp);
- end;
- end;
-
- SetLength(fHashArray, 0);
-
- inherited;
- end;
-
-
- { TtsKernel1D }
-
- constructor TtsKernel1D.Create(Radius, Strength: Single);
- var
- TempRadius, SQRRadius, TempStrength, TempValue: Double;
- Idx: Integer;
-
-
- function CalcValue(Index: Integer): Single;
- var
- Temp: Double;
- begin
- Temp := Max(0, Abs(Index) - TempStrength);
- Temp := Sqr(Temp * TempRadius) / SQRRadius;
-
- Result := Exp(-Temp);
- end;
-
- begin
- inherited Create;
-
- // calculate new radius and strength
- TempStrength := Min(Radius - 1, Radius * Strength);
- TempRadius := Radius - TempStrength;
-
- SQRRadius := sqr(TempRadius) * sqr(TempRadius);
-
- // caluculating size of the kernel
- Size := Round(TempRadius);
- while CalcValue(Size) > 0.001 do
- Inc(Size);
- Size := Size -1;
-
- ValueSum := 0;
- ItemCount := Size * 2 +1;
- SetLength(Items, ItemCount);
-
- // calculate Value (yes thats right. there is no -1)
- for Idx := 0 to Size do begin
- TempValue := CalcValue(Idx);
-
- with Items[Size + Idx] do begin
- Offset := Idx;
- Value := TempValue;
- end;
-
- with Items[Size - Idx] do begin
- Offset := -Idx;
- Value := TempValue;
- end;
-
- // sum
- ValueSum := ValueSum + TempValue;
- if Idx > 0 then
- ValueSum := ValueSum + TempValue;
- end;
- end;
-
-
- procedure TtsKernel1D.UpdateDataOffset(DataSize: Integer);
- var
- Idx: Integer;
- begin
- for Idx := 0 to ItemCount -1 do
- with Items[Idx] do
- DataOffset := Offset * DataSize;
- end;
-
-
-
- { TtsKernel2D }
-
- constructor TtsKernel2D.Create(Radius, Strength: Single);
- var
- TempRadius, SQRRadius, TempStrength, TempValue: Double;
- X, Y, Height, Width: Integer;
-
-
- function CalcValue(Index: Single): Single;
- var
- Temp: Double;
- begin
- Temp := Max(0, Abs(Index) - TempStrength);
- Temp := Sqr(Temp * TempRadius) / SQRRadius;
-
- Result := Exp(-Temp);
- end;
-
-
- procedure QuickSort(L, R: Integer);
- var
- I, J: Integer;
- P, T: TtsKernel2DItem;
-
- function Compare(const Item1, Item2: TtsKernel2DItem): Integer;
- begin
- if Item1.Value = Item2.Value then
- Result := 0
- else
- if Item1.Value > Item2.Value then
- Result := -1
- else
- Result := 1;
- end;
-
- begin
- repeat
- I := L;
- J := R;
- P := Items[(L + R) shr 1];
-
- repeat
- while Compare(Items[I], P) < 0 do
- Inc(I);
-
- while Compare(Items[J], P) > 0 do
- Dec(J);
-
- if I <= J then begin
- T := Items[I];
- Items[I] := Items[J];
- Items[J] := T;
- Inc(I);
- Dec(J);
- end;
- until I > J;
-
- if L < J then
- QuickSort(L, J);
-
- L := I;
- until I >= R;
- end;
-
-
- begin
- inherited Create;
-
- // calculate new radius and strength
- TempStrength := Min(Radius - 1, Radius * Strength);
- TempRadius := Radius - TempStrength;
-
- SQRRadius := sqr(TempRadius) * sqr(TempRadius);
-
- // caluculating X size of the kernel
- SizeX := 0;
- MidSizeX := SizeX;
-
- while CalcValue(SizeX) > 0.5 do begin
- Inc(SizeX);
- Inc(MidSizeX);
- end;
-
- while CalcValue(SizeX) > 0.001 do
- Inc(SizeX);
-
- // caluculating Y size of the kernel
- SizeY := 0;
- MidSizeY := SizeY;
-
- while CalcValue(SizeY) > 0.5 do begin
- Inc(SizeY);
- Inc(MidSizeY);
- end;
-
- while CalcValue(SizeY) > 0.001 do
- Inc(SizeY);
-
- ValueSum := 0;
-
- Width := SizeX * 2 + 1;
- Height := SizeY * 2 + 1;
- ItemCount := Height * Width;
- SetLength(Items, ItemCount);
-
- Width := SizeX * 2 + 1;
- Height := SizeY * 2 + 1;
- ItemCount := Height * Width;
- SetLength(Items, ItemCount);
-
- // calculate Value (yes thats right. there is no -1)
- for Y := 0 to SizeY do begin
- for X := 0 to SizeX do begin
- TempValue := CalcValue(Sqrt(Sqr(X) + Sqr(Y)));
-
- with Items[(SizeY + Y) * Width + (SizeX + X)] do begin
- OffsetX := X;
- OffsetY := Y;
- Value := TempValue;
- end;
-
- with Items[(SizeY + Y) * Width + (SizeX - X)] do begin
- OffsetX := -X;
- OffsetY := Y;
- Value := TempValue;
- end;
-
- with Items[(SizeY - Y) * Width + (SizeX + X)] do begin
- OffsetX := X;
- OffsetY := -Y;
- Value := TempValue;
- end;
-
- with Items[(SizeY - Y) * Width + (SizeX - X)] do begin
- OffsetX := -X;
- OffsetY := -Y;
- Value := TempValue;
- end;
-
- // sum
- ValueSum := ValueSum + TempValue;
- if (X > 0) and (Y > 0) then
- ValueSum := ValueSum + TempValue;
- end;
- end;
-
- // sort
- QuickSort(0, ItemCount -1);
-
- // cut small items
- while Items[ItemCount -1].Value < 0.001 do
- Dec(ItemCount);
-
- SetLength(Items, ItemCount);
- end;
-
-
- procedure TtsKernel2D.UpdateDataOffset(DataSizeX, DataSizeY: Integer);
- var
- Idx: Integer;
- begin
- for Idx := 0 to ItemCount -1 do
- with Items[Idx] do
- DataOffset := OffsetX * DataSizeX + OffsetY * DataSizeY;
- end;
-
-
- { TtsChar }
-
- (*
- procedure TtsChar.CalculateKerningData(CharImage: TtsImage);
- var
- Y: Integer;
- pLeft, pRight: PtsColor;
-
-
- function GetFirstPixel(pData: PtsColor; MinOpaque: Byte; IncValue, MaxSteps: Integer) : Integer;
- var
- CurStep: Integer;
- begin
- Result := MaxSteps;
- CurStep := 0;
-
- while CurStep < MaxSteps do begin
- if pData^.Alpha >= MinOpaque then begin
- Result := CurStep;
- Break;
- end;
-
- Inc(CurStep);
- Inc(pData, IncValue);
- end;
- end;
-
- begin
- SetLength(KerningValuesLeft, CharImage.Height);
- SetLength(KerningValuesRight, CharImage.Height);
-
- for Y := 0 to CharImage.Height - 1 do begin
- pRight := CharImage.ScanLine[Y];
- Inc(pRight, CharImage.Width -1);
- KerningValuesRight[Y] := GetFirstPixel(pRight, $40, -1, CharImage.Width);
-
- pLeft:= CharImage.ScanLine[Y];
- KerningValuesLeft[Y] := GetFirstPixel(pLeft, $40, 1, CharImage.Width);
- end;
- end;
- *)
-
-
- //function TtsChar.CalculateKerningValue(LastChar: TtsChar): Smallint;
- //begin
- // Result := 0;
- //var
- // TempHeight, TempLastHeight: Integer;
- // Y, YMin, YMax: Integer;
- // LeftYMin, LeftYMax, RightYMin, RightYMax: Integer;
- //
- // Dist, TempDist: Integer;
- //
- // function GetMinDistance(Row: Integer): Integer;
- // begin
- //// Result :=
- //// Self.KerningValuesLeft[Self.BaseLine - Self.GlyphRect.Top + Row] +
- //// LastChar.KerningValuesRight[LastChar.BaseLine - LastChar.GlyphRect.Top + Row];
- // end;
- //
- //begin
- // Result := 0;
- //
- // if Assigned(LastChar) then begin
- // TempLastHeight := Length(LastChar.KerningValuesRight);
- // TempHeight := Length(Self.KerningValuesLeft);
- //
- // if (TempLastHeight > 0) and (TempHeight > 0) then begin
- // LeftYMin := Self.GlyphRect.Bottom - Self.BaseLine;
- // LeftYMax := Self.GlyphRect.Top - Self.BaseLine;
- //
- // RightYMin := LastChar.GlyphRect.Bottom - LastChar.BaseLine;
- // RightYMax := LastChar.GlyphRect.Top - LastChar.BaseLine;
- //
- // YMin := Min(LeftYMin, RightYMin);
- // YMax := Max(LeftYMax, RightYMax);
- //
- // Dist := -1;
- //
- // for Y := YMax to YMin -1 do begin
- // TempDist := GetMinDistance(Y);
- //
- // if (Dist = -1) then
- // Dist := TempDist
- // else
- //
- // if TempDist < Dist then
- // Dist := TempDist;
- // end;
- //
- // // calculate advance of last char to diff
- // Dist := Dist + LastChar.Advance - (LastChar.GlyphRect.Right - LastChar.GlyphRect.Left);
- //
- // Result := -Dist +3;
- // end;
- // end;
- //end;
-
-
- constructor TtsChar.Create(CharCode: WideChar);
- begin
- inherited Create;
-
- fCharCode := CharCode;
- end;
-
-
- destructor TtsChar.Destroy;
- begin
- // SetLength(KerningValuesLeft, 0);
- // SetLength(KerningValuesRight, 0);
-
- inherited;
- end;
-
-
- procedure TtsChar.ExpandRect(Left, Top, Right, Bottom: Integer);
- begin
- Advance := Advance + Left + Right;
- GlyphOriginY := GlyphOriginY + Top + Bottom;
-
- GlyphRect.Right := GlyphRect.Right + Left + Right;
- GlyphRect.Bottom := GlyphRect.Bottom + Top + Bottom;
- end;
-
-
- { TtsImage }
- type
- TtsModeFunc = function(Source, Dest: Byte): Byte; register;
-
-
- function ModeFuncIgnore(Source, Dest: Byte): Byte; register;
- {$ifdef TS_PURE_PASCAL}
- begin
- Result := Dest;
- {$else}
- asm
- mov al, dl
- {$endif}
- end;
-
-
- function ModeFuncReplace(Source, Dest: Byte): Byte; register;
- {$ifdef TS_PURE_PASCAL}
- begin
- Result := Source;
- {$else}
- asm
- {$endif}
- end;
-
-
- function ModeFuncModulate(Source, Dest: Byte): Byte; register;
- {$ifdef TS_PURE_PASCAL}
- begin
- Result := (Source * Dest) div $FF
- {$else}
- asm
- // inc ax
- // inc dx
- mul dl
- shr eax, 8
- {$endif}
- end;
-
-
- procedure TtsImage.AddFunc(Func: TtsImageFunc; Data: Pointer);
- var
- X, Y: Integer;
- pPix: PtsColor;
- begin
- for Y := 0 to Height - 1 do begin
- pPix := ScanLine[Y];
-
- for X := 0 to Width - 1 do begin
- Func(Self, X, Y, pPix^, Data);
-
- Inc(pPix);
- end;
- end;
- end;
-
-
- procedure TtsImage.AddResizingBorder(tsChar: TtsChar);
- var
- X, Y: Integer;
- pPix: PtsColor;
-
- pTemp: PtsColor;
- SumCount: Integer;
- SumColor: array [0..2] of integer;
- begin
- SumColor[0] := 0;
- SumColor[1] := 0;
- SumColor[2] := 0;
- SumCount := 0;
-
- // settings of char
- tsChar.GlyphRect.Top := tsChar.GlyphRect.Top + 1;
- tsChar.GlyphRect.Left := tsChar.GlyphRect.Left + 1;
- tsChar.GlyphRect.Right := tsChar.GlyphRect.Right + 1;
- tsChar.GlyphRect.Bottom := tsChar.GlyphRect.Bottom + 1;
-
- // resize image
- Resize(Width + 4, Height + 4, 2, 2);
-
- // calculate color of invisible pixels
- for Y := 0 to Height -1 do begin
- pPix := ScanLine[Y];
-
- for X := 0 to Width -1 do begin
- if pPix^.Alpha = 0 then begin
- // row -1
- if Y > 0 then begin
- pTemp := pPix;
- Dec(pTemp, fWidth);
-
- // row -1 / col
- if pTemp^.Alpha > 0 then begin
- Inc(SumCount);
- Inc(SumColor[0], pTemp^.Red);
- Inc(SumColor[1], pTemp^.Green);
- Inc(SumColor[2], pTemp^.Blue);
- end;
-
- // row -1 / col -1
- if X > 0 then begin
- Dec(pTemp);
-
- if pTemp^.Alpha > 0 then begin
- Inc(SumCount);
- Inc(SumColor[0], pTemp^.Red);
- Inc(SumColor[1], pTemp^.Green);
- Inc(SumColor[2], pTemp^.Blue);
- end;
-
- Inc(pTemp);
- end;
-
- // row -1 / col +1
- if X < fWidth -1 then begin
- Inc(pTemp);
-
- if pTemp^.Alpha > 0 then begin
- Inc(SumCount);
- Inc(SumColor[0], pTemp^.Red);
- Inc(SumColor[1], pTemp^.Green);
- Inc(SumColor[2], pTemp^.Blue);
- end;
- end;
- end;
-
- // row +1
- if Y < fHeight -1 then begin
- pTemp := pPix;
- Inc(pTemp, fWidth);
-
- // row +1 / col
- if pTemp^.Alpha > 0 then begin
- Inc(SumCount);
- Inc(SumColor[0], pTemp^.Red);
- Inc(SumColor[1], pTemp^.Green);
- Inc(SumColor[2], pTemp^.Blue);
- end;
-
- // row +1 / col -1
- if X > 0 then begin
- Dec(pTemp);
-
- if pTemp^.Alpha > 0 then begin
- Inc(SumCount);
- Inc(SumColor[0], pTemp^.Red);
- Inc(SumColor[1], pTemp^.Green);
- Inc(SumColor[2], pTemp^.Blue);
- end;
-
- Inc(pTemp);
- end;
-
- // row +1 / col +1
- if X < fWidth -1 then begin
- Inc(pTemp);
-
- if pTemp^.Alpha > 0 then begin
- Inc(SumCount);
- Inc(SumColor[0], pTemp^.Red);
- Inc(SumColor[1], pTemp^.Green);
- Inc(SumColor[2], pTemp^.Blue);
- end;
- end;
- end;
-
- // row / col -1
- if X > 0 then begin
- pTemp := pPix;
- Dec(pTemp);
-
- if pTemp^.Alpha > 0 then begin
- Inc(SumCount);
- Inc(SumColor[0], pTemp^.Red);
- Inc(SumColor[1], pTemp^.Green);
- Inc(SumColor[2], pTemp^.Blue);
- end;
- end;
-
- // row / col +1
- if X < fWidth -1 then begin
- pTemp := pPix;
- Inc(pTemp);
-
- if pTemp^.Alpha > 0 then begin
- Inc(SumCount);
- Inc(SumColor[0], pTemp^.Red);
- Inc(SumColor[1], pTemp^.Green);
- Inc(SumColor[2], pTemp^.Blue);
- end;
- end;
-
- // any pixel next to the transparent pixel they are opaque?
- if SumCount > 0 then begin
- // calculate resulting pixel color
- pPix^.Red := SumColor[0] div SumCount;
- pPix^.Green := SumColor[1] div SumCount;
- pPix^.Blue := SumColor[2] div SumCount;
-
- // clearing values
- SumColor[0] := 0;
- SumColor[1] := 0;
- SumColor[2] := 0;
- SumCount := 0;
- end;
- end;
-
- Inc(pPix);
- end;
- end;
- end;
-
-
- procedure TtsImage.AssignFrom(Image: TtsImage);
- var
- pImage: Pointer;
- ImageSize: Integer;
- begin
- ImageSize := Image.Width * Image.Height * GetFormatSize(Image.Format);
-
- GetMem(pImage, ImageSize);
-
- if pImage <> nil then
- Move(Image.Data^, pImage^, ImageSize);
-
- SetDataPtr(pImage, Image.Format, Image.Width, Image.Height);
- end;
-
-
- procedure TtsImage.BeforeDestruction;
- begin
- SetDataPtr(nil);
-
- inherited;
- end;
-
-
- procedure TtsImage.BlendImage(Image: TtsImage; X, Y: Integer; AutoExpand: Boolean);
- var
- pImage, pDest: PtsColor;
- X1, X2, Y1, Y2, BX1, BX2, BY1, BY2, NewWidth, NewHeight: Integer;
- TempX, TempY: Integer;
-
- TempLines: array of PtsColor;
- pSource: PtsColor;
-
- // Blending
- pUnder, pOver: PtsColor;
- ResultAlpha, FaqUnder, FaqOver: Byte;
- begin
- // Calculate new size
- X1 := Min(X, 0);
- X2 := Max(X + Image.Width, Width);
-
- Y1 := Min(Y, 0);
- Y2 := Max(Y + Image.Height, Height);
-
- BX1 := Max(X, 0);
- BX2 := Min(X + Image.Width, Width);
-
- BY1 := Max(Y, 0);
- BY2 := Min(Y + Image.Height, Height);
-
- NewWidth := X2 - X1;
- NewHeight := Y2 - Y1;
-
- // Allocate new image
- GetMem(pImage, NewWidth * NewHeight * GetFormatSize(Format));
- try
- FillChar(pImage^, NewWidth * NewHeight * GetFormatSize(Format), #$00);
-
- // ScanLines
- SetLength(TempLines, NewHeight);
-
- for TempY := 0 to NewHeight - 1 do begin
- TempLines[TempY] := pImage;
- Inc(TempLines[TempY], NewWidth * TempY);
- end;
-
- // copy non overlapping data from underlaying Image
- for TempY := 0 to Height -1 do begin
- pDest := TempLines[TempY - Y1];
- Inc(pDest, - X1);
-
- pSource := ScanLine[TempY];
-
- for TempX := 0 to Width -1 do begin
- pDest^ := pSource^;
-
- Inc(pDest);
- Inc(pSource);
- end;
- end;
-
- // copy non overlapping data from overlaying Image
- for TempY := 0 to Image.Height -1 do begin
- pDest := TempLines[TempY + Y - Y1];
- Inc(pDest, X - X1);
-
- pSource := Image.ScanLine[TempY];
-
- for TempX := 0 to Image.Width -1 do begin
- pDest^ := pSource^;
-
- Inc(pDest);
- Inc(pSource);
- end;
- end;
-
- // Blend overlapped
- for TempY := BY1 to BY2 - 1 do begin
- pOver := Image.ScanLine[TempY - Min(BY1, Y)];
- Inc(pOver, BX1 - X);
-
- pUnder := ScanLine[TempY - Min(BY1, 0)];
- Inc(pUnder, BX1);
-
- pDest := TempLines[TempY - Min(Y, 0)];
- Inc(pDest, BX1 - Min(X, 0));
-
- for TempX := BX1 to BX2 - 1 do begin
- ResultAlpha := pOver^.Alpha + pUnder^.Alpha * ($FF - pOver^.Alpha) div $FF;
-
- if ResultAlpha > 0 then begin
- FaqUnder := (pUnder^.Alpha * ($FF - pOver^.Alpha) div $FF) * $FF div ResultAlpha;
- FaqOver := pOver^.Alpha * $FF div ResultAlpha;
-
- pDest^.Red := (pOver^.Red * FaqOver + pUnder^.Red * FaqUnder) div $FF;
- pDest^.Green := (pOver^.Green * FaqOver + pUnder^.Green * FaqUnder) div $FF;
- pDest^.Blue := (pOver^.Blue * FaqOver + pUnder^.Blue * FaqUnder) div $FF;
- end else begin
- pDest^.Red := 0;
- pDest^.Green := 0;
- pDest^.Blue := 0;
- end;
-
- pDest^.Alpha := ResultAlpha;
-
- Inc(pOver);
- Inc(pUnder);
- Inc(pDest);
- end;
- end;
-
- // Set new image
- SetDataPtr(pImage, Format, NewWidth, NewHeight);
- except
- FreeMem(pImage);
- end;
- end;
-
-
-
- type
- TtsImageBlurFuncData = packed record
- Kernel: TtsKernel1D;
- Pos, MaxPos: Integer;
- end;
-
- TBlurFunc = function(pSource: pByte; var Data: TtsImageBlurFuncData): Byte; register;
-
-
- function BlurFuncKernel(pSource: pByte; var Data: TtsImageBlurFuncData): Byte; register;
- var
- Idx: Integer;
- pTemp: pByte;
- TempSum, TempMax: Double;
- begin
- TempSum := 0;
- TempMax := 0;
-
- with Data do begin
- for Idx := 0 to Kernel.ItemCount -1 do begin
- with Kernel.Items[Idx] do begin
- if (Pos + Offset >= 0) and (Pos + Offset < MaxPos) then begin
- pTemp := pSource;
- Inc(pTemp, DataOffset);
-
- TempSum := TempSum + pTemp^ * Value;
- TempMax := TempMax + Value;
- end;
- end;
- end;
- end;
-
- Result := Round(TempSum / TempMax);
- end;
-
-
- function BlurFuncIgnore(pSource: pByte; var Data: TtsImageBlurFuncData): Byte; register;
- {$ifdef TS_PURE_PASCAL}
- begin
- Result := pSource^;
- {$else}
- asm
- mov al, byte ptr [eax]
- {$endif}
- end;
-
-
- procedure TtsImage.Blur(HorzKernel, VertKernel: TtsKernel1D; ChannelMask: tsBitmask);
- var
- X, Y: Integer;
- Temp: TtsImage;
-
- pSource, pDest: ptsColor;
-
- FuncData: TtsImageBlurFuncData;
- RedFunc, GreenFunc, BlueFunc, AlphaFunc: TBlurFunc;
-
-
- procedure AssignFunc(var Func: TBlurFunc; MaskBit: Cardinal);
- begin
- if MaskBit and ChannelMask > 0 then
- Func := BlurFuncKernel
- else
- Func := BlurFuncIgnore;
- end;
-
-
- begin
- // casing functions
- AssignFunc(RedFunc, TS_CHANNEL_RED);
- AssignFunc(GreenFunc, TS_CHANNEL_GREEN);
- AssignFunc(BlueFunc, TS_CHANNEL_BLUE);
- AssignFunc(AlphaFunc, TS_CHANNEL_ALPHA);
-
-
- Temp := TtsImage.Create;
- try
- Temp.CreateEmpty(Format, Width, Height);
- Temp.FillColor(1, 1, 1, 0, TS_CHANNELS_RGBA, cModesReplace);
-
- // blur horz from original to temp image
- HorzKernel.UpdateDataOffset(4);
-
- FuncData.Kernel := HorzKernel;
- FuncData.MaxPos := Temp.Width;
-
- for Y := 0 to Temp.Height - 1 do begin
- pSource := Self.ScanLine[Y];
- pDest := Temp.ScanLine[Y];
-
- for X := 0 to FuncData.MaxPos - 1 do begin
- FuncData.Pos := X;
- pDest^.Red := RedFunc(@(pSource^.Red), FuncData);
- pDest^.Green := GreenFunc(@(pSource^.Green), FuncData);
- pDest^.Blue := BlueFunc(@(pSource^.Blue), FuncData);
- pDest^.Alpha := AlphaFunc(@(pSource^.Alpha), FuncData);
-
- Inc(pDest);
- Inc(pSource);
- end;
- end;
-
- // blur vert from temp to original image
- VertKernel.UpdateDataOffset(Width * 4);
-
- FuncData.Kernel := VertKernel;
- FuncData.MaxPos := Temp.Height;
-
- for Y := 0 to Temp.Height - 1 do begin
- pSource := Temp.ScanLine[Y];
- pDest := Self.ScanLine[Y];
-
- FuncData.Pos := Y;
-
- for X := 0 to Temp.Width - 1 do begin
- pDest^.Red := RedFunc(@(pSource^.Red), FuncData);
- pDest^.Green := GreenFunc(@(pSource^.Green), FuncData);
- pDest^.Blue := BlueFunc(@(pSource^.Blue), FuncData);
- pDest^.Alpha := AlphaFunc(@(pSource^.Alpha), FuncData);
-
- Inc(pDest);
- Inc(pSource);
- end;
- end;
-
- finally
- Temp.Free;
- end;
- end;
-
-
- procedure TtsImage.CreateEmpty(Format: TtsFormat; aWidth, aHeight: Integer);
- var
- pImage: pByte;
- begin
- pImage := AllocMem(aWidth * aHeight * GetFormatSize(Format));
-
- SetDataPtr(pImage, Format, aWidth, aHeight);
- end;
-
-
- procedure TtsImage.FillColor(Red, Green, Blue, Alpha: Single; ChannelMask: tsBitmask; Modes: TtsImageModes);
- //var
- // MaskColor: TtsFillcolorData;
- //begin
- // // prepare mask
- // FillChar(MaskColor.Mask, 4, $FF);
- // if ChannelMask and TS_CHANNEL_RED = TS_CHANNEL_RED then
- // MaskColor.Mask[0] := $00;
- // if ChannelMask and TS_CHANNEL_GREEN = TS_CHANNEL_GREEN then
- // MaskColor.Mask[1] := $00;
- // if ChannelMask and TS_CHANNEL_BLUE = TS_CHANNEL_BLUE then
- // MaskColor.Mask[2] := $00;
- // if ChannelMask and TS_CHANNEL_ALPHA = TS_CHANNEL_ALPHA then
- // MaskColor.Mask[3] := $00;
- //
- // pCardinal(@MaskColor.Mask[4])^ := pCardinal(@MaskColor.Mask[0])^;
- // pCardinal(@MaskColor.Mask[8])^ := pCardinal(@MaskColor.Mask[0])^;
- // pCardinal(@MaskColor.Mask[12])^ := pCardinal(@MaskColor.Mask[0])^;
- //
- // // prepare color
- // MaskColor.Color[0] := Round($FF * Red);
- // MaskColor.Color[1] := Round($FF * Green);
- // MaskColor.Color[2] := Round($FF * Blue);
- // MaskColor.Color[3] := Round($FF * Alpha);
- // pCardinal(@MaskColor.Color[4])^ := pCardinal(@MaskColor.Color[0])^;
- // pCardinal(@MaskColor.Color[8])^ := pCardinal(@MaskColor.Color[0])^;
- // pCardinal(@MaskColor.Color[12])^ := pCardinal(@MaskColor.Color[0])^;
- //
- // // image mode
- // FillChar(MaskColor.ModuloMask, 4, $00);
- // if (Modes[tsModeRed] = TS_MODE_MODULATE) and (MaskColor.Mask[0] > 0) then
- // MaskColor.ModuloMask[0] := $FF;
- // if (Modes[tsModeGreen] = TS_MODE_MODULATE) and (MaskColor.Mask[1] > 0) then
- // MaskColor.ModuloMask[1] := $FF;
- // if (Modes[tsModeBlue] = TS_MODE_MODULATE) and (MaskColor.Mask[2] > 0) then
- // MaskColor.ModuloMask[2] := $FF;
- // if (Modes[tsModeAlpha] = TS_MODE_MODULATE) and (MaskColor.Mask[3] > 0) then
- // MaskColor.ModuloMask[3] := $FF;
- // pCardinal(@MaskColor.ModuloMask[4])^ := pCardinal(@MaskColor.ModuloMask[0])^;
- //
- // // fill with color
- // if pCardinal(@MaskColor.ModuloMask[0])^ = 0 then
- // Fillcolor_RGBA8(Data, @MaskColor, Width * Height)
- // else
- // Fillcolor_RGBA8_modulo(Data, @MaskColor, Width * Height);
- //
- // {$IFNDEF TS_PURE_PASCAL}
- //// if supportSSE then
- //// Fillcolor_RGBA8_SSE(Data, @MaskColor, Width * Height)
- //// else
- // {$ENDIF}
- //
- //// Fillcolor_RGBA8(Data, @MaskColor, Width * Height);
- //end;
- var
- _Red, _Green, _Blue, _Alpha: Byte;
- RedFunc, GreenFunc, BlueFunc, AlphaFunc, LuminanceFunc: TtsModeFunc;
-
- Y, X: Integer;
- pPix: PtsColor;
-
-
- procedure AssignFunc(var Func: TtsModeFunc; Mask, Mode: tsEnum);
- begin
- if ChannelMask and Mask = Mask then begin
- if Mode = TS_MODE_MODULATE then
- Func := ModeFuncModulate
- else
- Func := ModeFuncReplace
- end else
- Func := ModeFuncIgnore
- end;
-
-
- begin
- _Red := Round($FF * Red);
- _Green := Round($FF * Green);
- _Blue := Round($FF * Blue);
- _Alpha := Round($FF * Alpha);
-
- AssignFunc(RedFunc, TS_CHANNEL_RED, Modes[tsModeRed]);
- AssignFunc(GreenFunc, TS_CHANNEL_GREEN, Modes[tsModeGreen]);
- AssignFunc(BlueFunc, TS_CHANNEL_BLUE, Modes[tsModeBlue]);
- AssignFunc(AlphaFunc, TS_CHANNEL_ALPHA, Modes[tsModeAlpha]);
- AssignFunc(LuminanceFunc, TS_CHANNEL_LUMINANCE, Modes[tsModeLuminance]);
-
- for Y := 0 to Height - 1 do begin
- pPix := ScanLine[Y];
-
- for X := 0 to Width - 1 do begin
- pPix^.Red := RedFunc (_Red, pPix^.Red);
- pPix^.Green := GreenFunc(_Green, pPix^.Green);
- pPix^.Blue := BlueFunc (_Blue, pPix^.Blue);
- pPix^.Alpha := AlphaFunc(_Alpha, pPix^.Alpha);
-
- Inc(pPix);
- end;
- end;
- end;
-
-
- procedure TtsImage.FillPattern(Pattern: TtsImage; X, Y: Integer; ChannelMask: tsBitmask; Modes: TtsImageModes);
- var
- TempX, TempY, RandX, RandY, PosX: Integer;
- RedFunc, GreenFunc, BlueFunc, AlphaFunc, LuminanceFunc: TtsModeFunc;
- pSrc, pDest: PtsColor;
-
-
- procedure AssignFunc(var Func: TtsModeFunc; Mask, Mode: tsEnum);
- begin
- if ChannelMask and Mask = Mask then begin
- if Mode = TS_MODE_MODULATE then
- Func := ModeFuncModulate
- else
- Func := ModeFuncReplace
- end else
- Func := ModeFuncIgnore
- end;
-
-
- begin
- // Pattern position
- if X < 0 then
- RandX := Random(Pattern.Width)
- else
- RandX := X;
-
- if Y < 0 then
- RandY := Random(Pattern.Height)
- else
- RandY := Y;
-
- AssignFunc(RedFunc, TS_CHANNEL_RED, Modes[tsModeRed]);
- AssignFunc(GreenFunc, TS_CHANNEL_GREEN, Modes[tsModeGreen]);
- AssignFunc(BlueFunc, TS_CHANNEL_BLUE, Modes[tsModeBlue]);
- AssignFunc(AlphaFunc, TS_CHANNEL_ALPHA, Modes[tsModeAlpha]);
- AssignFunc(LuminanceFunc, TS_CHANNEL_LUMINANCE, Modes[tsModeLuminance]);
-
- // Copy data
- for TempY := 0 to Height - 1 do begin
- pDest := ScanLine[TempY];
- pSrc := Pattern.Scanline[(TempY + RandY) mod Pattern.Height];
-
- Inc(pSrc, RandX);
- PosX := RandX;
-
- for TempX := 0 to Width - 1 do begin
- if PosX >= Pattern.Width then begin
- pSrc := Pattern.Scanline[(TempY + RandY) mod Pattern.Height];
- PosX := 0;
- end;
-
- pDest^.Red := RedFunc (pSrc^.Red, pDest^.Red);
- pDest^.Green := GreenFunc(pSrc^.Green, pDest^.Green);
- pDest^.Blue := BlueFunc (pSrc^.Blue, pDest^.Blue);
- pDest^.Alpha := AlphaFunc(pSrc^.Alpha, pDest^.Alpha);
-
- Inc(pDest);
- Inc(pSrc);
- Inc(PosX);
- end;
- end;
- end;
-
-
- procedure TtsImage.FindMinMax(var MinMaxInfo: tsRect);
- var
- X, Y: Integer;
- pPix: PtsColor;
- begin
- MinMaxInfo.Top := -1;
- MinMaxInfo.Left := -1;
- MinMaxInfo.Right := -1;
- MinMaxInfo.Bottom := -1;
-
- // Search for MinMax
- for Y := 0 to Height -1 do begin
- pPix := ScanLine[Y];
-
- for X := 0 to Width -1 do begin
- if pPix^.Alpha > 0 then begin
- if (X < MinMaxInfo.Left) or (MinMaxInfo.Left = -1) then
- MinMaxInfo.Left := X;
-
- if (X+1 > MinMaxInfo.Right) or (MinMaxInfo.Right = -1) then
- MinMaxInfo.Right := X +1;
-
- if (Y < MinMaxInfo.Top) or (MinMaxInfo.Top = -1) then
- MinMaxInfo.Top := Y;
-
- if (Y+1 > MinMaxInfo.Bottom) or (MinMaxInfo.Bottom = -1) then
- MinMaxInfo.Bottom := Y +1;
- end;
-
- Inc(pPix);
- end;
- end;
- end;
-
-
- function TtsImage.GetEmpty: Boolean;
- begin
- Result := fData = nil;
- end;
-
-
- function TtsImage.GetFormatSize(Format: TtsFormat): Integer;
- begin
- case Format of
- tsFormatRGBA8: Result := 4;
- else
- Result := 0;
- end;
- end;
-
-
- function TtsImage.GetScanLine(Index: Integer): pointer;
- begin
- if not fScanLinesValid then
- UpdateScanLines;
-
- if (fScanLinesValid) and (Index >= 0) and (Index <= High(fScanLines)) then
- Result := fScanLines[Index]
- else
- Result := nil;
- end;
-
-
- procedure TtsImage.LoadFromFile(FileName: PAnsiChar);
- var
- Surface, ConvSurface: PSDL_Surface;
- Format: TSDL_PixelFormat;
-
- ImageSize: Integer;
- Image: pByte;
- begin
- Surface := IMG_Load(FileName);
-
- if Surface <> nil then
- try
- FillChar(Format, SizeOf(TSDL_PixelFormat), 0);
- Format.BitsPerPixel := 32;
- Format.BytesPerPixel := 4;
- Format.RMask := $000000FF;
- Format.GMask := $0000FF00;
- Format.BMask := $00FF0000;
- Format.AMask := $FF000000;
- Format.Rshift := 0;
- Format.Gshift := 8;
- Format.Bshift := 16;
- Format.Ashift := 24;
-
- ConvSurface := SDL_ConvertSurface(Surface, @Format, SDL_SWSURFACE);
- if ConvSurface <> nil then
- try
- // Set Image Size
- ImageSize := ConvSurface^.Width * ConvSurface^.Height * 4;
-
- GetMem(Image, ImageSize);
- try
- // Copy image
- Move(ConvSurface^.pixels^, Image^, ImageSize);
-
- // Set new Data
- SetDataPtr(Image, tsFormatRGBA8, ConvSurface^.Width, ConvSurface^.Height);
- except
- FreeMem(Image);
- end;
- finally
- SDL_FreeSurface(ConvSurface);
- end;
- finally
- SDL_FreeSurface(Surface);
- end;
- end;
-
-
- procedure TtsImage.Resize(NewWidth, NewHeight, X, Y: Integer);
- var
- pImage: PByte;
- PixSize, LineSize, ImageSize, OrgLineSize: Integer;
-
- pSource, pDest: PByte;
- YStart, YEnd, YPos, XStart, XEnd: Integer;
- begin
- if (NewHeight = 0) or (NewWidth = 0) then begin
- SetDataPtr(nil);
- end else begin
- PixSize := GetFormatSize(Format);
- LineSize := PixSize * NewWidth;
- ImageSize := LineSize * NewHeight;
-
- OrgLineSize := PixSize * Width;
-
- GetMem(pImage, ImageSize);
- try
- FillChar(pImage^, ImageSize, 0);
-
- // positions
- YStart := Max(0, Y);
- YEnd := Min(NewHeight, Y + Height);
-
- XStart := Max(0, X);
- XEnd := Min(NewWidth, X + Width);
-
- // copy data
- for YPos := YStart to YEnd -1 do begin
- pDest := pImage;
- Inc(pDest, LineSize * YPos + PixSize * XStart);
-
- pSource := fData;
- Inc(pSource, OrgLineSize * (YPos - Y) + PixSize * (XStart - X));
-
- Move(pSource^, pDest^, (XEnd - XStart) * PixSize);
- end;
-
- // assign
- SetDataPtr(pImage, Format, NewWidth, NewHeight);
- except
- FreeMem(pImage);
- end;
- end;
- end;
-
-
- procedure TtsImage.SetDataPtr(aData: Pointer; aFormat: TtsFormat; aWidth, aHeight: Integer);
- begin
- fScanLinesValid := False;
-
- if fData <> nil then
- FreeMemory(fData);
-
- fData := aData;
- if fData <> nil then begin
- fWidth := aWidth;
- fHeight := aHeight;
- fFormat := aFormat;
- end else begin
- fWidth := 0;
- fHeight := 0;
- fFormat := tsFormatEmpty;
- end;
- end;
-
-
- procedure TtsImage.UpdateScanLines;
- var
- Idx, LineSize: Integer;
- Temp: pByte;
- begin
- LineSize := fWidth * GetFormatSize(fFormat);
-
- SetLength(fScanLines, fHeight);
- for Idx := 0 to fHeight -1 do begin
- Temp := fData;
- Inc(Temp, Idx * LineSize);
-
- fScanLines[Idx] := Temp;
- end;
-
- fScanLinesValid := True;
- end;
-
-
- { TtsFont }
-
- procedure TtsFont.AddChar(CharCode: WideChar; Char: TtsChar);
- var
- Idx1, Idx2: Integer;
- Chars: PtsFontCharArray;
- begin
- Idx1 := Hi(Ord(CharCode));
- Chars := fChars[Idx1];
-
- if Chars = nil then begin
- New(Chars);
- FillChar(Chars^, SizeOf(TtsFontCharArray), 0);
-
- fChars[Idx1] := Chars;
- end;
-
- if Chars <> nil then begin
- Idx2 := Lo(Ord(CharCode));
- Chars^.Chars[Idx2] := Char;
- Chars^.CharCount := Chars^.CharCount + 1;
- end;
- end;
-
-
- procedure TtsFont.ClearChars;
- var
- Idx1, Idx2: Integer;
- Chars: PtsFontCharArray;
-
- Char: TtsChar;
- begin
- // iterate first step
- for Idx1 := Low(fChars) to High(fChars) do begin
- Chars := fChars[Idx1];
-
- // iterate second step
- if Chars <> nil then begin
- for Idx2 := Low(Chars^.Chars) to High(Chars^.Chars) do begin
- Char := Chars^.Chars[Idx2];
-
- // free char
- if Char <> nil then begin
- if Char.RendererImageReference <> nil then begin
- if fRenderer <> nil then
- fRenderer.RemoveImageReference(Char.RendererImageReference);
-
- Char.RendererImageReference.Free;
- end;
-
- Char.Free;
- end;
- end;
-
- // dispose
- fChars[Idx1] := nil;
- dispose(Chars);
- end;
- end;
- end;
-
-
- constructor TtsFont.Create(Renderer: TtsRenderer; Size: Integer; Style: TtsFontStyles; Format: TtsFormat; AntiAliasing: TtsAntiAliasing);
- begin
- inherited Create;
-
- fRenderer := Renderer;
-
- fSize := Size;
- fStyle := Style;
- fFormat := Format;
- fAntiAliasing := AntiAliasing;
- end;
-
-
- procedure TtsFont.DeleteChar(CharCode: WideChar);
- var
- Idx1, Idx2: Integer;
- Chars: PtsFontCharArray;
- Char: TtsChar;
- begin
- // first step
- Idx1 := Hi(Ord(CharCode));
- Chars := fChars[Idx1];
-
- if Chars <> nil then begin
- // second step
- Idx2 := Lo(Ord(CharCode));
- Char := Chars^.Chars[Idx2];
-
- if Char <> nil then begin
- Chars^.Chars[Idx2] := nil;
- Chars^.CharCount := Chars^.CharCount -1;
-
- // no chars so delete the subpage
- if Chars^.CharCount = 0 then begin
- fChars[Idx1] := nil;
- Dispose(Chars);
- end;
-
- if Char.RendererImageReference <> nil then begin
- if fRenderer <> nil then
- fRenderer.RemoveImageReference(Char.RendererImageReference);
-
- Char.RendererImageReference.Free;
- end;
-
- Char.Free;
- end;
- end;
- end;
-
-
- destructor TtsFont.Destroy;
- begin
- // Chars
- ClearChars;
-
- inherited;
- end;
-
-
- function TtsFont.GetChar(CharCode: WideChar): TtsChar;
- {$IFDEF TS_PURE_PASCAL}
- var
- Chars: PtsFontCharArray;
- begin
- // first step
- Chars := fChars[Hi(Ord(CharCode))];
-
- // second step
- if Chars <> nil then
- Result := Chars^.Chars[Lo(Ord(CharCode))]
- else
- Result := nil;
- {$else}
- asm
- add eax, offset TtsFont.fChars // add offset of fChars to self
-
- movzx ecx, dh // extract high byte to ecx
- mov eax, dword ptr [eax + ecx * 4] // copy array element to eax
-
- test eax, eax // subarray is empty
- jz @@end
-
- movzx edx, dl // extract lower byte to ed x
- mov eax, dword ptr [eax + edx * 4] // copy array element to eax
-
- @@end:
- {$endif}
- end;
-
-
- procedure TtsFont.GetTextMetric(var Metric: TtsTextMetric);
- begin
- Metric.Ascent := Ascent;
- Metric.Descent := Descent;
- Metric.LineSkip := Ascent + Descent + ExternalLeading;
- Metric.LineSkip_with_LineSpace := Metric.LineSkip + LineSpacing;
- end;
-
-
- // May be fpc has problems because it's an virtual function
- function TtsFont.Validate(CharCode: WideChar): Boolean;
- //{$IFDEF TS_PURE_PASCAL}
- begin
- Result := GetChar(CharCode) <> nil;
- //{$else}
- //asm
- // // self is still in eax
- // // charcode is still is edx
- // call TtsFont.GetChar
- // test eax, eax
- // setnz al
- //{$endif}
- end;
-
-
- { TtsFontCreator }
-
- procedure TtsFontCreator.AddChar(CharCode: WideChar);
- var
- tsChar: TtsChar;
-
- GlyphOriginX, GlyphOriginY, GlyphWidth, GlyphHeight, Advance: Integer;
- CharImage: TtsImage;
- begin
- if fCreateChars and (Ord(CharCode) > 0) then begin
- tsChar := GetChar(CharCode);
-
- // Check if the char allready was added
- if tsChar = nil then begin
- // check if the Char exists in the font
- if GetGlyphMetrics(CharCode, GlyphOriginX, GlyphOriginY, GlyphWidth, GlyphHeight, Advance) then
- if (GlyphOriginX <> 0) or (GlyphOriginY <> 0) or (GlyphWidth <> 0) or (GlyphHeight <> 0) or (Advance <> 0) then begin
- // Getting Image of Char
- CharImage := TtsImage.Create;
- try
- if fRenderer.SaveImages then begin
- if (GlyphWidth > 0) and (GlyphHeight > 0) then begin
- // getting char image
- GetCharImage(CharCode, CharImage);
- end;
- end;
-
- if (tsStyleUnderline in Style) or (tsStyleStrikeout in Style) then begin
- if (CharImage.Width = 0) and (CharImage.Height = 0) then begin
- CharImage.CreateEmpty(tsFormatRGBA8, Advance, 1);
- GlyphOriginY := 1;
- end;
- end;
-
- // Create new Entry for Char
- tsChar := TtsChar.Create(CharCode);
- tsChar.GlyphOriginX := GlyphOriginX;
- tsChar.GlyphOriginY := GlyphOriginY;
- tsChar.Advance := Advance;
- tsChar.GlyphRect.Left := 0;
- tsChar.GlyphRect.Top := 0;
- tsChar.GlyphRect.Right := CharImage.Width;
- tsChar.GlyphRect.Bottom := CharImage.Height;
-
- AddChar(CharCode, tsChar);
-
- if fRenderer.SaveImages then begin
- try
- // apply underline style
- if tsStyleUnderline in Style then
- DrawLine(tsChar, CharImage, UnderlinePosition, UnderlineSize);
-
- // apply strikeout stlye
- if tsStyleStrikeout in Style then
- DrawLine(tsChar, CharImage, StrikeoutPosition, StrikeoutSize);
- except
- CharImage.FillColor(1, 0, 0, 0, TS_CHANNELS_RGB, cModesNormal);
- end;
-
- // PostProcessing
- DoPostProcess(CharImage, tsChar);
-
- // Add invisible border for resizing (at last before adding)
- if AddResizingBorder then begin
- tsChar.HasResizingBorder := True;
-
- CharImage.AddResizingBorder(tsChar);
- end;
-
- // Add Image to Renderer
- tsChar.RendererImageReference := fRenderer.AddImage(tsChar, CharImage);
- end;
- finally
- FreeAndNil(CharImage);
- end;
- end;
- end;
- end;
- end;
-
-
- function TtsFontCreator.AddPostProcessStep(PostProcessStep: TtsPostProcessStep): TtsPostProcessStep;
- begin
- Result := PostProcessStep;
-
- fPostProcessSteps.Add(PostProcessStep);
- end;
-
-
- procedure TtsFontCreator.ClearPostProcessSteps;
- var
- Idx: Integer;
- begin
- for Idx := fPostProcessSteps.Count -1 downto 0 do
- DeletePostProcessStep(Idx);
-
- fPostProcessSteps.Clear;
- end;
-
-
- constructor TtsFontCreator.Create(Renderer: TtsRenderer; Size: Integer; Style: TtsFontStyles; Format: TtsFormat; AntiAliasing: TtsAntiAliasing);
- begin
- inherited Create(Renderer, Size, Style, Format, AntiAliasing);
-
- fCreateChars := True;
-
- fPostProcessSteps := TList.Create;
- end;
-
-
- procedure TtsFontCreator.DeletePostProcessStep(Index: Integer);
- var
- Entry: TtsPostProcessStep;
- begin
- if (Index >= 0) and (Index < fPostProcessSteps.Count) then begin
- Entry := fPostProcessSteps[Index];
- Entry.Free;
-
- fPostProcessSteps.Delete(Index);
- end;
- end;
-
-
- destructor TtsFontCreator.Destroy;
- begin
- if fPostProcessSteps <> nil then begin
- ClearPostProcessSteps;
- FreeAndNil(fPostProcessSteps);
- end;
-
- inherited;
- end;
-
-
- procedure TtsFontCreator.DoPostProcess(var CharImage: TtsImage; const tsChar: TtsChar);
- var
- Idx: Integer;
- Entry: TtsPostProcessStep;
- begin
- if not CharImage.Empty then begin
- for Idx := 0 to fPostProcessSteps.Count - 1 do begin
- Entry := fPostProcessSteps[Idx];
-
- if Entry.IsInRange(tsChar.CharCode) then
- Entry.PostProcess(CharImage, tsChar);
- end;
- end;
- end;
-
-
- procedure TtsFontCreator.DrawLine(Char: TtsChar; CharImage: TtsImage; LinePosition, LineSize: Integer);
- var
- NewWidth, NewHeight, NewPosX, NewPosY, YOffset, Idx: Integer;
-
-
- procedure FillLine(pPix: ptsColor);
- var
- Idx: Integer;
- begin
- Idx := NewWidth;
- while Idx > 0 do begin
- pPix^.Red := $FF;
- pPix^.Green := $FF;
- pPix^.Blue := $FF;
- pPix^.Alpha := $FF;
-
- Inc(pPix);
- Dec(Idx);
- end;
- end;
-
- begin
- if LineSize <= 0 then
- Exit;
-
- LinePosition := LinePosition - LineSize;
-
- // calculate width and height
- NewWidth := CharImage.Width;
- NewPosX := 0;
- NewHeight := CharImage.Height;
- NewPosY := 0;
-
- // expand image to the full advance
- if Char.Advance > CharImage.Width then
- NewWidth := Char.Advance;
-
- // add glyph position to image width and set position
- if Char.GlyphOriginX > Char.GlyphRect.Left then begin
- NewWidth := NewWidth + Char.GlyphOriginX;
- NewPosX := Char.GlyphOriginX;
- end;
-
- if Char.GlyphOriginX < 0 then
- NewWidth := NewWidth - Char.GlyphOriginX;
-
- // line is under the image
- if LinePosition < (Char.GlyphOriginY - CharImage.Height) then
- NewHeight := NewHeight + (Char.GlyphOriginY - CharImage.Height - LinePosition);
-
- // line is above the image
- if LinePosition + LineSize > Char.GlyphOriginY then begin
- NewPosY := ((LinePosition + LineSize) - Char.GlyphOriginY);
- NewHeight := NewHeight + NewPosY;
- end;
-
- // resize
- CharImage.Resize(NewWidth, NewHeight, NewPosX, NewPosY);
-
- // draw lines
- YOffset := (Char.GlyphOriginY + NewPosY) - LinePosition;
- for Idx := 1 to LineSize do
- FillLine(CharImage.ScanLine[YOffset - Idx]);
-
- // move glyph rect
- Char.GlyphRect.Left := Char.GlyphRect.Left + NewPosX;
- Char.GlyphRect.Right := Char.GlyphRect.Right + NewPosX;
- Char.GlyphRect.Top := Char.GlyphRect.Top + NewPosY;
- Char.GlyphRect.Bottom := Char.GlyphRect.Bottom + NewPosY;
- end;
-
-
- function TtsFontCreator.GetPostProcessStep(Index: Integer): TtsPostProcessStep;
- begin
- if (Index >= 0) and (Index < fPostProcessSteps.Count) then
- Result := TtsPostProcessStep(fPostProcessSteps[Index])
- else
- Result := nil;
- end;
-
-
- function TtsFontCreator.GetPostProcessStepCount: Integer;
- begin
- Result := fPostProcessSteps.Count;
- end;
-
-
- function TtsFontCreator.Validate(CharCode: WideChar): Boolean;
- begin
- Result := Inherited Validate(CharCode);
-
- // if char wasnt found then create it.
- if not Result then begin
- AddChar(CharCode);
-
- // and test for creation
- Result := Inherited Validate(CharCode);
- end;
- end;
-
-
- { TtsPostProcessStep }
-
- procedure TtsPostProcessStep.AddUsageChars(Usage: TtsFontProcessStepUsage; Chars: pWideChar);
- begin
- if Chars <> nil then
- while Chars^ <> #0 do begin
- AddUsageRange(Usage, Chars^, Chars^);
-
- Inc(Chars);
- end;
- end;
-
-
- procedure TtsPostProcessStep.AddUsageRange(Usage: TtsFontProcessStepUsage;
- StartChar, EndChar: WideChar);
- var
- pItem: PtsPostProcessStepRange;
- begin
- New(pItem);
-
- pItem^.StartChar := StartChar;
- pItem^.EndChar := EndChar;
-
- case Usage of
- tsUInclude:
- fIncludeCharRange.Add(pItem);
- tsUExclude:
- fExcludeCharRange.Add(pItem);
- end;
- end;
-
-
- procedure TtsPostProcessStep.ClearExcludeRange;
- begin
- ClearList(fExcludeCharRange);
- end;
-
-
- procedure TtsPostProcessStep.ClearIncludeRange;
- begin
- ClearList(fIncludeCharRange);
- end;
-
-
- procedure TtsPostProcessStep.ClearList(List: TList);
- var
- Idx: Integer;
- pItem: PtsPostProcessStepRange;
- begin
- for Idx := 0 to List.Count - 1 do begin
- pItem := List[Idx];
- Dispose(pItem);
- end;
-
- List.Clear;
- end;
-
-
- constructor TtsPostProcessStep.Create;
- begin
- inherited Create;
-
- fIncludeCharRange := TList.Create;
- fExcludeCharRange := TList.Create;
- end;
-
-
- destructor TtsPostProcessStep.Destroy;
- begin
- ClearIncludeRange;
- ClearExcludeRange;
-
- fIncludeCharRange.Free;
- fExcludeCharRange.Free;
-
- inherited;
- end;
-
-
- function TtsPostProcessStep.IsInRange(CharCode: WideChar): Boolean;
- var
- Idx: Integer;
- pItem: PtsPostProcessStepRange;
- begin
- // Look in include range
- if fIncludeCharRange.Count <> 0 then begin
- Result := False;
-
- for Idx := 0 to fIncludeCharRange.Count - 1 do begin
- pItem := fIncludeCharRange[Idx];
-
- if (CharCode >= pItem^.StartChar) and (CharCode <= pItem^.EndChar) then begin
- Result := True;
- Break;
- end;
- end;
- end else
- Result := True;
-
- // Look in exclude range but only if its included
- if Result then begin
- for Idx := 0 to fExcludeCharRange.Count - 1 do begin
- pItem := fExcludeCharRange[Idx];
-
- if (CharCode >= pItem^.StartChar) and (CharCode <= pItem^.EndChar) then begin
- Result := False;
- Break;
- end;
- end;
- end;
- end;
-
-
- { TtsFontCreatorSDL }
-
- constructor TtsFontCreatorSDL.Create(Renderer: TtsRenderer; const Filename: AnsiString; Size: Integer;
- Style: TtsFontStyles; Format: TtsFormat; AntiAliasing: TtsAntiAliasing);
- var
- TempStyle: Integer;
- begin
- inherited Create(Renderer, Size, Style, Format, AntiAliasing);
-
- // Init SDL_ttf
- if (TTF_WasInit = 0) then
- if (TTF_Init < 0) then
- raise Exception.Create('TtsFontCreator.Create: TTF_Init error');
-
- // Create FFT_Font
- fSDLFont := TTF_OpenFont(pAnsiChar(Filename), Size);
-
- // Getting style - SDL_ttf dosn't support it. so we only have normal
- fFontFileStyle := TS_STYLE_NORMAL;
-
- // getting props
- Ascent := TTF_FontAscent(fSDLFont);
- Descent := -TTF_FontDescent(fSDLFont);
- ExternalLeading := TTF_FontLineSkip(fSDLFont) - (Ascent + Descent);
-
- // SDL_ttf dosn't support it so we must calculate it by our self
- UnderlinePosition := - round(Ascent / 8);
- if UnderlinePosition > -1 then
- UnderlinePosition := -1;
-
- if tsStyleBold in Style then
- UnderlineSize := round(Ascent / 8)
- else
- UnderlineSize := round(Ascent / 13);
- if UnderlineSize < 1 then
- UnderlineSize := 1;
-
- StrikeoutPosition := round(Ascent / 3.5);
- if tsStyleBold in Style then
- StrikeoutSize := round(Ascent / 14)
- else
- StrikeoutSize := round(Ascent / 19);
- if StrikeoutSize < 1 then
- StrikeoutSize := 1;
-
- FixedWidth := TTF_FontFaceIsFixedWidth(fSDLFont) > 0;
-
- Copyright := '';
- FaceName := TTF_FontFaceFamilyName(fSDLFont);
- StyleName := TTF_FontFaceStyleName(fSDLFont);
- FullName := FaceName + #32 + StyleName;
-
- // Set style
- TempStyle := 0;
-
- if tsStyleBold in Style then
- TempStyle := TempStyle or TTF_STYLE_BOLD;
- if tsStyleItalic in Style then
- TempStyle := TempStyle or TTF_STYLE_ITALIC;
- // if tsStyleUnderline in Style then
- // TempStyle := TempStyle or TTF_STYLE_UNDERLINE;
-
- TTF_SetFontStyle(fSDLFont, TempStyle);
- end;
-
-
- destructor TtsFontCreatorSDL.Destroy;
- begin
- // Destroy Font
- TTF_CloseFont(fSDLFont);
- fSDLFont := nil;
-
- inherited;
- end;
-
-
- procedure TtsFontCreatorSDL.GetCharImage(CharCode: WideChar; const CharImage: TtsImage);
- const
- WHITE: TSDL_Color = (r: $FF; g: $FF; b: $FF; unused: 0);
- BLACK: TSDL_Color = (r: $00; g: $00; b: $00; unused: 0);
-
- var
- CharSurface: PSDL_Surface;
-
- X, Y, TempWidth: Integer;
- pSource: pByte;
- pDest: PtsColor;
-
-
- function GetPaletteEntry(Index: Byte): Byte;
- begin
- Result := 0;
-
- with CharSurface^.format^ do begin
- if palette <> nil then
- if (palette^.ncolors > 0) and (Index < palette^.ncolors) then
- Result := palette^.colors[Index].r
- end;
- end;
-
-
- begin
- //CharCode: Needs to use an widestring because of #0 endchar
-
- case AntiAliasing of
- tsAANone:
- CharSurface := TTF_RenderGlyph_Solid(fSDLFont, Ord(CharCode), WHITE);
- tsAANormal:
- CharSurface := TTF_RenderGlyph_Shaded(fSDLFont, Ord(CharCode), WHITE, BLACK);
- end;
-
-
- if CharSurface <> nil then
- try
- CharImage.CreateEmpty(fFormat, CharSurface^.Width, CharSurface^.Height);
- try
- TempWidth := CharSurface^.Width;
- if TempWidth mod 4 > 0 then
- TempWidth := (TempWidth div 4 + 1) * 4;
-
- for Y := 0 to CharSurface^.Height - 1 do begin
- pDest := CharImage.ScanLine[Y];
- pSource := CharSurface^.Pixels;
- Inc(pSource, Y * TempWidth);
-
- for X := 0 to CharSurface^.Width - 1 do begin
- pDest^.Red := $FF;
- pDest^.Green := $FF;
- pDest^.Blue := $FF;
- pDest^.Alpha := GetPaletteEntry(pSource^);
-
- Inc(pSource);
- Inc(pDest);
- end;
- end;
- except
- CharImage.Free;
- end;
- finally
- SDL_FreeSurface(CharSurface);
- end;
- end;
-
-
- function TtsFontCreatorSDL.GetGlyphMetrics(CharCode: WideChar; var GlyphOriginX, GlyphOriginY, GlyphWidth, GlyphHeight, Advance: Integer): Boolean;
- var
- MinX, MaxX, MinY, MaxY: Integer;
- begin
- if fSDLFont <> nil then begin
- Result := TTF_GlyphMetrics(fSDLFont, Ord(CharCode), MinX, MaxX, MinY, MaxY, Advance) = 0;
- GlyphWidth := MaxX - MinX;
- GlyphHeight := MaxY - MinY;
-
- GlyphOriginX := MinX;
- GlyphOriginY := GlyphHeight + MinY;
- end
-
- else
- Result := False;
- end;
-
-
- { TtsFontCreatorGDIFontFace }
-
- constructor TtsFontCreatorGDIFontFace.Create(Renderer: TtsRenderer; const Fontname: AnsiString;
- Size: Integer; Style: TtsFontStyles; Format: TtsFormat; AntiAliasing: TtsAntiAliasing);
- var
- Idx: Integer;
- LogFont: TLogFontA;
-
- DC: HDC;
-
- TableName: Cardinal;
- Buffer: Pointer;
- BufferSize: Cardinal;
- Lang: AnsiString;
-
- TextMetric: TTextMetricW;
- OutTextMetric: TOutlineTextmetricW;
- begin
- inherited Create (Renderer, Size, Style, Format, AntiAliasing);
-
- // setting up matrix
- FillChar(fMat2, SizeOf(TMat2), $00);
-
- fMat2.eM11.Value := 1;
- fMat2.eM22.Value := 1;
-
- fFontname := Fontname;
-
- // Creating Font
- FillChar(LogFont, SizeOf(LogFont), 0);
-
- // name
- fFontname := Fontname;
- for Idx := 1 to min(Length(Fontname), Length(LogFont.lfFaceName)) do
- LogFont.lfFaceName[Idx -1] := Fontname[Idx];
-
- // char set
- LogFont.lfCharSet := DEFAULT_CHARSET;
-
- // size
- // fPointSize := PointSize;
- LogFont.lfHeight := -Size; //-MulDiv(PointSize, GetDeviceCaps(Temp.Canvas.Handle, LOGPIXELSY), 72);
-
- // style
- if tsStyleBold in Style then
- LogFont.lfWeight := FW_BOLD
- else
- LogFont.lfWeight := FW_NORMAL;
-
- if tsStyleItalic in Style then
- LogFont.lfItalic := 1;
-
- if tsStyleUnderline in Style then
- LogFont.lfUnderline := 1;
-
- // smooth
- case AntiAliasing of
- tsAANone:
- LogFont.lfQuality := NONANTIALIASED_QUALITY;
- tsAANormal:
- LogFont.lfQuality := ANTIALIASED_QUALITY;
- // tsSmoothSmooth:
- // begin
- // if Smooth = tsSmoothSmooth then
- // fMat2.eM11.Value := 3;
- // end;
- end;
-
- // create font
- fFontHandle := CreateFontIndirectA(LogFont);
-
- // Getting informations about font
- DC := CreateCompatibleDC(0);
- try
- SelectObject(DC, fFontHandle);
-
- // find strings in text
- TableName := MakeTTTableName('n', 'a', 'm', 'e');
- BufferSize := GetFontData(DC, TableName, 0, nil, 0);
-
- if BufferSize <> GDI_ERROR then begin
- GetMem(Buffer, BufferSize);
- try
- if GetFontData(DC, TableName, 0, Buffer, BufferSize) <> GDI_ERROR then begin
- SetLength(Lang, 4);
- GetLocaleInfoA(LOCALE_USER_DEFAULT, LOCALE_ILANGUAGE, @Lang[1], 4);
-
- GetTTString(Buffer, BufferSize, NAME_ID_COPYRIGHT, StrToInt('$' + String(Lang)), fCopyright);
- GetTTString(Buffer, BufferSize, NAME_ID_FACE_NAME, StrToInt('$' + String(Lang)), fFaceName);
- GetTTString(Buffer, BufferSize, NAME_ID_STYLE_NAME, StrToInt('$' + String(Lang)), fStyleName);
- GetTTString(Buffer, BufferSize, NAME_ID_FULL_NAME, StrToInt('$' + String(Lang)), fFullName);
- end;
- finally
- FreeMem(Buffer);
- end;
- end;
-
- // Text Metric
- GetTextMetricsW(DC, TextMetric);
-
- Ascent := TextMetric.tmAscent;
- Descent := TextMetric.tmDescent;
- ExternalLeading := TextMetric.tmExternalLeading;
-
- DefaultChar := TextMetric.tmDefaultChar;
-
- // inverse logic of the bit. clear then fixed pitch
- FixedWidth := TextMetric.tmPitchAndFamily and TMPF_FIXED_PITCH = 0;
-
- // style
- FontFileStyle := TS_STYLE_NORMAL;
-
- if TextMetric.tmWeight > 400 then
- FontFileStyle := FontFileStyle or TS_STYLE_BOLD;
-
- if TextMetric.tmItalic > 0 then
- FontFileStyle := FontFileStyle or TS_STYLE_ITALIC;
-
- if TextMetric.tmUnderlined > 0 then
- FontFileStyle := FontFileStyle or TS_STYLE_UNDERLINE;
-
- if TextMetric.tmStruckOut > 0 then
- FontFileStyle := FontFileStyle or TS_STYLE_STRIKEOUT;
-
- // Outline Text Metric
- GetOutlineTextMetricsW(DC, SizeOf(OutTextMetric), OutTextMetric);
-
- UnderlinePosition := OutTextMetric.otmsUnderscorePosition;
- UnderlineSize := OutTextMetric.otmsUnderscoreSize;
- if UnderlineSize < 1 then
- UnderlineSize := 1;
-
- StrikeoutPosition := OutTextMetric.otmsStrikeoutPosition;
- StrikeoutSize := OutTextMetric.otmsStrikeoutSize;
- if StrikeoutSize < 1 then
- StrikeoutSize := 1;
- finally
- DeleteDC(DC);
- end;
- end;
-
-
- destructor TtsFontCreatorGDIFontFace.Destroy;
- begin
- DeleteObject(fFontHandle);
-
- inherited;
- end;
-
-
- procedure TtsFontCreatorGDIFontFace.GetCharImage(CharCode: WideChar; const CharImage: TtsImage);
- var
- DC: HDC;
- begin
- DC := CreateCompatibleDC(0);
- try
- SelectObject(DC, fFontHandle);
-
- case AntiAliasing of
- tsAANone:
- GetCharImageNone(DC, CharCode, CharImage);
- tsAANormal:
- GetCharImageAntialiased(DC, CharCode, CharImage);
- end;
- finally
- DeleteDC(DC);
- end;
- end;
-
-
- procedure TtsFontCreatorGDIFontFace.GetCharImageAntialiased(DC: HDC; CharCode: WideChar; const CharImage: TtsImage);
- var
- Metric: TGlyphMetrics;
- pBuffer: Pointer;
- Size, OutlineResult: Cardinal;
- GlyphIndex: Integer;
- X, Y, Height, Width, Spacer: Integer;
- pDest: PtsColor;
- pSrc: pByte;
-
-
- procedure CopyPixel;
- var
- Idx: Integer;
- Temp, Count: Cardinal;
- begin
- Count := Min(X, fMat2.eM11.Value);
-
- Temp := 0;
- for Idx := 0 to Count -1 do begin
- Temp := Temp + pSrc^;
- Inc(pSrc);
- end;
-
- Dec(X, Count);
-
- pDest^.Red := $FF;
- pDest^.Green := $FF;
- pDest^.Blue := $FF;
- pDest^.Alpha := $FF * Temp div ($40 * Cardinal(fMat2.eM11.Value));
-
- Inc(pDest);
- end;
-
-
- begin
- FillChar(Metric, SizeOf(TGlyphMetrics), $00);
-
- // Translate Glyphindex
- GlyphIndex := GetGlyphIndex(CharCode);
-
- // size
- // if GlyphIndex <> 0 then
- Size := GetGlyphOutlineA(DC, GlyphIndex, GGO_GRAY8_BITMAP or GGO_GLYPH_INDEX, @Metric, 0, nil, @fMat2);
- // else
- // Size := GetGlyphOutlineA(DC, Ord(fDefaultChar), GGO_GRAY8_BITMAP, Metric, 0, nil, fMat2);
-
- if (Size <> GDI_ERROR) and (Size <> 0) then begin
- GetMem(pBuffer, Size);
- try
- // glyphdata
- // if GlyphIndex <> 0 then
- OutlineResult := GetGlyphOutlineA(DC, GlyphIndex, GGO_GRAY8_BITMAP or GGO_GLYPH_INDEX, @Metric, Size, pBuffer, @fMat2);
- // else
- // OutlineResult := GetGlyphOutlineA(DC, Ord(fDefaultChar), GGO_GRAY8_BITMAP, Metric, Size, pBuffer, fMat2);
-
- if OutlineResult <> GDI_ERROR then begin
- // Image size
- Height := Metric.gmBlackBoxY;
- Width := Integer(Metric.gmBlackBoxX) div fMat2.eM11.Value;
- if (Integer(Metric.gmBlackBoxX) mod fMat2.eM11.Value) <> 0 then
- Width := Width + fMat2.eM11.Value - (Integer(Metric.gmBlackBoxX) mod fMat2.eM11.Value);
-
- // spacer
- if (Metric.gmBlackBoxX mod 4) <> 0 then
- Spacer := 4 - (Metric.gmBlackBoxX mod 4)
- else
- Spacer := 0;
-
- // copy image
- if (Height > 0) and (Width > 0) then begin
- CharImage.CreateEmpty(fFormat, Width, Height);
-
- pSrc := pBuffer;
-
- for Y := 0 to Height -1 do begin
- pDest := CharImage.ScanLine[Y];
-
- X := Metric.gmBlackBoxX;
- while X > 0 do
- CopyPixel;
-
- if Spacer <> 0 then
- Inc(pSrc, Spacer);
- end;
- end;
- end;
- finally
- FreeMem(pBuffer);
- end;
- end;
- end;
-
-
- procedure TtsFontCreatorGDIFontFace.GetCharImageNone(DC: HDC; CharCode: WideChar; const CharImage: TtsImage);
- var
- Metric: TGlyphMetrics;
- pBuffer: Pointer;
- Size, OutlineResult: Cardinal;
- GlyphIndex: Integer;
- X, Y, Height, Width, SourceX, SourceWidth: Integer;
- pDest: PtsColor;
- pSrc: pByte;
-
-
- procedure ExpandByte;
- var
- Idx, Count, SourceCount: Integer;
- begin
- SourceCount := Min(8, SourceX);
- Count := Min(8, X);
-
- for Idx := 1 to Count do begin
- pDest^.Red := $FF;
- pDest^.Green := $FF;
- pDest^.Blue := $FF;
-
- if (pSrc^ and $80) > 0 then
- pDest^.Alpha := $FF
- else
- pDest^.Alpha := $00;
-
- pSrc^ := (pSrc^ and not $80) shl 1;
-
- Inc(pDest);
- end;
-
- Dec(SourceX, SourceCount);
- Dec(X, Count);
- end;
-
-
- begin
- // fMat2.eM11.Value must be 1
- Assert(fMat2.eM11.Value = 1);
-
- FillChar(Metric, SizeOf(TGlyphMetrics), $00);
-
- // Translate Glyphindex
- GlyphIndex := GetGlyphIndex(CharCode);
-
- // size
- // if GlyphIndex <> 0 then
- Size := GetGlyphOutlineA(DC, GlyphIndex, GGO_BITMAP or GGO_GLYPH_INDEX, @Metric, 0, nil, @fMat2);
- // else
- // Size := GetGlyphOutlineA(DC, Ord(fDefaultChar), GGO_BITMAP, Metric, 0, nil, fMat2);
-
- if (Size <> GDI_ERROR) and (Size <> 0) then begin
- GetMem(pBuffer, Size);
- try
- // glyphdata
- // if GlyphIndex <> 0 then
- OutlineResult := GetGlyphOutlineA(DC, GlyphIndex, GGO_BITMAP or GGO_GLYPH_INDEX, @Metric, Size, pBuffer, @fMat2);
- // else
- // OutlineResult := GetGlyphOutlineA(DC, Ord(fDefaultChar), GGO_BITMAP, Metric, Size, pBuffer, fMat2);
-
- if OutlineResult <> GDI_ERROR then begin
- SourceWidth := (Size div Metric.gmBlackBoxY) * 8;
- Width := Metric.gmBlackBoxX;
- Height := Metric.gmBlackBoxY;
-
- // copy image
- if (Height > 0) and (Width > 0) then begin
- CharImage.CreateEmpty(tsFormatRGBA8, Width, Height);
-
- pSrc := pBuffer;
-
- for Y := 0 to Height -1 do begin
- pDest := CharImage.ScanLine[Y];
-
- // copy data
- SourceX := SourceWidth;
- X := Width;
- while SourceX > 0 do begin
- ExpandByte;
-
- Inc(pSrc);
- end;
- end;
- end;
- end;
- finally
- FreeMem(pBuffer);
- end;
- end;
- end;
-
-
- function TtsFontCreatorGDIFontFace.GetGlyphIndex(CharCode: WideChar): Integer;
- var
- // ReadRawData: Boolean;
- DC: HDC;
- GCPRes: TGCPResultsW;
- begin
- Result := 0;
-
- // ReadRawData := True;
-
- DC := CreateCompatibleDC(0);
- try
- SelectObject(DC, fFontHandle);
-
- // windows nt
- if Addr(GetCharacterPlacementW) <> nil then begin
- FillChar(GCPRes, SizeOf(GCPRes), 0);
- GetMem(GCPRes.lpGlyphs, SizeOf(Cardinal));
- try
- GCPRes.lStructSize := SizeOf(GCPRes);
- GCPRes.lpGlyphs^ := 0;
- GCPRes.nGlyphs := 1;
-
- if GetCharacterPlacementW(DC, @CharCode, 1, GCP_MAXEXTENT, @GCPRes, 0) <> GDI_ERROR then begin
- if (GCPRes.nGlyphs = 1) and (GCPRes.lpGlyphs <> nil) then begin
- Result := GCPRes.lpGlyphs^;
-
- // ReadRawData := False;
- end;
- end;
- finally
- FreeMem(GCPRes.lpGlyphs);
- end;
- end;
-
- // windows 9x workaround
- // ReadRawData := True;
-
- // if ReadRawData then begin
- // if GetTTUnicodeCharCount(DC) > 0 then
- // Result := GetTTUnicodeGlyphIndex(DC, Ord(CharCode));
- // end;
- finally
- DeleteDC(DC);
- end;
- end;
-
-
- function TtsFontCreatorGDIFontFace.GetGlyphMetrics(CharCode: WideChar; var GlyphOriginX, GlyphOriginY, GlyphWidth, GlyphHeight, Advance: Integer): Boolean;
- var
- DC: HDC;
- Metric: TGlyphMetrics;
- Size: Cardinal;
- GlyphIndex: Integer;
- begin
- Result := False;
-
- // Set values to 0
- GlyphOriginX := 0;
- GlyphOriginY := 0;
- GlyphWidth := 0;
- GlyphHeight := 0;
- Advance := 0;
-
- // Translate Glyphindex
- GlyphIndex := GetGlyphIndex(CharCode);
-
- DC := CreateCompatibleDC(0);
- try
- SelectObject(DC, fFontHandle);
-
- // get value of resulting bitmaps
- case AntiAliasing of
- tsAANone: begin
- // if GlyphIndex <> 0 then
- Size := GetGlyphOutlineA(DC, GlyphIndex, GGO_BITMAP or GGO_GLYPH_INDEX, @Metric, 0, nil, @fMat2);
- // else
- // Size := GetGlyphOutlineA(DC, Ord(fDefaultChar), GGO_BITMAP, Metric, 0, nil, fMat2);
- end;
- tsAANormal: begin
- // if GlyphIndex <> 0 then
- Size := GetGlyphOutlineA(DC, GlyphIndex, GGO_GRAY8_BITMAP or GGO_GLYPH_INDEX, @Metric, 0, nil, @fMat2);
- // else
- // Size := GetGlyphOutlineA(DC, Ord(fDefaultChar), GGO_GRAY8_BITMAP, Metric, 0, nil, fMat2);
- end;
- else
- Size := 0;
- end;
-
- // dosn't work so get metric value
- if (Size = GDI_ERROR) or (Size = 0) then begin
- // if GlyphIndex <> 0 then
- Size := GetGlyphOutlineA(DC, GlyphIndex, GGO_METRICS or GGO_GLYPH_INDEX, @Metric, 0, nil, @fMat2);
- // else
- // Size := GetGlyphOutlineA(DC, Ord(fDefaultChar), GGO_METRICS, Metric, 0, nil, fMat2);
- end;
-
- // we have values?
- if (Size <> GDI_ERROR) and (Size > 0) then begin
- GlyphOriginX := Round(Metric.gmptGlyphOrigin.X / fMat2.eM11.value);
- GlyphOriginY := Metric.gmptGlyphOrigin.Y;
- GlyphWidth := Round(Metric.gmBlackBoxX / fMat2.eM11.value);
- GlyphHeight := Metric.gmBlackBoxY;
-
- Advance := Round(Metric.gmCellIncX / fMat2.eM11.value);
-
- Result := True;
- end;
- finally
- DeleteDC(DC)
- end;
- end;
-
-
- { TtsFontCreatorGDIFile }
-
- constructor TtsFontCreatorGDIFile.Create(Renderer: TtsRenderer; const Filename: AnsiString;
- Size: Integer; Style: TtsFontStyles; Format: TtsFormat; AntiAliasing: TtsAntiAliasing);
- var
- FaceName: AnsiString;
- begin
- // filename
- fFileName := StrNew(pAnsiChar(Filename));
-
- fFontRegistred := false;
- FaceName := '';
-
- if GetFaceName(fFilename, FaceName) then
- fFontRegistred := RegisterFont(fFilename, False);
-
- // inherited
- inherited Create(Renderer, FaceName, Size, Style, Format, AntiAliasing);
- end;
-
-
- destructor TtsFontCreatorGDIFile.Destroy;
- begin
- inherited;
-
- // unregister font
- if fFontRegistred then
- UnRegisterFont(fFilename, False);
-
- StrDispose(fFileName);
- end;
-
-
- function TtsFontCreatorGDIFile.GetFaceName(Filename: PAnsiChar; var Face: AnsiString): boolean;
- var
- Lang: AnsiString;
- begin
- SetLength(Lang, 4);
- GetLocaleInfoA(LOCALE_USER_DEFAULT, LOCALE_ILANGUAGE, @Lang[1], 4);
-
- Face := GetTTFontFullNameFromFile(Filename, StrToInt('$' + String(Lang)));
-
- Result := Face <> '';
- end;
-
-
- function TtsFontCreatorGDIFile.RegisterFont(Filename: pAnsiChar; RegisterPublic: Boolean): boolean;
- var
- Flags: Cardinal;
- begin
- Result := False;
-
- // Flags
- if not RegisterPublic then
- Flags := FR_PRIVATE or FR_NOT_ENUM
- else
- Flags := 0;
-
- // AddFontResource
- if Addr(AddFontResourceExA) <> nil then
- Result := AddFontResourceExA(FileName, Flags, nil) > 0
- else
-
- if Addr(AddFontResourceA) <> nil then
- Result := AddFontResourceA(FileName) > 0;
- end;
-
-
- function TtsFontCreatorGDIFile.UnRegisterFont(Filename: pAnsiChar; RegisterPublic: Boolean): boolean;
- var
- Flags: Cardinal;
- begin
- Result := False;
-
- // Flags
- if not RegisterPublic then
- Flags := FR_PRIVATE or FR_NOT_ENUM
- else
- Flags := 0;
-
- // RemoveFontResource
- if Addr(RemoveFontResourceExA) <> nil then
- Result := RemoveFontResourceExA(FileName, Flags, nil)
- else
-
- if Addr(RemoveFontResourceA) <> nil then
- Result := RemoveFontResourceA(FileName);
- end;
-
- { TtsFontCreatorGDIFile }
-
- constructor TtsFontCreatorGDIStream.Create(Renderer: TtsRenderer; const Source: TStream;
- Size: Integer; Style: TtsFontStyles; Format: TtsFormat; AntiAliasing: TtsAntiAliasing);
- var
- FaceName: AnsiString;
- begin
- fFontRegistred := false;
- FaceName := '';
-
- if GetFaceName(Source, FaceName) then
- fFontRegistred := RegisterFont(Source);
-
- // inherited
- inherited Create(Renderer, FaceName, Size, Style, Format, AntiAliasing);
- end;
-
-
- destructor TtsFontCreatorGDIStream.Destroy;
- begin
- inherited;
-
- // unregister font
- if fFontRegistred then
- UnRegisterFont();
- end;
-
-
- function TtsFontCreatorGDIStream.GetFaceName(Stream: TStream; var Face: AnsiString): boolean;
- var
- Lang: AnsiString;
- begin
- SetLength(Lang, 4);
- GetLocaleInfoA(LOCALE_USER_DEFAULT, LOCALE_ILANGUAGE, @Lang[1], 4);
-
- Face := GetTTFontFullNameFromStream(Stream, StrToInt('$' + String(Lang)));
-
- Result := Face <> '';
- end;
-
-
- function TtsFontCreatorGDIStream.RegisterFont(Data: TStream): boolean;
- var
- ms: TMemoryStream;
- cnt: DWORD;
- begin
- Result := False;
- fHandle := 0;
-
- ms:= TMemoryStream.Create;
- try
- ms.CopyFrom(Data, 0);
- if Addr(AddFontMemResourceEx)<>nil then
- fHandle:= AddFontMemResourceEx(ms.Memory, ms.Size, nil, @cnt);
- Result:= fHandle > 0;
- finally
- ms.Free;
- end;
- end;
-
-
- function TtsFontCreatorGDIStream.UnRegisterFont(): boolean;
- begin
- Result := RemoveFontMemResourceEx(fHandle);
- end;
-
- { TtsRenderer }
-
- procedure TtsRenderer.BeginBlock(Left, Top, Width, Height: Integer; Flags: tsBitmask);
- begin
- fisBlock := True;
-
- fBlockLeft := Left;
- fBlockTop := Top;
- fBlockWidth := Width;
- fBlockHeight := Height;
- fFlags := Flags;
-
- fWordWrap := fFlags and TS_BLOCKFLAG_WORD_WRAP = TS_BLOCKFLAG_WORD_WRAP;
- // fSingleLine := fFlags and TS_BLOCKFLAG_SINGLE_LINE = TS_BLOCKFLAG_SINGLE_LINE;
-
- fLineTop := Top + tsGetParameteri(TS_BLOCK_OFFSET_Y);
- fTextOffsetY := 0;
- fTextOffsetX := 0;
-
- with fLinesTemp do begin
- New(Lines);
-
- with Lines^ do begin
- NextLine := nil;
- LineItemFirst := nil;
- LineItemLast := nil;
- LineLength := 0;
- LineAutoBreak := False;
- end;
- Empty := True;
- end;
-
- fLinesFirst := nil;
- fLinesLast := nil;
-
- // if font is active add to list
- if fActiveFont <> nil then
- FontActivate(fActiveFontID);
- end;
-
-
- function TtsRenderer.CalculateLinesHeight(pLinesItem: PtsLinesItem): Integer;
- var
- pLine: PtsLineItem;
- Metric: TtsTextMetric;
- begin
- Result := 0;
-
- while pLinesItem <> nil do begin
- pLine := pLinesItem^.LineItemFirst;
-
- GetLineMetric(pLine, Metric);
- Result := Result + Metric.LineSkip_with_LineSpace;
-
- pLinesItem := pLinesItem^.NextLine;
- end;
-
- // remove last linespace from the lines
- Result := Result - (Metric.LineSkip_with_LineSpace - Metric.LineSkip);
- end;
-
-
- procedure TtsRenderer.CalculateWordLength(Font: TtsFont; pWord: PtsLineItem);
- var
- pTempWord: PWideChar;
- Char: TtsChar;
- CharSpacing: tsInt;
- begin
- if pWord^.ItemType in [TS_BLOCK_WORD, TS_BLOCK_SPACE] then begin
- CharSpacing := fLastActiveFont.CharSpacing;
-
- pTempWord := pWord^.Word;
- pWord^.WordLength := 0;
-
- while pTempWord^ <> #0 do begin
- // normal char
- if Font.Validate(pTempWord^) then
- Char := Font.GetChar(pTempWord^)
- else
-
- // default char
- if Font.Validate(Font.DefaultChar) then
- Char := Font.GetChar(Font.DefaultChar)
- else
- Char := nil;
-
- if Char <> nil then begin
- pWord^.WordLength := pWord^.WordLength + Char.Advance + CharSpacing;
- end;
-
- Inc(pTempWord);
- end;
- end;
- end;
-
-
- procedure TtsRenderer.Color(Red, Green, Blue, Alpha: Single);
- var
- LineItem: PtsLineItem;
- begin
- if isBlock then begin
- New(LineItem);
-
- LineItem^.NextItem := nil;
- LineItem^.PrevItem := nil;
- LineItem^.ItemType := TS_BLOCK_COLOR;
- LineItem^.Red := Red;
- LineItem^.Green := Green;
- LineItem^.Blue := Blue;
- LineItem^.Alpha := Alpha;
-
- PushLineItem(LineItem);
- end else
-
- begin
- DrawSetColor(Red, Green, Blue, Alpha);
- end;
- end;
-
-
- constructor TtsRenderer.Create(Context: TtsContext);
- begin
- inherited Create;
-
- fContext := Context;
-
- fSaveImages := True;
- end;
-
-
- destructor TtsRenderer.Destroy;
- begin
- if isBlock then
- EndBlock;
-
- inherited;
- end;
-
-
- procedure TtsRenderer.DrawLine(pLine: PtsLineItem; LineLength: Integer; LineBreak: Boolean);
- var
- pText: PWideChar;
- Char: TtsChar;
-
- Metric: TtsTextMetric;
-
- TempLeft, Temp: Integer;
- DrawLeft, SpaceTemp: Single;
- DrawAscent, LineSkip: Integer;
-
- DrawText: Boolean;
-
- BlockSpaceCount: Integer;
- BlockSpaceWidth: Single;
-
-
- function CountSpaces(pLine: PtsLineItem): Integer;
- var
- pText: PWideChar;
- begin
- Result := 0;
-
- while pLine <> nil do begin
- case pLine^.ItemType of
- TS_BLOCK_SPACE: begin
- pText := pLine^.Word;
-
- // Enumerate Text
- while pText^ <> #0 do begin
- Inc(Result);
- Inc(pText);
- end;
- end;
- end;
-
- pLine := pLine^.NextItem;
- end;
- end;
-
-
- begin
- if fFlags and TS_BLOCKFLAG_CALC_SIZE > 0 then
- Exit;
-
- BlockSpaceWidth := 0;
- DrawLeft := 0;
- TempLeft := 0;
-
- GetLineMetric(pLine, Metric);
-
- // set drawposition to new baseline
- DrawAscent := fLineTop + fTextOffsetY + Metric.Ascent;
-
- // increment linetop with height of line
- LineSkip := Metric.LineSkip;
- fLineTop := fLineTop + LineSkip;
-
- // clipping
- DrawText := True;
- if fisBlock then begin
- if not (fFlags and TS_BLOCKFLAG_NO_CLIP = TS_BLOCKFLAG_NO_CLIP) then begin
- case tsGetParameteri(TS_CLIP) of
- TS_CLIP_COMPLETE: begin
- if (fLineTop + fTextOffsetY < fBlockTop) or
- ((fLineTop + fTextOffsetY - LineSkip) > (fBlockTop + fBlockHeight)) then
- DrawText := False;
- end;
- TS_CLIP_BORDER: begin
- if ((fLineTop + fTextOffsetY - LineSkip) < fBlockTop) or
- (fLineTop + fTextOffsetY > (fBlockTop + fBlockHeight)) then
- DrawText := False;
- end;
- end;
- end;
- end;
-
- // TextBlock text alignment
- if isBlock then begin
- case tsGetParameteri(TS_ALIGN) of
- TS_ALIGN_CENTER:
- begin
- TempLeft := (fBlockWidth div 2) - (LineLength div 2);
- end;
- TS_ALIGN_RIGHT:
- begin
- TempLeft := fBlockWidth - LineLength;
- end;
- TS_ALIGN_BLOCK: begin
- if LineBreak then begin
- BlockSpaceCount := CountSpaces(pLine);
-
- if BlockSpaceCount > 0 then
- BlockSpaceWidth := (fBlockWidth - LineLength) / BlockSpaceCount;
- end;
- end;
- end;
-
- DrawSetPosition(fBlockLeft + TempLeft, DrawAscent);
- end else
-
- // Normal text alignment
- begin
- case tsGetParameteri(TS_ALIGN) of
- TS_ALIGN_CENTER:
- begin
- TempLeft := - (LineLength div 2);
- end;
- TS_ALIGN_RIGHT:
- begin
- TempLeft := - LineLength;
- end;
- end;
-
- DrawSetPositionRelative(TempLeft, 0);
- end;
-
- DrawSetPositionRelative(tsGetParameteri(TS_BLOCK_OFFSET_X), 0);
-
- // Enumerate LineItems
- while pLine <> nil do begin
- case pLine^.ItemType of
- TS_BLOCK_FONT: begin
- fActiveFont := pLine^.Font;
- fActiveFontID := pLine^.FontID;
- end;
-
- TS_BLOCK_COLOR: begin
- DrawSetColor(pLine^.Red, pLine^.Green, pLine^.Blue, pLine^.Alpha);
- end;
-
- TS_BLOCK_WORD: begin
- if DrawText then begin
- if fActiveFont <> nil then begin
- pText := pLine^.Word;
-
- // Enumerate Text
- while pText^ <> #0 do begin
- // normal char
- if fActiveFont.Validate(pText^) then
- Char := fActiveFont.GetChar(pText^)
- else
-
- // default char
- if fActiveFont.Validate(fActiveFont.DefaultChar) then
- Char := fActiveFont.GetChar(fActiveFont.DefaultChar)
- else
- Char := nil;
-
- if Char <> nil then begin
- DrawSetPositionRelative(Char.GlyphOriginX, -fActiveFont.fBaselineOffset);
- DrawChar(fActiveFont, Char);
- DrawSetPositionRelative(Char.Advance - Char.GlyphOriginX + fActiveFont.CharSpacing, fActiveFont.fBaselineOffset);
- end;
-
- Inc(pText);
- end;
- end;
- end;
- end;
-
- TS_BLOCK_SPACE: begin
- if DrawText then begin
- if fActiveFont <> nil then begin
- pText := pLine^.Word;
-
- // Enumerate Text
- while pText^ <> #0 do begin
- // normal char
- if fActiveFont.Validate(pText^) then
- Char := fActiveFont.GetChar(pText^)
- else
-
- // default char
- if fActiveFont.Validate(fActiveFont.DefaultChar) then
- Char := fActiveFont.GetChar(fActiveFont.DefaultChar)
- else
- Char := nil;
-
- if Char <> nil then begin
- // We have lines so we must repeat the "empty" space
- if (tsStyleUnderline in fActiveFont.Style) or (tsStyleStrikeout in fActiveFont.Style) then begin
- // width we need to draw
- SpaceTemp := Char.Advance + fActiveFont.CharSpacing + BlockSpaceWidth;
- // set the position to the normal end. Following we decrease
- // these value by the width of the drawn chars. So we get the
- // difference of the last drawn space.
- DrawLeft := DrawLeft + Char.Advance + fActiveFont.CharSpacing + BlockSpaceWidth;
-
- Temp := Char.Advance - Char.GlyphOriginX + fActiveFont.CharSpacing;
-
- while SpaceTemp > 0 do begin
- // draw the char
- DrawSetPositionRelative(Char.GlyphOriginX, 0);
- DrawChar(fActiveFont, Char);
- // set the position inside the drawer
- DrawSetPositionRelative(Temp, 0);
-
- // decrease need to draw width
- SpaceTemp := SpaceTemp - Temp;
- // decrease the drawwidth with the width of the char.
- DrawLeft := DrawLeft - Temp;
- end;
- end else
- // no lines so only set the position
- DrawLeft := DrawLeft + Char.Advance + fActiveFont.CharSpacing + BlockSpaceWidth;
- end;
-
- Inc(pText);
- end;
-
- DrawSetPositionRelative(Round(DrawLeft), 0);
- DrawLeft := DrawLeft - Round(DrawLeft);
- end;
- end;
- end;
-
- TS_BLOCK_LINEBREAK: begin
-
- end;
- // TS_BLOCK_TAB: begin
- // case tsGetParameteri(TS_TAB) of
- // TS_TAB_FIXED:
- // begin
- // Temp := tsGetParameteri(TS_TAB_FIXED_WIDTH);
- //
- //// if (DrawLeft - fBlockLeft) mod Temp > 0 then
- // DrawLeft := (Round(DrawLeft) mod Temp) + Temp;
- // end;
- // TS_TAB_ABSOLUTE:
- // begin
- //
- // end;
- // end;
- // end;
- end;
-
- pLine := pLine^.NextItem;
- end;
- end;
-
-
- procedure TtsRenderer.DrawLines(pLinesItem: PtsLinesItem);
- begin
- if fFlags and TS_BLOCKFLAG_CALC_SIZE = 0 then begin
- while pLinesItem <> nil do begin
- DrawLine(pLinesItem^.LineItemFirst, pLinesItem^.LineLength, pLinesItem^.LineAutoBreak);
-
- pLinesItem := pLinesItem^.NextLine;
- end;
- end;
- end;
-
-
- procedure TtsRenderer.EndBlock;
- var
- LinesHeight: Integer;
- VerticalAlign: tsEnum;
- begin
- // if temp line exist then push them
- with fLinesTemp do begin
- if Lines <> nil then
- if Lines^.LineItemFirst <> nil then
- PushTempLines;
-
- FreeLines(Lines);
- end;
-
- // if vertical align isn't top
- VerticalAlign := tsGetParameteri(TS_VALIGN);
- if (VerticalAlign = TS_VALIGN_CENTER) or
- (VerticalAlign = TS_VALIGN_BOTTOM) then begin
- // calculating height
- LinesHeight := CalculateLinesHeight(fLinesFirst);
-
- // setting offset
- case VerticalAlign of
- TS_VALIGN_CENTER:
- fTextOffsetY := fTextOffsetY + (fBlockHeight div 2 - LinesHeight div 2);
- TS_VALIGN_BOTTOM:
- fTextOffsetY := fTextOffsetY + (fBlockHeight - LinesHeight);
- end;
-
- // drawing lines
- DrawLines(fLinesFirst);
- end;
-
- // Free all lines
- FreeLines(fLinesFirst);
- fLinesLast := nil;
-
- fisBlock := False;
- end;
-
-
- procedure TtsRenderer.FontActivate(FontID: Cardinal);
- var
- pLine: PtsLineItem;
- begin
- if FontID <> 0 then begin
- fLastActiveFont := fContext.FontGet(FontID);
- fLastActiveFontID := FontID;
- end else
- fLastActiveFont := nil;
-
- // if in block then add blockitem
- if isBlock then begin
- New(pLine);
-
- pLine^.NextItem := nil;
- pLine^.PrevItem := nil;
- pLine^.ItemType := TS_BLOCK_FONT;
- pLine^.FontID := FontID;
- pLine^.Font := fLastActiveFont;
-
- if pLine^.Font <> nil then
- PushLineItem(pLine)
- else
- Dispose(pLine);
- end else
-
- // activate font
- begin
- fActiveFontID := FontID;
- fActiveFont := fLastActiveFont;
- end;
- end;
-
-
- procedure TtsRenderer.FreeLines(var pLinesItem: PtsLinesItem);
- var
- pTemp: PtsLinesItem;
- begin
-
- while pLinesItem <> nil do begin
- pTemp := pLinesItem;
-
- FreeLineItems(pLinesItem^.LineItemFirst);
- pLinesItem^.LineItemLast := pLinesItem^.LineItemFirst;
-
- pLinesItem := pLinesItem^.NextLine;
- Dispose(pTemp);
- end;
- end;
-
-
- procedure TtsRenderer.FreeLineItems(var pLine: PtsLineItem);
- var
- pTemp: PtsLineItem;
- begin
- while pLine <> nil do begin
- pTemp := pLine;
-
- case pLine^.ItemType of
- TS_BLOCK_WORD, TS_BLOCK_SPACE:
- tsStrDispose(pLine^.Word);
- end;
-
- pLine := pLine^.NextItem;
- Dispose(pTemp);
- end;
- end;
-
-
- function TtsRenderer.GetActiveFont: TtsFont;
- begin
- if fisBlock then
- Result := fLastActiveFont
- else
- Result := fActiveFont;
- end;
-
-
- function TtsRenderer.GetActiveFontID: Cardinal;
- begin
- if fisBlock then
- Result := fLastActiveFontID
- else
- Result := fActiveFontID;
- end;
-
-
- procedure TtsRenderer.GetLineMetric(pLine: PtsLineItem; var Metric: TtsTextMetric);
- var
- Font: TtsFont;
- Temp: TtsTextMetric;
- begin
- // Defaults
- Metric.Ascent := 0;
- Metric.Descent := 0;
- Metric.LineSkip := 0;
- Metric.LineSkip_with_LineSpace := 0;
-
- // calculating lines
- Font := fActiveFont;
-
- while pLine <> nil do begin
- case pLine^.ItemType of
- TS_BLOCK_FONT: begin
- Font := pLine^.Font;
- end;
-
- TS_BLOCK_WORD, TS_BLOCK_SPACE, TS_BLOCK_LINEBREAK: begin
- if Font <> nil then begin
- Font.GetTextMetric(Temp);
-
- if Temp.Ascent > Metric.Ascent then
- Metric.Ascent := Temp.Ascent;
-
- if Temp.Descent > Metric.Descent then
- Metric.Descent := Temp.Descent;
-
- if Temp.LineSkip > Metric.LineSkip then
- Metric.LineSkip := Temp.LineSkip;
-
- if Temp.LineSkip_with_LineSpace > Metric.LineSkip_with_LineSpace then
- Metric.LineSkip_with_LineSpace := Temp.LineSkip_with_LineSpace;
-
- // font was handled so we can remove the font to skip the following words.
- // because the value only will change if we change the font.
- Font := nil;
- end;
- end;
- end;
-
- pLine := pLine^.NextItem;
- end;
- end;
-
-
- procedure TtsRenderer.PushTempLines;
- begin
- TrimSpaces(fLinesTemp.Lines);
-
- fLinesTemp.Lines^.LineLength := fLinesTemp.Lines^.LineLength - fLastActiveFont.CharSpacing;
-
- // add after last item
- if fLinesFirst <> nil then begin
- fLinesLast^.NextLine := fLinesTemp.Lines;
- fLinesLast := fLinesTemp.Lines;
- end;
-
- // set first item
- if fLinesFirst = nil then begin
- fLinesFirst := fLinesTemp.Lines;
- fLinesLast := fLinesTemp.Lines;
- end;
-
- // if vertical align is top then draw direktlly
- if tsGetParameteri(TS_VALIGN) = TS_VALIGN_TOP then
- DrawLine(fLinesLast^.LineItemFirst, fLinesLast^.LineLength, fLinesLast^.LineAutoBreak);
-
- // create new item
- with fLinesTemp do begin
- New(Lines);
- with Lines^ do begin
- NextLine := nil;
- LineItemFirst := nil;
- LineItemLast := nil;
- LineLength := 0;
- LineAutoBreak := False;
- end;
-
- Empty := True;
- end;
- end;
-
-
- procedure TtsRenderer.PushLineItem(pLine: PtsLineItem);
- begin
- with fLinesTemp do begin
- if Lines <> nil then begin
- // add after last item
- if Lines^.LineItemLast <> nil then begin
- pLine^.PrevItem := Lines^.LineItemLast;
- Lines^.LineItemLast^.NextItem := pLine;
- Lines^.LineItemLast := pLine;
- end;
-
- // set first item
- if Lines^.LineItemFirst = nil then begin
- Lines^.LineItemFirst := pLine;
- Lines^.LineItemLast := pLine;
- end;
- end;
- end;
- end;
-
-
- procedure TtsRenderer.SplitIntoLines(pItemList: PtsLineItem);
- var
- pExtractItem: PtsLineItem;
-
-
- procedure PushWord(pItem: PtsLineItem);
- begin
- if pItem <> nil then begin
- with fLinesTemp.Lines^ do begin
- // add after last item
- if LineItemLast <> nil then begin
- LineItemLast^.NextItem := pItem;
- pItem^.PrevItem := LineItemLast;
- LineItemLast := pItem;
- end;
-
- // set first item
- if LineItemFirst = nil then begin
- LineItemFirst := pItem;
- LineItemLast := pItem;
- end;
- end;
- end;
- end;
-
-
- begin
- while pItemList <> nil do begin
- // extract word from list
- pExtractItem := pItemList;
- pItemList := pItemList^.NextItem;
- pExtractItem^.NextItem := nil;
- pExtractItem^.PrevItem := nil;
-
- case pExtractItem^.ItemType of
- TS_BLOCK_WORD, TS_BLOCK_SPACE: begin
- // calculate size
- CalculateWordLength(fLastActiveFont, pExtractItem);
-
- if fWordWrap {and not fSingleLine} then begin
- // if line + word is larger than draw width
- if fLinesTemp.Lines^.LineLength + pExtractItem^.WordLength > fBlockWidth then begin
- fLinesTemp.Lines^.LineAutoBreak := True;
-
- // if line is empty
- if fLinesTemp.Lines^.LineLength = 0 then begin
- // ### Split word into multiple lines
- PushWord(pExtractItem);
-
- pExtractItem := nil;
- end; // else
-
- PushTempLines;
- end;
- end;
-
- // add extracted word to intern small list
- if pExtractItem <> nil then begin
- // add word
- PushWord(pExtractItem);
-
- // add Length
- fLinesTemp.Lines^.LineLength := fLinesTemp.Lines^.LineLength + pExtractItem^.WordLength;
- end;
- end;
-
- TS_BLOCK_LINEBREAK: begin
- // if not fSingleLine then begin
- PushWord(pExtractItem);
-
- PushTempLines;
- // end;
- end;
-
- TS_BLOCK_TAB: begin
- PushWord(pExtractItem);
- end;
- end;
- end;
- end;
-
-
- function TtsRenderer.SplitText(pText: PWideChar): PtsLineItem;
- var
- pLastItem: PtsLineItem;
-
- State: Integer;
-
- WordLength: Integer;
- pWordBegin: PWideChar;
-
-
- procedure ExtractWord;
- var
- pWord: PWideChar;
- pWordItem: PtsLineItem;
-
-
- procedure AddItem;
- begin
- // add item to list
- if Result <> nil then begin
- pLastItem^.NextItem := pWordItem;
- pWordItem^.PrevItem := pLastItem;
- pLastItem := pWordItem;
- end;
-
- if Result = nil then begin
- Result := pWordItem;
- pLastItem := pWordItem;
- end;
- end;
-
-
- begin
- if State <> 0 then begin
- // Create listitem
- New(pWordItem);
- pWordItem^.NextItem := nil;
- pWordItem^.PrevItem := nil;
- pWordItem^.ItemType := State;
-
- // only if space or text
- case State of
- TS_BLOCK_WORD, TS_BLOCK_SPACE: begin
- pWordItem^.Word := tsStrAlloc(WordLength);
-
- // copy chars
- WordLength := 0;
- pWord := pWordItem^.Word;
-
- while pWordBegin <> pText do begin
- pWord^ := pWordBegin^;
-
- Inc(pWord);
- Inc(pWordBegin);
- end;
-
- AddItem;
- end;
-
- TS_BLOCK_LINEBREAK: begin
- if pWordBegin <> pText then begin
- // Skip Linebreak
- while pWordBegin <> pText do
- Inc(pWordBegin);
-
- // if not fSingleLine then begin
- AddItem;
- // end else
-
- // begin
- // Dispose(pWordItem);
- // pWordItem := nil;
- // end;
-
- end else
-
- begin
- Dispose(pWordItem);
- pWordItem := nil;
- end;
- end;
-
- TS_BLOCK_TAB: begin
- AddItem;
- end;
- end;
- end;
- end;
-
-
- begin
- Result := nil;
- pLastItem := nil;
- WordLength := 0;
- State := 0;
-
- pWordBegin := pText;
-
- // look for word breaks
- while pText^ <> #0 do begin
- case pText^ of
- // Tabulator
- #$0009: begin
- ExtractWord;
- Inc(pWordBegin);
- State := TS_BLOCK_TAB;
- end;
-
- // line breaks
- #$000D, #$000A: begin
- if State <> TS_BLOCK_LINEBREAK then
- ExtractWord;
-
- if pWordBegin <> pText then begin
- ExtractWord;
- Inc(pWordBegin);
- end;
-
- State := TS_BLOCK_LINEBREAK;
- end;
-
- // Spaces
- #$0020: begin
- if State <> TS_BLOCK_SPACE then begin
- ExtractWord;
-
- State := TS_BLOCK_SPACE;
- end;
- end;
- else
- if State <> TS_BLOCK_WORD then begin
- ExtractWord;
-
- State := TS_BLOCK_WORD;
- end;
- end;
-
- Inc(pText);
- Inc(WordLength);
- end;
-
- // copy last word
- if pWordBegin <> pText then
- ExtractWord;
- end;
-
-
- function TtsRenderer.TextGetDrawHeight: Integer;
- var
- pLinesItem: PtsLinesItem;
- Metric: TtsTextMetric;
- begin
- Result := 0;
-
- // all lines
- pLinesItem := fLinesFirst;
-
- while pLinesItem <> nil do begin
- GetLineMetric(pLinesItem^.LineItemFirst, Metric);
-
- Result := Result + Metric.LineSkip_with_LineSpace;
-
- pLinesItem := pLinesItem^.NextLine;
- end;
-
- // last if we had an templine
- if fLinesTemp.Lines <> nil then begin
- GetLineMetric(fLinesTemp.Lines^.LineItemFirst, Metric);
-
- Result := Result + Metric.LineSkip_with_LineSpace;
- end;
- end;
-
-
- function TtsRenderer.TextGetDrawWidth: Integer;
- var
- pLinesItem: PtsLinesItem;
- Temp: Integer;
- {%H-}Font: TtsFont;
-
-
- function IntGetLineWidth(pLine: PtsLineItem): Integer;
- begin
- Result := 0;
-
- while pLine <> nil do begin
- case pLine^.ItemType of
- TS_BLOCK_FONT: begin
- Font := pLine^.Font;
- end;
-
- TS_BLOCK_WORD, TS_BLOCK_SPACE: begin
- Result := Result + pLine^.WordLength;
- end;
- end;
-
- pLine := pLine^.NextItem;
- end;
- end;
-
- begin
- Result := 0;
-
- // all lines
- Font := fActiveFont;
-
- pLinesItem := fLinesFirst;
- while pLinesItem <> nil do begin
- Temp := IntGetLineWidth(pLinesItem^.LineItemFirst);
- if Temp > Result then
- Result := Temp;
-
- pLinesItem := pLinesItem^.NextLine;
- end;
-
- // last if we had an templine
- if fLinesTemp.Lines <> nil then begin
- Temp := IntGetLineWidth(fLinesTemp.Lines^.LineItemFirst);
-
- if Temp > Result then
- Result := Temp;
- end;
- end;
-
-
- function TtsRenderer.TextGetWidth(pText: pWideChar): Integer;
- var
- pItemList: PtsLineItem;
- pTempItem: PtsLineItem;
- begin
- Result := 0;
-
- pItemList := SplitText(pText);
- pTempItem := pItemList;
-
- while pTempItem <> nil do begin
- CalculateWordLength(fActiveFont, pTempItem);
- Result := Result + pTempItem^.WordLength;
-
- pTempItem := pTempItem^.NextItem;
- end;
-
- // Free Items
- FreeLineItems(pItemList);
- end;
-
-
- procedure TtsRenderer.TextOut(pText: pWideChar);
- var
- pItemList: PtsLineItem;
-
- pTempItem: PtsLineItem;
- TempLength: Integer;
- begin
- pItemList := SplitText(pText);
-
- if isBlock then begin
- SplitIntoLines(pItemList);
- end else
-
- begin
- DrawSetPosition(0, 0);
-
- // Calculate Word length
- TempLength := 0;
- pTempItem := pItemList;
-
- while pTempItem <> nil do begin
- CalculateWordLength(fActiveFont, pTempItem);
- TempLength := TempLength + pTempItem^.WordLength;
-
- pTempItem := pTempItem^.NextItem;
- end;
-
- // remove last Char Spacing
- TempLength := TempLength - fActiveFont.CharSpacing;
-
- // if single line is top then set the Position to the baseline
- if tsGetParameteri(TS_SINGLE_LINE) = TS_SINGLE_LINE_TOP then
- DrawSetPositionRelative(0, fActiveFont.Ascent);
-
- // draw
- DrawLine(pItemList, TempLength, False);
-
- // Free Items
- FreeLineItems(pItemList);
- end;
- end;
-
-
-
- procedure TtsRenderer.TrimSpaces(pLinesItem: PtsLinesItem);
- var
- pTempLoopItem, pTempItem: PtsLineItem;
- begin
- if pLinesItem <> nil then begin
- // delete all spaces at beginning
- while pLinesItem^.LineItemFirst <> nil do begin
- if pLinesItem^.LineItemFirst^.ItemType <> TS_BLOCK_SPACE then
- Break;
-
- // save first
- pTempItem := pLinesItem^.LineItemFirst;
-
- // remove first item fromlist
- pLinesItem^.LineItemFirst := pLinesItem^.LineItemFirst^.NextItem;
- if pLinesItem^.LineItemFirst = nil then
- pLinesItem^.LineItemLast := nil
- else
- pLinesItem^.LineItemFirst^.PrevItem := nil;
-
- pLinesItem^.LineLength := pLinesItem^.LineLength - pTempItem^.WordLength;
-
- // dispose item
- pTempItem^.NextItem := nil;
- FreeLineItems(pTempItem);
- end;
-
- // delete all spaces at the end
- while pLinesItem^.LineItemLast <> nil do begin
- if pLinesItem^.LineItemLast^.ItemType <> TS_BLOCK_SPACE then
- break;
-
- // save last item
- pTempItem := pLinesItem^.LineItemLast;
-
- // remove last item from list
- pLinesItem^.LineItemLast := pLinesItem^.LineItemLast^.PrevItem;
- if pLinesItem^.LineItemLast = nil then
- pLinesItem^.LineItemFirst := nil
- else
- pLinesItem^.LineItemLast^.NextItem := nil;
-
- pLinesItem^.LineLength := pLinesItem^.LineLength - pTempItem^.WordLength;
-
- // dispose item
- FreeLineItems(pTempItem);
- end;
-
-
- // delete all spaces until some text comes
- pTempLoopItem := pLinesItem^.LineItemFirst;
- while pTempLoopItem <> nil do begin
- // exit if we have an word
- if pTempLoopItem^.ItemType = TS_BLOCK_WORD then
- Break;
-
- pTempItem := pTempLoopItem;
-
- pTempLoopItem := pTempLoopItem^.NextItem;
-
- if pTempItem^.ItemType = TS_BLOCK_SPACE then begin
- pLinesItem^.LineLength := pLinesItem^.LineLength - pTempItem^.WordLength;
-
- // set new next/prev
- if pTempItem^.NextItem <> nil then
- pTempItem^.NextItem^.PrevItem := pTempItem^.PrevItem;
-
- if pTempItem^.PrevItem <> nil then
- pTempItem^.PrevItem^.NextItem := pTempItem^.NextItem;
-
- // remove item
- pTempItem^.PrevItem := nil;
- pTempItem^.NextItem := nil;
-
- FreeLineItems(pTempItem);
- end;
- end;
-
- // delete all spaces until some text comes
- pTempLoopItem := pLinesItem^.LineItemLast;
- while pTempLoopItem <> nil do begin
- // exit if we have an word
- if pTempLoopItem^.ItemType = TS_BLOCK_WORD then
- Break;
-
- pTempItem := pTempLoopItem;
-
- pTempLoopItem := pTempLoopItem^.PrevItem;
-
- if pTempItem^.ItemType = TS_BLOCK_SPACE then begin
- pLinesItem^.LineLength := pLinesItem^.LineLength - pTempItem^.WordLength;
-
- // set new next/prev
- if pTempItem^.PrevItem <> nil then
- pTempItem^.PrevItem^.NextItem := pTempItem^.NextItem;
-
- if pTempItem^.NextItem <> nil then
- pTempItem^.NextItem^.PrevItem := pTempItem^.PrevItem;
-
- // remove item
- pTempItem^.PrevItem := nil;
- pTempItem^.NextItem := nil;
-
- FreeLineItems(pTempItem);
- end;
- end;
- end;
- end;
-
-
- procedure TtsRenderer.CharOut(CharCode: WideChar);
- var
- tsChar: TtsChar;
- begin
- tsChar := fActiveFont.GetChar(CharCode);
-
- if tsChar <> nil then
- DrawChar(fActiveFont, tsChar);
- end;
-
-
- { TtsRendererNULL }
-
- function TtsRendererNULL.AddImage(Char: TtsChar; CharImage: TtsImage): TtsRendererImageReference;
- begin
- Result := TtsRendererNULLImageReference.Create;
-
- if fSaveImages then
- with TtsRendererNULLImageReference(Result) do begin
- Image := TtsImage.Create;
- Image.AssignFrom(CharImage);
- end;
- end;
-
-
- procedure TtsRendererNULL.DrawChar(Font: TtsFont; Char: TtsChar);
- begin
- // nothing
- end;
-
-
- procedure TtsRendererNULL.DrawSetColor(Red, Green, Blue, Alpha: Single);
- begin
- // nothing
- end;
-
-
- procedure TtsRendererNULL.DrawSetPosition(X, Y: Integer);
- begin
- // nothing
- end;
-
-
- procedure TtsRendererNULL.DrawSetPositionRelative(X, Y: Integer);
- begin
- // nothing
- end;
-
-
- procedure TtsRendererNULL.RemoveImageReference(ImageReference: TtsRendererImageReference);
- begin
- if (ImageReference is TtsRendererNULLImageReference) then
- with TtsRendererNULLImageReference(ImageReference) do
- if Image <> nil then
- Image.Free;
- end;
-
-
-
- { TtsRendererOpenGL }
-
- function TtsRendererOpenGL.AddImage(Char: TtsChar; CharImage: TtsImage): TtsRendererImageReference;
- var
- Idx: Integer;
- TextureEntry: PtsRendererOpenGLTextureEntry;
- TextureAdded: Boolean;
-
- Texture: PtsRendererOpenGLTexture;
- CharHeight, CharWidth: Integer;
-
- W1, H1, TempBorder: Single;
- begin
- Result := nil;
-
- if not CharImage.Empty then begin
- Result := TtsRendererOpenGLImageReference.Create;
-
- with TtsRendererOpenGLImageReference(Result) do begin
- Coordinates.Top := 0;
- Coordinates.Left := 0;
- Coordinates.Right := 0;
- Coordinates.Bottom := 0;
-
- TextureAdded := False;
- TextureEntry := nil;
-
- // look if we can add the image to an texture
- for Idx := 0 to fTextures.Count - 1 do begin
- if AddImageToTexture(fTextures[Idx], CharImage, TexID, Coordinates) then begin
- TextureEntry := fTextures[Idx];
- TextureAdded := True;
-
- Break;
- end;
- end;
-
- // could not added so create new texture
- if not TextureAdded then begin
- TextureEntry := CreateNewTexture;
-
- AddImageToTexture(TextureEntry, CharImage, TexID, Coordinates);
- end;
-
- // generating coords
- if TextureEntry <> nil then begin
- Texture := TextureEntry^.Texture;
-
- if Texture <> nil then begin
- with Char do begin
- CharHeight := Coordinates.Bottom - Coordinates.Top;
- CharWidth := Coordinates.Right - Coordinates.Left;
-
- // Set Variables for resizing border
- if HasResizingBorder then begin
- W1 := 1 / Texture^.Width;
- H1 := 1 / Texture^.Height;
- TempBorder := 2;
- end else begin
- W1 := 0;
- H1 := 0;
- TempBorder := 0;
- end;
-
- // Top Left
- TexCoords[0].X := Coordinates.Left / Texture^.Width + W1;
- TexCoords[0].Y := Coordinates.Top / Texture^.Height + H1;
- // Vertex[0].X := - GlyphRect.Left + Size1;
- // Vertex[0].Y := - GlyphRect.Top - GlyphOriginY + Size1;
- Vertex[0].X := - GlyphRect.Left;
- Vertex[0].Y := - GlyphRect.Top - GlyphOriginY;
-
- // Bottom Left
- TexCoords[1].X := Coordinates.Left / Texture^.Width + W1;
- TexCoords[1].Y := Coordinates.Bottom / Texture^.Height - H1;
- // Vertex[1].X := - GlyphRect.Left + Size1;
- // Vertex[1].Y := CharHeight - GlyphRect.Top - GlyphOriginY - Size1;
- Vertex[1].X := - GlyphRect.Left;
- Vertex[1].Y := CharHeight - GlyphRect.Top - GlyphOriginY - TempBorder;
-
- // Bottom Right
- TexCoords[2].X := Coordinates.Right / Texture^.Width - W1;
- TexCoords[2].Y := Coordinates.Bottom / Texture^.Height - H1;
- // Vertex[2].X := CharWidth - GlyphRect.Left - Size1;
- // Vertex[2].Y := CharHeight - GlyphRect.Top - GlyphOriginY - Size1;
- Vertex[2].X := CharWidth - GlyphRect.Left - TempBorder;
- Vertex[2].Y := CharHeight - GlyphRect.Top - GlyphOriginY - TempBorder;
-
- // Top Right
- TexCoords[3].X := Coordinates.Right / Texture^.Width - W1;
- TexCoords[3].Y := Coordinates.Top / Texture^.Height + H1;
- // Vertex[3].X := CharWidth - GlyphRect.Left - Size1;
- // Vertex[3].Y := - GlyphRect.Top - GlyphOriginY + Size1;
- Vertex[3].X := CharWidth - GlyphRect.Left - TempBorder;
- Vertex[3].Y := - GlyphRect.Top - GlyphOriginY;
- end;
- end;
- end;
- end;
- end;
- end;
-
-
- function TtsRendererOpenGL.AddImageToTexture(Texture: PtsRendererOpenGLTextureEntry; Image: TtsImage; var TextureID: Integer; var Coordinates: tsRect): boolean;
- var
- NeedX, NeedY: Word;
- Start: Word;
- Y, Y2: Integer;
- Managed: PtsRendererOpenGLManagedEntry;
-
-
- function CheckVertical(StartPos, EndPos: Integer): Boolean;
- var
- TempY: Integer;
- TempManaged: PtsRendererOpenGLManagedEntry;
- Found: Boolean;
- begin
- Result := False;
-
- for TempY := Y +1 to Y + NeedY -1 do begin
- TempManaged := Texture^.Lines[TempY];
-
- // Überprüfen ob der entsprechende Bereich noch frei ist.
- Found := False;
-
- while TempManaged <> nil do begin
- if (TempManaged^.Start <= StartPos) and (TempManaged^.Start + TempManaged^.Count >= EndPos) then
- Found := True;
-
- TempManaged := TempManaged^.NextEntry;
- end;
-
- if not Found then
- Exit;
- end;
-
- Result := True;
- end;
-
-
- begin
- Result := False;
-
- NeedX := Image.Width shr 1;
- if (Image.Width and 1) > 0 then
- Inc(NeedX);
-
- NeedY := Image.Height shr 1;
- if (Image.Height and 1) > 0 then
- Inc(NeedY);
-
- // scan for free space
- for Y := Low(Texture^.Lines) to High(Texture^.Lines) - NeedY do begin
- Managed := Texture^.Lines[Y];
-
- while Managed <> nil do begin
- if Managed^.Count >= NeedX then begin
- if CheckVertical(Managed^.Start, Managed^.Start + NeedX) then begin
- Start := Managed^.Start;
-
- // allocating space
- for Y2 := Y to Y + NeedY -1 do
- AllocSpace(Texture^.Lines[Y2], Start, NeedX);
-
- // setting texturecoordinates values
- TextureID := Texture^.ID;
-
- Coordinates.Left := Start shl 1;
- Coordinates.Top := Y shl 1;
- Coordinates.Right := Coordinates.Left + Image.Width;
- Coordinates.Bottom := Coordinates.Top + Image.Height;
-
- Texture^.Usage := Texture^.Usage + NeedX * NeedY;
-
- // copy charimage
- with Texture^.Texture^ do begin
- glBindTexture(GL_TEXTURE_2D, Texture^.Texture^.glTextureID);
- glTexSubImage2D(GL_TEXTURE_2D, 0, Coordinates.Left, Coordinates.Top, Image.Width, Image.Height, GL_RGBA, GL_UNSIGNED_BYTE, Image.Data);
- end;
-
- Result := True;
- Exit;
- end;
- end;
-
- Managed := Managed^.NextEntry;
- end;
- end;
- end;
-
-
- procedure TtsRendererOpenGL.AfterConstruction;
- begin
- inherited;
-
- fTextures := TList.Create;
- fTextureSize := 256;
- end;
-
-
- procedure TtsRendererOpenGL.AllocSpace(var FirstManaged: PtsRendererOpenGLManagedEntry; Start, Count: Word);
- var
- Managed, TempManaged: PtsRendererOpenGLManagedEntry;
-
-
- procedure RemoveManagedItem(pItem: PtsRendererOpenGLManagedEntry);
- var
- pTemp, pTemp2: PtsRendererOpenGLManagedEntry;
- begin
- pTemp := FirstManaged;
-
- while pTemp <> nil do begin
- pTemp2 := pTemp^.NextEntry;
-
- if pTemp2 = pItem then begin
- pTemp^.NextEntry := pItem^.NextEntry;
-
- Break;
- end;
-
- pTemp := pTemp2;
- end;
- end;
-
-
- begin
- // complete remove of the FIRST item (spezial handling for first item removal.)
- if (Start = FirstManaged^.Start) and (Count = FirstManaged^.Count) then begin
- TempManaged := FirstManaged;
-
- FirstManaged := FirstManaged^.NextEntry;
-
- Dispose(TempManaged);
- end else
-
- // look for matching item
- begin
- Managed := FirstManaged;
-
- while Managed <> nil do begin
- // matched item?
- if (Start >= Managed^.Start) and ((Start + Count) <= (Managed^.Start + Managed^.Count)) then begin
-
- // cut at start
- if (Start = Managed^.Start) then begin
-
- // remove the whole item
- if (Count = Managed^.Count) then begin
- RemoveManagedItem(Managed);
-
- // no need to preserve Managed because we leaving the loop
- Dispose(Managed);
- end else
-
- // cut at start
- begin
- Managed^.Start := Managed^.Start + Count;
- Managed^.Count := Managed^.Count - Count;
- end;
- end else
-
- // cut at end
- if (Start + Count) = (Managed^.Start + Managed^.Count) then begin
- Managed^.Count := Managed^.Count - Count;
- end else
-
- // cut in the middle
- begin
- New(TempManaged);
- TempManaged^.NextEntry := Managed^.NextEntry;
- Managed^.NextEntry := TempManaged;
-
- TempManaged^.Start := Start + Count;
- TempManaged^.Count := (Managed^.Start + Managed^.Count) - TempManaged^.Start;
-
- Managed^.Count := Start - Managed^.Start;
- end;
-
- // we found an item so leave the loop
- Break;
- end;
-
- Managed := Managed^.NextEntry;
- end;
- end;
- end;
-
-
- procedure TtsRendererOpenGL.BeforeDestruction;
- begin
- ClearTextures;
- fTextures.Free;
-
- inherited;
- end;
-
-
- procedure TtsRendererOpenGL.BeginBlock(Left, Top, Width, Height: Integer; Flags: tsBitmask);
- begin
- fPos.X := 0;
- fPos.Y := 0;
-
- inherited;
- end;
-
-
- procedure TtsRendererOpenGL.ClearTextures;
- var
- Idx: Integer;
- begin
- // Disposing items
- for Idx := fTextures.Count - 1 downto 0 do
- DeleteTexture(Idx);
-
- // Clear list
- fTextures.Clear;
- end;
-
-
- function TtsRendererOpenGL.CreateNewTexture: PtsRendererOpenGLTextureEntry;
- var
- Idx: Integer;
- begin
- New (Result);
- with Result^ do begin
- ID := fTextures.Add(Result);
- Usage := 0;
-
- // create opengl texture
- New(Texture);
- with Texture^ do begin
- Width := TextureSize;
- Height := TextureSize;
-
- glGenTextures(1, @glTextureID);
- glBindTexture(GL_TEXTURE_2D, glTextureID);
-
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
-
- glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, TextureSize, TextureSize, 0, GL_RGBA, GL_UNSIGNED_BYTE, nil);
- end;
-
- // initiale memory manager value
- SetLength(Lines, Texture^.Height shr 1);
-
- for Idx := Low(Lines) to High(Lines) do begin
- New(Lines[Idx]);
- Lines[Idx]^.NextEntry := nil;
- Lines[Idx]^.Start := 0;
- Lines[Idx]^.Count := Texture^.Width shr 1;
- end;
- end;
- end;
-
-
- procedure TtsRendererOpenGL.DeleteTexture(Idx: Integer);
- var
- pItem: PtsRendererOpenGLTextureEntry;
-
- LineIdx: Integer;
- pManaged, pTempManaged: PtsRendererOpenGLManagedEntry;
- begin
- pItem := fTextures[Idx];
-
- fTextures.Delete(Idx);
-
- if pItem <> nil then begin
- with pItem^ do begin
- // Free opengl texture
- if Texture <> nil then begin
- glDeleteTextures(1, @(Texture^.glTextureID));
-
- Dispose(Texture);
- end;
-
- // free lines
- for LineIdx := Low(Lines) to High(Lines) do begin
- pManaged := Lines[LineIdx];
- Lines[LineIdx] := nil;
-
- while pManaged <> nil do begin
- pTempManaged := pManaged;
- pManaged := pManaged^.NextEntry;
-
- Dispose(pTempManaged);
- end;
- end;
-
- SetLength(Lines, 0);
- end;
-
- Dispose(pItem);
- end;
- end;
-
-
- procedure TtsRendererOpenGL.DrawChar(Font: TtsFont; Char: TtsChar);
- var
- Texture: PtsRendererOpenGLTexture;
- TempVertex: tsQuadFloat;
- begin
- if Char.RendererImageReference <> nil then begin
- with Char.RendererImageReference as TtsRendererOpenGLImageReference do begin
- Texture := GetTextureByID(TexID);
-
- if Texture <> nil then begin
- glBindTexture(GL_TEXTURE_2D, Texture^.glTextureID);
- glEnable(GL_TEXTURE_2D);
-
- // calculate new quad
- TranslateQuad(TempVertex, Vertex, fPos);
-
- glBegin(GL_QUADS);
- glTexCoord2fv(@TexCoords[0]);
- glVertex2fv(@TempVertex[0]);
-
- glTexCoord2fv(@TexCoords[1]);
- glVertex2fv(@TempVertex[1]);
-
- glTexCoord2fv(@TexCoords[2]);
- glVertex2fv(@TempVertex[2]);
-
- glTexCoord2fv(@TexCoords[3]);
- glVertex2fv(@TempVertex[3]);
- glEnd;
-
- // if debug is enabled
- if fContext.gDebugDrawCharRects then begin
- glDisable(GL_TEXTURE_2D);
-
- // image Rect
- glColor4f(0, 1, 0, 0.1);
- glBegin(GL_QUADS);
- glVertex2fv(@TempVertex[0]);
- glVertex2fv(@TempVertex[1]);
- glVertex2fv(@TempVertex[2]);
- glVertex2fv(@TempVertex[3]);
- glEnd;
-
- // glyph rect
- glColor4f(1, 0, 0, 0.1);
- glBegin(GL_QUADS);
- glVertex2f(TempVertex[0].X + Char.GlyphRect.Left, TempVertex[0].Y + Char.GlyphRect.Top);
- glVertex2f(TempVertex[0].X + Char.GlyphRect.Left, TempVertex[0].Y + Char.GlyphRect.Bottom);
- glVertex2f(TempVertex[0].X + Char.GlyphRect.Right, TempVertex[0].Y + Char.GlyphRect.Bottom);
- glVertex2f(TempVertex[0].X + Char.GlyphRect.Right, TempVertex[0].Y + Char.GlyphRect.Top);
- glEnd;
-
- // baseline
- glColor4f(0, 0, 1, 0.25);
- glBegin(GL_LINES);
- glVertex2f(TempVertex[0].X, 0);
- glVertex2f(TempVertex[2].X, 0);
- glEnd;
-
- glColor4f(1, 1, 1, 1);
- end;
- end;
- end;
- end;
- end;
-
-
- procedure TtsRendererOpenGL.DrawSetColor(Red, Green, Blue, Alpha: Single);
- begin
- glColor4f(Red, Green, Blue, Alpha);
- end;
-
-
- procedure TtsRendererOpenGL.DrawSetPosition(X, Y: Integer);
- begin
- fPos.X := X;
- fPos.Y := Y;
- end;
-
-
- procedure TtsRendererOpenGL.DrawSetPositionRelative(X, Y: Integer);
- begin
- DrawSetPosition(fPos.X + X, fPos.Y + Y);
- end;
-
-
- procedure TtsRendererOpenGL.FreeSpace(var FirstManaged: PtsRendererOpenGLManagedEntry; Start, Count: Word);
- var
- Last, Managed, Temp: PtsRendererOpenGLManagedEntry;
- AddItem: Boolean;
- begin
- // if we have no space we can add item directly
- if FirstManaged = nil then begin
- New(Temp);
- Temp^.Start := Start;
- Temp^.Count := Count;
- Temp^.NextEntry := nil;
-
- FirstManaged := Temp;
- end else
-
- // Special handling for first Item
- if Start + Count < FirstManaged^.Start then begin
- New(Temp);
- Temp^.Start := Start;
- Temp^.Count := Count;
- Temp^.NextEntry := FirstManaged;
-
- FirstManaged := Temp;
- end else
-
- begin
- Managed := FirstManaged;
- Last := nil;
-
- while Managed <> nil do begin
- // block is in front of another
- if Start + Count = Managed^.Start then begin
- Managed^.Start := Managed^.Start - Count;
- Managed^.Count := Managed^.Count + Count;
-
- if Last <> nil then begin
- if Last^.Start + Last^.Count = Managed^.Start then begin
- // Remove Item
- Last^.Count := Last^.Count + Managed^.Count;
- Last^.NextEntry := Managed^.NextEntry;
-
- Dispose(Managed);
- end;
- end;
-
- Break;
- end else
-
- // block is behind another
- if Start = Managed^.Start + Managed^.Count then begin
- Managed^.Count := Managed^.Count + Count;
-
- Temp := Managed^.NextEntry;
- if Temp <> nil then begin
- if Managed^.Start + Managed^.Count = Temp^.Start then begin
- // Remove Item
- Managed^.Count := Managed^.Count + Temp^.Count;
- Managed^.NextEntry := Temp^.NextEntry;
-
- Dispose(Temp);
- end;
- end;
-
- Break;
- end else
-
- // the block dosn't border an other so we must create some other
- begin
- AddItem := False;
-
- if not (Managed^.NextEntry <> nil) then
- AddItem := True
- else
-
- if (Managed^.Start + Managed^.Count < Start) and (Managed^.NextEntry^.Start > Start + Count) then
- AddItem := True;
-
- if AddItem then begin
- New(Temp);
- Temp^.Start := Start;
- Temp^.Count := Count;
- Temp^.NextEntry := Managed^.NextEntry;
- Managed^.NextEntry := Temp;
-
- Break;
- end;
- end;
-
- Last := Managed;
- Managed := Managed^.NextEntry;
- end;
- end;
- end;
-
-
- function TtsRendererOpenGL.GetTextureByID(ID: Integer): PtsRendererOpenGLTexture;
- var
- Idx: Integer;
- pTexture: PtsRendererOpenGLTextureEntry;
- begin
- Result := nil;
-
- for Idx := 0 to fTextures.Count - 1 do begin
- pTexture := fTextures[Idx];
-
- if pTexture <> nil then
- if pTexture^.ID = ID then begin
- Result := pTexture^.Texture;
- Break;
- end;
- end;
- end;
-
-
-
- procedure TtsRendererOpenGL.RemoveImageReference(ImageReference: TtsRendererImageReference);
- var
- OpenGLRef: TtsRendererOpenGLImageReference;
- pItem: PtsRendererOpenGLTextureEntry;
-
- Idx, TempIdx: Integer;
- TempWidth, TempHeight: Integer;
- NeedX, NeedY: Integer;
- LinesY, TempX, TempY: Integer;
- begin
- OpenGLRef := TtsRendererOpenGLImageReference(ImageReference);
-
- // freeing texture
- for Idx := 0 to fTextures.Count - 1 do begin
- pItem := fTextures[Idx];
-
- if pItem <> nil then begin
- if pItem^.ID = OpenGLRef.TexID then begin
- TempWidth := OpenGLRef.Coordinates.Right - OpenGLRef.Coordinates.Left;
- TempHeight := OpenGLRef.Coordinates.Bottom - OpenGLRef.Coordinates.Top;
-
- with pItem^ do begin
- // calc size
- NeedX := TempWidth shr 1;
- if (TempWidth and 1) > 0 then
- Inc(NeedX);
-
- NeedY := TempHeight shr 1;
- if (TempHeight and 1) > 0 then
- Inc(NeedY);
-
- TempY := OpenGLRef.Coordinates.Top shr 1;
- TempX := OpenGLRef.Coordinates.Left shr 1;
-
- Usage := Usage - NeedX * NeedY;
-
- Assert(Usage >= 0);
-
- // Points
- for LinesY := 0 to NeedY - 1 do
- FreeSpace(Lines[TempY + LinesY], TempX, NeedX);
-
- // freeing opengltexture
- if Usage = 0 then begin
- for TempIdx := 0 to fTextures.Count - 1 do begin
- if PtsRendererOpenGLTextureEntry(fTextures[TempIdx])^.ID = pItem^.ID then begin
- DeleteTexture(TempIdx);
-
- Break;
- end;
- end;
- end;
- end;
-
- Break;
- end;
- end;
- end;
- end;
-
-
- { TtsContext }
-
- function TtsContext.AnsiToWide(pText: pAnsiChar): pWideChar;
-
- function GetDefaultChar: WideChar;
- begin
- Result := #0;
-
- if tsGetParameteri(TS_EMPTY_CP_ENTRY) = TS_EMPTY_CP_ENTRY_USE_DEFAULT then
- if ActiveFont <> nil then
- Result := ActiveFont.DefaultChar;
- end;
-
- begin
- Result := nil;
-
- // UTF-8
- if gCodePage = TS_CODEPAGE_UTF8 then begin
- Result := tsStrAlloc(Length(pText));
- tsAnsiUTF8ToWide(Result, pText, GetDefaultChar);
- end else
-
- // ISO 8859-1
- if gCodePage = TS_CODEPAGE_8859_1 then begin
- Result := tsStrAlloc(Length(pText));
- tsAnsiISO_8859_1_ToWide(Result, pText);
- end else
-
- // single or double byte CodePage
- begin
- if (Addr(gCodePageFunc) <> nil) and (gCodePagePtr <> nil) then begin
- Result := tsStrAlloc(Length(pText));
- gCodePageFunc(Result, pText, gCodePagePtr, GetDefaultChar);
- end;
- end;
- end;
-
-
- procedure TtsContext.ClearFonts;
- var
- List: TList;
- Idx: Integer;
- pItem: PtsContextFontEntry;
- begin
- List := TList.Create;
- try
- fFonts.GetValues(List);
- fFonts.Clear;
-
- for Idx := 0 to List.Count - 1 do begin
- pItem := List[Idx];
-
- pItem^.Font.Free;
- Dispose(pItem);
- end;
- finally
- List.Free;
- end;
- end;
-
-
- procedure TtsContext.ClearImages;
- var
- List: TList;
- Idx: Integer;
- pItem: PtsContextImageEntry;
- begin
- List := TList.Create;
- try
- fImages.GetValues(List);
- fImages.Clear;
-
- for Idx := 0 to List.Count - 1 do begin
- pItem := List[Idx];
-
- pItem^.Image.Free;
- Dispose(pItem);
- end;
- finally
- List.Free;
- end;
- end;
-
-
- constructor TtsContext.Create;
- begin
- inherited;
-
- Inc(gLastContextID);
- fContextID := gLastContextID;
-
- // hashes
- fFonts := TtsHash.Create(127);
- fImages := TtsHash.Create(127);
-
- // defaults
- gEmptyCodePageEntry := TS_EMPTY_CP_ENTRY_USE_DEFAULT;
- gCodePage := TS_CODEPAGE_8859_1;
- gCodePagePtr := nil; //@CP_8859_1;
- gCodePageFunc := nil; //tsAnsiSBCDToWide;
-
- gGlobalFormat := TS_FORMAT_RGBA8;
- gGlobalAntiAliasing := TS_ANTIALIASING_NORMAL;
-
- gSingleLine := TS_SINGLE_LINE_BASELINE;
- gAlign := TS_ALIGN_LEFT;
- gVAlign := TS_VALIGN_TOP;
- gClip := TS_CLIP_COMPLETE;
-
- gImageMode[tsModeRed] := TS_MODE_REPLACE;
- gImageMode[tsModeGreen] := TS_MODE_REPLACE;
- gImageMode[tsModeBlue] := TS_MODE_REPLACE;
- gImageMode[tsModeAlpha] := TS_MODE_MODULATE;
- gImageMode[tsModeLuminance] := TS_MODE_REPLACE;
-
- gImageLibrary := 0;
- end;
-
-
- destructor TtsContext.Destroy;
- begin
- ClearFonts;
- fFonts.Free;
-
- ClearImages;
- fImages.Free;
-
- if Renderer <> nil then
- Renderer.Free;
-
- inherited;
- end;
-
-
- function TtsContext.FontAdd(Font: TtsFont): Cardinal;
- var
- Entry: PtsContextFontEntry;
- begin
- New(Entry);
-
- Inc(fLastFontID);
-
- Entry^.FontID := fLastFontID;
- Entry^.Font := Font;
-
- fFonts.Add(fLastFontID, Entry);
-
- Result := fLastFontID;
- end;
-
-
- function TtsContext.FontCount: Cardinal;
- begin
- Result := fFonts.Count;
- end;
-
-
- procedure TtsContext.FontDelete(Font: Cardinal);
- var
- Entry: PtsContextFontEntry;
- begin
- if fLastFontID = Font then
- Renderer.FontActivate(0);
-
- Entry := fFonts.Get(Font);
-
- if Entry <> nil then begin
- fFonts.Delete(Entry^.FontID);
-
- Dispose(Entry);
- end;
- end;
-
-
- function TtsContext.FontGet(Font: Cardinal): TtsFont;
- var
- Entry: PtsContextFontEntry;
- begin
- Entry := fFonts.Get(Font);
-
- if Entry <> nil then
- Result := Entry^.Font
- else
- Result := nil;
- end;
-
-
- function TtsContext.GetActiveFont: TtsFont;
- begin
- Result := nil;
-
- if Renderer <> nil then
- Result := Renderer.ActiveFont;
- end;
-
-
- function TtsContext.GetIsLocked: boolean;
- begin
- if Renderer <> nil then
- Result := Renderer.isBlock
- else
- Result := False;
- end;
-
-
- function TtsContext.ImageAdd(Image: TtsImage): Cardinal;
- var
- Entry: PtsContextImageEntry;
- begin
- New(Entry);
-
- Inc(fLastImageID);
-
- Entry^.ImageID := fLastImageID;
- Entry^.Image := Image;
-
- fImages.Add(fLastImageID, Entry);
-
- Result := fLastImageID;
- end;
-
-
- function TtsContext.ImageCount: Cardinal;
- begin
- Result := fImages.Count;
- end;
-
-
- procedure TtsContext.ImageDelete(Image: Cardinal);
- var
- Entry: PtsContextImageEntry;
- begin
- Entry := fImages.Get(Image);
-
- if Entry <> nil then begin
- fImages.Delete(Entry^.ImageID);
-
- Dispose(Entry);
- end;
- end;
-
-
- function TtsContext.ImageGet(Image: Cardinal): TtsImage;
- var
- Entry: PtsContextImageEntry;
- begin
- Entry := fImages.Get(Image);
-
- if Entry <> nil then
- Result := Entry^.Image
- else
- Result := nil;
- end;
-
- end.
|