LZScene

Форк
0
/
GLBitmapFont.pas 
1498 строк · 41.0 Кб
1
//
2
// This unit is part of the GLScene Engine https://github.com/glscene
3
//
4
{
5
  Bitmap Fonts management classes for GLScene
6

7
   History :  
8
   04/12/14 - PW - Corrected the usage of pixel formats for Lazarus (by Gabriel Corneanu)
9
   20/11/12 - PW - CPP compatibility: replaced direct access to some properties with records
10
   01/09/11 - Yar - Bugfixed StartASCII, StopASCII properties for non-Unicode compiler
11
   30/06/11 - DaStr - Bugfixed TGLBitmapFontRanges.Add(for AnsiChar)
12
   16/05/11 - Yar - Redesign to use multiple textures (by Gabriel Corneanu)
13
   13/05/11 - Yar - Adapted to unicode (by Gabriel Corneanu)
14
   23/08/10 - Yar - Added OpenGLTokens to uses, replaced OpenGL1x functions to OpenGLAdapter
15
   05/07/10 - Yar - Now HSpace and VSpace can take negative values (thanks Sandor Domokos) (BugtrackerID = 3024975)
16
   22/04/10 - Yar - Fixes after GLState revision
17
   05/03/10 - DanB - More state added to TGLStateCache
18
   24/02/10 - Yar - Bugfix in TGLCustomBitmapFont.PrepareImage when image is not RGBA8
19
   25/01/10 - Yar - Replace Char to AnsiChar
20
   11/11/09 - DaStr - Added Delphi 2009 compatibility (thanks mal)
21
   16/10/08 - UweR - Removed unneeded typecast in TGLBitmapFontRange.SetStartGlyphIdx
22
   06/06/07 - DaStr - Added GLColor to uses (BugtrackerID = 1732211)
23
   30/03/07 - DaStr - Added $I GLScene.inc
24
   22/12/06 - LC - Fixed TGLCustomBitmapFont.RenderString, it now unbinds the texture.
25
  Bugtracker ID=1619243 (thanks Da Stranger)
26
   09/03/05 - EG - Fixed space width during rendering
27
   12/15/04 - Eugene Kryukov - Moved FCharRects to protected declaration in TGLCustomBitmapFont
28
   18/10/04 - NelC - Fixed a texture reset bug in RenderString
29
   02/08/04 - LR, YHC - BCB corrections: use record instead array
30
   28/06/04 - LR - Change TTextLayout to TGLTextLayout for Linux
31
   27/06/04 - NelC - Added TGLFlatText.Assign
32
   01/03/04 - SG - TGLCustomBitmapFont.RenderString now saves GL_CURRENT_BIT state
33
   01/07/03 - EG - TGLCustomBitmapFont.TextOut now saves and restore state
34
   07/05/03 - EG - TGLFlatText Notification fix, added Options
35
   30/10/02 - EG - Added TGLFlatText
36
   29/09/02 - EG - Added TexCoords LUT, faster RenderString,
37
  removed TGLBitmapFontRange.Widths
38
   28/09/02 - EG - Introduced TGLCustomBitmapFont
39
   06/09/02 - JAJ - Prepared for TGLWindowsBitmapFont
40
   28/08/02 - EG - Repaired fixed CharWidth, variable CharWidth not yet repaired
41
   12/08/02 - JAJ - Merged Dual Development, Alpha Channel and CharWidth are now side by side
42
   UNKNOWN  - EG - Added Alpha Channel.
43
   02/06/02 - JAJ - Modified to flexible character width
44
   20/01/02 - EG - Dropped 'Graphics' dependency
45
   10/09/01 - EG - Fixed visibility of tile 0
46
   12/08/01 - EG - Completely rewritten handles management
47
   21/02/01 - EG - Now XOpenGL based (multitexture)
48
   15/01/01 - EG - Creation
49
   
50
}
51
unit GLBitmapFont;
52

53
{$I GLScene.inc}
54

55
{$DEFINE GLS_UNICODE_SUPPORT}
56

57

58
interface
59

60
uses
61
  Classes, Graphics, SysUtils, Types,
62
  GLScene, GLVectorGeometry, GLContext, GLCrossPlatform,
63
  GLTexture, GLState, GLUtils, GLGraphics, GLColor, GLBaseClasses,
64
  GLRenderContextInfo, GLTextureFormat,
65
  OpenGLTokens, XOpenGL, GLVectorTypes;
66

67
type
68
{$IFNDEF GLS_UNICODE_SUPPORT}
69
  UnicodeString = WideString; // Use WideString for earlier versions
70
{$ENDIF}
71

72
  // TGLBitmapFontRange
73
  //
74
  { : An individual character range in a bitmap font.
75
    A range allows mapping ASCII characters to character tiles in a font
76
    bitmap, tiles are enumerated line then column (raster). }
77
  TGLBitmapFontRange = class(TCollectionItem)
78
  private
79
    function GetStartASCII: WideString;
80
    function GetStopASCII: WideString;
81
  protected
82
     
83
    FStartASCII, FStopASCII: WideChar;
84
    FStartGlyphIdx, FStopGlyphIdx, FCharCount: Integer;
85
    procedure SetStartASCII(const val: WideString);
86
    procedure SetStopASCII(const val: WideString);
87
    procedure SetStartGlyphIdx(val: Integer);
88
    function GetDisplayName: string; override;
89
  public
90
     
91
    constructor Create(Collection: TCollection); override;
92
    destructor Destroy; override;
93

94
    procedure Assign(Source: TPersistent); override;
95
    procedure NotifyChange;
96
  published
97
     
98
    property StartASCII: WideString read GetStartASCII write SetStartASCII;
99
    property StopASCII: WideString read GetStopASCII write SetStopASCII;
100
    property StartGlyphIdx: Integer read FStartGlyphIdx write SetStartGlyphIdx;
101
    property StopGlyphIdx: Integer read FStopGlyphIdx;
102
    property CharCount: Integer read FCharCount;
103
  end;
104

105
  // TGLBitmapFontRanges
106
  //
107
  TGLBitmapFontRanges = class(TCollection)
108
  private
109
    FCharCount: Integer;
110
  protected
111
     
112
    FOwner: TComponent;
113

114
    function GetOwner: TPersistent; override;
115
    procedure SetItems(index: Integer; const val: TGLBitmapFontRange);
116
    function GetItems(index: Integer): TGLBitmapFontRange;
117
    function CalcCharacterCount: Integer;
118
    procedure Update(Item: TCollectionItem); override;
119

120
  public
121
     
122
    constructor Create(AOwner: TComponent);
123
    destructor Destroy; override;
124

125
    function Add: TGLBitmapFontRange; overload;
126
    function Add(const StartASCII, StopASCII: WideChar)
127
      : TGLBitmapFontRange; overload;
128
    function Add(const StartASCII, StopASCII: AnsiChar)
129
      : TGLBitmapFontRange; overload;
130
    function FindItemID(ID: Integer): TGLBitmapFontRange;
131
    property Items[index: Integer]: TGLBitmapFontRange read GetItems
132
      write SetItems; default;
133

134
    { : Converts an ASCII character into a tile index.
135
      Return -1 if character cannot be rendered. }
136
    function CharacterToTileIndex(aChar: WideChar): Integer;
137
    function TileIndexToChar(aIndex: Integer): WideChar;
138
    procedure NotifyChange;
139

140
    // : Total number of characters in the ranges; cached for performance
141
    property CharacterCount: Integer read FCharCount;
142
  end;
143

144
  PCharInfo = ^TCharInfo;
145

146
  TCharInfo = record
147
    l, t, w: word;
148
  end;
149

150
  // TGLCustomBitmapFont
151
  //
152
  { : Provides access to individual characters in a BitmapFont.
153
    Only fixed-width bitmap fonts are supported, the characters are enumerated
154
    in a raster fashion (line then column). 
155
    Transparency is all or nothing, the transparent color being that of the
156
    top left pixel of the Glyphs bitmap.
157
    Performance note: as usual, for best performance, you base font bitmap
158
    dimensions should be close to a power of two, and have at least 1 pixel
159
    spacing between characters (horizontally and vertically) to avoid artefacts
160
    when rendering with linear filtering. }
161
  TGLCustomBitmapFont = class(TGLUpdateAbleComponent)
162
  private
163
     
164
    FRanges: TGLBitmapFontRanges;
165
    FGlyphs: TGLPicture;
166
    FCharWidth, FCharHeight: Integer;
167
    FGlyphsIntervalX, FGlyphsIntervalY: Integer;
168
    FHSpace, FVSpace, FHSpaceFix: Integer;
169
    FUsers: TList;
170
    FMinFilter: TGLMinFilter;
171
    FMagFilter: TGLMagFilter;
172
    FTextureWidth, FTextureHeight: Integer;
173
    FTextRows, FTextCols: Integer;
174
    FGlyphsAlpha: TGLTextureImageAlpha;
175
    FTextures: TList;
176
    FTextureModified: boolean;
177
    FLastTexture: TGLTextureHandle;
178
  protected
179
     
180
    FChars: array of TCharInfo;
181
    FCharsLoaded: boolean;
182
    procedure ResetCharWidths(w: Integer = -1);
183
    procedure SetCharWidths(index, value: Integer);
184

185
    procedure SetRanges(const val: TGLBitmapFontRanges);
186
    procedure SetGlyphs(const val: TGLPicture);
187
    procedure SetCharWidth(const val: Integer);
188
    procedure SetCharHeight(const val: Integer);
189
    procedure SetGlyphsIntervalX(const val: Integer);
190
    procedure SetGlyphsIntervalY(const val: Integer);
191
    procedure OnGlyphsChanged(Sender: TObject);
192
    procedure SetHSpace(const val: Integer);
193
    procedure SetVSpace(const val: Integer);
194
    procedure SetMagFilter(AValue: TGLMagFilter);
195
    procedure SetMinFilter(AValue: TGLMinFilter);
196
    procedure SetGlyphsAlpha(val: TGLTextureImageAlpha);
197

198
    procedure TextureChanged;
199
    procedure FreeTextureHandle; dynamic;
200
    function TextureFormat: Integer; dynamic;
201

202
    procedure InvalidateUsers;
203
    function CharactersPerRow: Integer;
204
    procedure GetCharTexCoords(Ch: WideChar;
205
      var TopLeft, BottomRight: TTexPoint);
206
    procedure GetICharTexCoords(var ARci: TGLRenderContextInfo; Chi: Integer;
207
      out TopLeft, BottomRight: TTexPoint);
208
    procedure PrepareImage(var ARci: TGLRenderContextInfo); virtual;
209
    procedure PrepareParams(var ARci: TGLRenderContextInfo);
210

211
    { : A single bitmap containing all the characters.
212
      The transparent color is that of the top left pixel. }
213
    property Glyphs: TGLPicture read FGlyphs write SetGlyphs;
214
    { : Nb of horizontal pixels between two columns in the Glyphs. }
215
    property GlyphsIntervalX: Integer read FGlyphsIntervalX
216
      write SetGlyphsIntervalX;
217
    { : Nb of vertical pixels between two rows in the Glyphs. }
218
    property GlyphsIntervalY: Integer read FGlyphsIntervalY
219
      write SetGlyphsIntervalY;
220
    { : Ranges allow converting between ASCII and tile indexes.
221
      See TGLCustomBitmapFontRange. }
222
    property Ranges: TGLBitmapFontRanges read FRanges write SetRanges;
223

224
    { : Width of a single character. }
225
    property CharWidth: Integer read FCharWidth write SetCharWidth default 16;
226
    { : Pixels in between rendered characters (horizontally). }
227
    property HSpace: Integer read FHSpace write SetHSpace default 1;
228
    { : Pixels in between rendered lines (vertically). }
229
    property VSpace: Integer read FVSpace write SetVSpace default 1;
230
    { : Horizontal spacing fix offset.
231
      This property is for internal use, and is added to the hspacing
232
      of each character when rendering, typically to fix extra spacing. }
233
    property HSpaceFix: Integer read FHSpaceFix write FHSpaceFix;
234

235
    property MagFilter: TGLMagFilter read FMagFilter write SetMagFilter
236
      default maLinear;
237
    property MinFilter: TGLMinFilter read FMinFilter write SetMinFilter
238
      default miLinear;
239
    property GlyphsAlpha: TGLTextureImageAlpha read FGlyphsAlpha
240
      write FGlyphsAlpha default tiaDefault;
241

242
  public
243
     
244
    constructor Create(AOwner: TComponent); override;
245
    destructor Destroy; override;
246

247
    procedure RegisterUser(anObject: TGLBaseSceneObject); virtual;
248
    procedure UnRegisterUser(anObject: TGLBaseSceneObject); virtual;
249

250
    { : Renders the given string at current position or at position given by the optional position variable.
251
      The current matrix is blindly used, meaning you can render all kinds
252
      of rotated and linear distorted text with this method, OpenGL
253
      Enable states are also possibly altered. }
254
    procedure RenderString(var ARci: TGLRenderContextInfo;
255
      const aText: UnicodeString; aAlignment: TAlignment;
256
      aLayout: TGLTextLayout; const aColor: TColorVector;
257
      aPosition: PVector = nil; aReverseY: boolean = False); overload; virtual;
258

259
    { : A simpler canvas-style TextOut helper for RenderString.
260
      The rendering is reversed along Y by default, to allow direct use
261
      with TGLCanvas }
262
    procedure TextOut(var rci: TGLRenderContextInfo; X, Y: Single;
263
      const Text: UnicodeString; const Color: TColorVector); overload;
264
    procedure TextOut(var rci: TGLRenderContextInfo; X, Y: Single;
265
      const Text: UnicodeString; const Color: TColor); overload;
266
    function TextWidth(const Text: UnicodeString): Integer;
267

268
    function CharacterToTileIndex(aChar: WideChar): Integer; virtual;
269
    function TileIndexToChar(aIndex: Integer): WideChar; virtual;
270
    function CharacterCount: Integer; virtual;
271

272
    { : Get the actual width for this char. }
273
    function GetCharWidth(Ch: WideChar): Integer;
274
    { : Get the actual pixel width for this string. }
275
    function CalcStringWidth(const aText: UnicodeString): Integer;
276
      overload; virtual;
277

278
    // make texture if needed
279
    procedure CheckTexture(var ARci: TGLRenderContextInfo);
280

281
    { : Height of a single character. }
282
    property CharHeight: Integer read FCharHeight write SetCharHeight
283
      default 16;
284

285
    property TextureWidth: Integer read FTextureWidth write FTextureWidth;
286
    property TextureHeight: Integer read FTextureHeight write FTextureHeight;
287
  end;
288

289
  // TGLBitmapFont
290
  //
291
  { : See TGLCustomBitmapFont.
292
    This class only publuishes some of the properties. }
293
  TGLBitmapFont = class(TGLCustomBitmapFont)
294
  published
295
     
296
    property Glyphs;
297
    property GlyphsIntervalX;
298
    property GlyphsIntervalY;
299
    property Ranges;
300
    property CharWidth;
301
    property CharHeight;
302
    property HSpace;
303
    property VSpace;
304
    property MagFilter;
305
    property MinFilter;
306
    property GlyphsAlpha;
307
  end;
308

309
  // TGLFlatTextOptions
310
  //
311
  TGLFlatTextOption = (ftoTwoSided);
312
  TGLFlatTextOptions = set of TGLFlatTextOption;
313

314
  // TGLFlatText
315
  //
316
  { : A 2D text displayed and positionned in 3D coordinates.
317
    The FlatText uses a character font defined and stored by a TGLBitmapFont
318
    component. Default character scale is 1 font pixel = 1 space unit. }
319
  TGLFlatText = class(TGLImmaterialSceneObject)
320
  private
321
     
322
    FBitmapFont: TGLCustomBitmapFont;
323
    FText: UnicodeString;
324
    FAlignment: TAlignment;
325
    FLayout: TGLTextLayout;
326
    FModulateColor: TGLColor;
327
    FOptions: TGLFlatTextOptions;
328

329
  protected
330
     
331
    procedure SetBitmapFont(const val: TGLCustomBitmapFont);
332
    procedure SetText(const val: UnicodeString);
333
    procedure SetAlignment(const val: TAlignment);
334
    procedure SetLayout(const val: TGLTextLayout);
335
    procedure SetModulateColor(const val: TGLColor);
336
    procedure SetOptions(const val: TGLFlatTextOptions);
337

338
    procedure Notification(AComponent: TComponent;
339
      Operation: TOperation); override;
340

341
  public
342
     
343
    constructor Create(AOwner: TComponent); override;
344
    destructor Destroy; override;
345

346
    procedure DoRender(var rci: TGLRenderContextInfo;
347
      renderSelf, renderChildren: boolean); override;
348

349
    procedure Assign(Source: TPersistent); override;
350

351
  published
352
     
353
    { : Refers the bitmap font to use.
354
      The referred bitmap font component stores and allows access to
355
      individual character bitmaps. }
356
    property BitmapFont: TGLCustomBitmapFont read FBitmapFont
357
      write SetBitmapFont;
358
    { : Text to render.
359
      Be aware that only the characters available in the bitmap font will
360
      be rendered. CR LF sequences are allowed. }
361
    property Text: UnicodeString read FText write SetText;
362
    { : Controls the text alignment (horizontal).
363
      Possible values : taLeftJustify, taRightJustify, taCenter }
364
    property Alignment: TAlignment read FAlignment write SetAlignment;
365
    { : Controls the text layout (vertical).
366
      Possible values : tlTop, tlCenter, tlBottom }
367
    property Layout: TGLTextLayout read FLayout write SetLayout;
368
    { : Color modulation, can be used for fade in/out too. }
369
    property ModulateColor: TGLColor read FModulateColor write SetModulateColor;
370
    { : Flat text options.
371
        ftoTwoSided : when set the text will be visible from its two
372
      sides even if faceculling is on (at the scene-level).
373
        }
374
    property Options: TGLFlatTextOptions read FOptions write SetOptions;
375
  end;
376

377
  // ------------------------------------------------------------------
378
  // ------------------------------------------------------------------
379
  // ------------------------------------------------------------------
380
implementation
381

382
// ------------------------------------------------------------------
383
// ------------------------------------------------------------------
384
// ------------------------------------------------------------------
385

386
// ------------------
387
// ------------------ TGLBitmapFontRange ------------------
388
// ------------------
389

390
// Create
391
//
392
constructor TGLBitmapFontRange.Create(Collection: TCollection);
393
begin
394
  inherited Create(Collection);
395
end;
396

397
// Destroy
398
//
399
destructor TGLBitmapFontRange.Destroy;
400
begin
401
  inherited;
402
end;
403

404
 
405
//
406
procedure TGLBitmapFontRange.Assign(Source: TPersistent);
407
begin
408
  if Source is TGLBitmapFontRange then
409
  begin
410
    FStartASCII := TGLBitmapFontRange(Source).FStartASCII;
411
    FStopASCII := TGLBitmapFontRange(Source).FStopASCII;
412
    FStartGlyphIdx := TGLBitmapFontRange(Source).FStartGlyphIdx;
413
    NotifyChange;
414
  end
415
  else
416
    inherited;
417
end;
418

419
// NotifyChange
420
//
421
procedure TGLBitmapFontRange.NotifyChange;
422
begin
423
  FCharCount := Integer(FStopASCII) - Integer(FStartASCII) + 1;
424
  FStopGlyphIdx := FStartGlyphIdx + FCharCount - 1;
425
  if Assigned(Collection) then
426
    (Collection as TGLBitmapFontRanges).NotifyChange;
427
end;
428

429
// GetDisplayName
430
//
431
function TGLBitmapFontRange.GetDisplayName: string;
432
begin
433
  Result := Format('ASCII [#%d, #%d] -> Glyphs [%d, %d]',
434
    [Integer(FStartASCII), Integer(FStopASCII), StartGlyphIdx, StopGlyphIdx]);
435
end;
436

437
function TGLBitmapFontRange.GetStartASCII: WideString;
438
begin
439
  Result := FStartASCII;
440
end;
441

442
function TGLBitmapFontRange.GetStopASCII: WideString;
443
begin
444
  Result := FStopASCII;
445
end;
446

447
// SetStartASCII
448
//
449
procedure TGLBitmapFontRange.SetStartASCII(const val: WideString);
450
begin
451
  if (Length(val) > 0) and (val[1] <> FStartASCII) then
452
  begin
453
    FStartASCII := val[1];
454
    if FStartASCII > FStopASCII then
455
      FStopASCII := FStartASCII;
456
    NotifyChange;
457
  end;
458
end;
459

460
// SetStopASCII
461
//
462
procedure TGLBitmapFontRange.SetStopASCII(const val: WideString);
463
begin
464
  if (Length(val) > 0) and (FStopASCII <> val[1]) then
465
  begin
466
    FStopASCII := val[1];
467
    if FStopASCII < FStartASCII then
468
      FStartASCII := FStopASCII;
469
    NotifyChange;
470
  end;
471
end;
472

473
// SetStartGlyphIdx
474
//
475
procedure TGLBitmapFontRange.SetStartGlyphIdx(val: Integer);
476
begin
477
  val := MaxInteger(0, val);
478
  if val <> FStartGlyphIdx then
479
  begin
480
    FStartGlyphIdx := val;
481
    NotifyChange;
482
  end;
483
end;
484

485
// ------------------
486
// ------------------ TGLBitmapFontRanges ------------------
487
// ------------------
488

489
// Create
490
//
491
constructor TGLBitmapFontRanges.Create(AOwner: TComponent);
492
begin
493
  FOwner := AOwner;
494
  inherited Create(TGLBitmapFontRange);
495
end;
496

497
// Destroy
498
//
499
destructor TGLBitmapFontRanges.Destroy;
500
begin
501
  inherited;
502
end;
503

504
// GetOwner
505
//
506
function TGLBitmapFontRanges.GetOwner: TPersistent;
507
begin
508
  Result := FOwner;
509
end;
510

511
// SetItems
512
//
513

514
procedure TGLBitmapFontRanges.SetItems(index: Integer;
515
  const val: TGLBitmapFontRange);
516
begin
517
  inherited Items[index] := val;
518
end;
519

520
// GetItems
521
//
522
function TGLBitmapFontRanges.GetItems(index: Integer): TGLBitmapFontRange;
523
begin
524
  Result := TGLBitmapFontRange(inherited Items[index]);
525
end;
526

527
// Add
528
//
529
function TGLBitmapFontRanges.Add: TGLBitmapFontRange;
530
begin
531
  Result := (inherited Add) as TGLBitmapFontRange;
532
end;
533

534
// Add
535
//
536
function TGLBitmapFontRanges.Add(const StartASCII, StopASCII: WideChar)
537
  : TGLBitmapFontRange;
538
begin
539
  Result := Add;
540
  Result.StartASCII := StartASCII;
541
  Result.StopASCII := StopASCII;
542
end;
543

544
// Add
545
//
546
function TGLBitmapFontRanges.Add(const StartASCII, StopASCII: AnsiChar)
547
  : TGLBitmapFontRange;
548
begin
549
  Result := Add(CharToWideChar(StartASCII), CharToWideChar(StopASCII));
550
end;
551

552
// FindItemID
553
//
554
function TGLBitmapFontRanges.FindItemID(ID: Integer): TGLBitmapFontRange;
555
begin
556
  Result := (inherited FindItemID(ID)) as TGLBitmapFontRange;
557
end;
558

559
// CharacterToTileIndex
560
//
561
function TGLBitmapFontRanges.CharacterToTileIndex(aChar: WideChar): Integer;
562
var
563
  i: Integer;
564
begin
565
  Result := -1;
566
  for i := 0 to Count - 1 do
567
    with Items[i] do
568
    begin
569
      if (aChar >= FStartASCII) and (aChar <= FStopASCII) then
570
      begin
571
        Result := StartGlyphIdx + Integer(aChar) - Integer(FStartASCII);
572
        Break;
573
      end;
574
    end;
575
end;
576

577
function TGLBitmapFontRanges.TileIndexToChar(aIndex: Integer): WideChar;
578
var
579
  i: Integer;
580
begin
581
  Result := #0;
582
  for i := 0 to Count - 1 do
583
    with Items[i] do
584
    begin
585
      if (aIndex >= StartGlyphIdx) and (aIndex <= StopGlyphIdx) then
586
      begin
587
        Result := WideChar(aIndex - StartGlyphIdx + Integer(FStartASCII));
588
        Break;
589
      end;
590
    end;
591
end;
592

593
procedure TGLBitmapFontRanges.Update(Item: TCollectionItem);
594
begin
595
  inherited;
596
  NotifyChange;
597
end;
598

599
// NotifyChange
600
//
601
procedure TGLBitmapFontRanges.NotifyChange;
602
begin
603
  FCharCount := CalcCharacterCount;
604

605
  if Assigned(FOwner) then
606
  begin
607
    if FOwner is TGLBaseSceneObject then
608
      TGLBaseSceneObject(FOwner).StructureChanged
609
    else if FOwner is TGLCustomBitmapFont then
610
      TGLCustomBitmapFont(FOwner).NotifyChange(Self);
611
  end;
612
end;
613

614
// CharacterCount
615
//
616
function TGLBitmapFontRanges.CalcCharacterCount: Integer;
617
var
618
  i: Integer;
619
begin
620
  Result := 0;
621
  for i := 0 to Count - 1 do
622
    with Items[i] do
623
      Inc(Result, Integer(FStopASCII) - Integer(FStartASCII) + 1);
624
end;
625

626
// ------------------
627
// ------------------ TGLCustomBitmapFont ------------------
628
// ------------------
629

630
// Create
631
//
632
constructor TGLCustomBitmapFont.Create(AOwner: TComponent);
633
begin
634
  inherited Create(AOwner);
635
  FRanges := TGLBitmapFontRanges.Create(Self);
636
  FGlyphs := TGLPicture.Create;
637
  FGlyphs.OnChange := OnGlyphsChanged;
638
  FCharWidth := 16;
639
  FCharHeight := 16;
640
  FHSpace := 1;
641
  FVSpace := 1;
642
  FUsers := TList.Create;
643
  FMinFilter := miLinear;
644
  FMagFilter := maLinear;
645
  FTextures := TList.Create;
646
  FTextureModified := true;
647
end;
648

649
// Destroy
650
//
651
destructor TGLCustomBitmapFont.Destroy;
652
begin
653
  FreeTextureHandle;
654
  inherited Destroy;
655
  FTextures.Free;
656
  FRanges.Free;
657
  FGlyphs.Free;
658
  Assert(FUsers.Count = 0);
659
  FUsers.Free;
660
end;
661

662
// GetCharWidth
663
//
664
function TGLCustomBitmapFont.GetCharWidth(Ch: WideChar): Integer;
665
var
666
  chi: Integer;
667
begin
668
  chi := CharacterToTileIndex(ch);
669
  if Length(FChars) = 0 then
670
    ResetCharWidths;
671
  if chi >= 0 then
672
    Result := FChars[chi].w
673
  else
674
    Result := 0;
675
end;
676

677
// CalcStringWidth
678
//
679
function TGLCustomBitmapFont.CalcStringWidth(const aText
680
  : UnicodeString): Integer;
681
var
682
  i: Integer;
683
begin
684
  if aText <> '' then
685
  begin
686
    Result := -HSpace + Length(aText) * (HSpaceFix + HSpace);
687
    for i := 1 to Length(aText) do
688
      Result := Result + GetCharWidth(aText[i]);
689
  end
690
  else
691
    Result := 0;
692
end;
693

694
// ResetCharWidths
695
//
696
procedure TGLCustomBitmapFont.ResetCharWidths(w: Integer = -1);
697
var
698
  i: Integer;
699
begin
700
  FCharsLoaded := False;
701
  i := CharacterCount;
702
  if Length(FChars) < i then
703
    SetLength(FChars, i);
704
  if w < 0 then
705
    w := CharWidth;
706
  for i := 0 to High(FChars) do
707
    FChars[i].w := w;
708
end;
709

710
// SetCharWidths
711
//
712
procedure TGLCustomBitmapFont.SetCharWidths(index, value: Integer);
713
begin
714
  if index >= 0 then
715
    FChars[index].w := value;
716
end;
717

718
// SetRanges
719
//
720
procedure TGLCustomBitmapFont.SetRanges(const val: TGLBitmapFontRanges);
721
begin
722
  FRanges.Assign(val);
723
  InvalidateUsers;
724
end;
725

726
// SetGlyphs
727
//
728
procedure TGLCustomBitmapFont.SetGlyphs(const val: TGLPicture);
729
begin
730
  FGlyphs.Assign(val);
731
end;
732

733
// SetCharWidth
734
//
735
procedure TGLCustomBitmapFont.SetCharWidth(const val: Integer);
736
begin
737
  if val <> FCharWidth then
738
  begin
739
    if val > 1 then
740
      FCharWidth := val
741
    else
742
      FCharWidth := 1;
743
    InvalidateUsers;
744
  end;
745
end;
746

747
// SetCharHeight
748
//
749
procedure TGLCustomBitmapFont.SetCharHeight(const val: Integer);
750
begin
751
  if val <> FCharHeight then
752
  begin
753
    if val > 1 then
754
      FCharHeight := val
755
    else
756
      FCharHeight := 1;
757
    InvalidateUsers;
758
  end;
759
end;
760

761
// SetGlyphsIntervalX
762
//
763
procedure TGLCustomBitmapFont.SetGlyphsIntervalX(const val: Integer);
764
begin
765
  if val > 0 then
766
    FGlyphsIntervalX := val
767
  else
768
    FGlyphsIntervalX := 0;
769
  InvalidateUsers;
770
end;
771

772
// SetGlyphsIntervalY
773
//
774
procedure TGLCustomBitmapFont.SetGlyphsIntervalY(const val: Integer);
775
begin
776
  if val > 0 then
777
    FGlyphsIntervalY := val
778
  else
779
    FGlyphsIntervalY := 0;
780
  InvalidateUsers;
781
end;
782

783
// SetHSpace
784
//
785
procedure TGLCustomBitmapFont.SetHSpace(const val: Integer);
786
begin
787
  if val <> FHSpace then
788
  begin
789
    FHSpace := val;
790
    InvalidateUsers;
791
  end;
792
end;
793

794
// SetVSpace
795
//
796
procedure TGLCustomBitmapFont.SetVSpace(const val: Integer);
797
begin
798
  if val <> FVSpace then
799
  begin
800
    FVSpace := val;
801
    InvalidateUsers;
802
  end;
803
end;
804

805
// SetMagFilter
806
//
807
procedure TGLCustomBitmapFont.SetMagFilter(AValue: TGLMagFilter);
808
begin
809
  if AValue <> FMagFilter then
810
  begin
811
    FMagFilter := AValue;
812
    TextureChanged;
813
    InvalidateUsers;
814
  end;
815
end;
816

817
// SetMinFilter
818
//
819
procedure TGLCustomBitmapFont.SetMinFilter(AValue: TGLMinFilter);
820
begin
821
  if AValue <> FMinFilter then
822
  begin
823
    FMinFilter := AValue;
824
    TextureChanged;
825
    InvalidateUsers;
826
  end;
827
end;
828

829
// SetGlyphsAlpha
830
//
831
procedure TGLCustomBitmapFont.SetGlyphsAlpha(val: TGLTextureImageAlpha);
832
begin
833
  if val <> FGlyphsAlpha then
834
  begin
835
    FGlyphsAlpha := val;
836
    TextureChanged;
837
    InvalidateUsers;
838
  end;
839
end;
840

841
// OnGlyphsChanged
842
//
843
procedure TGLCustomBitmapFont.OnGlyphsChanged(Sender: TObject);
844
begin
845
  InvalidateUsers;
846
  // when empty, width is 0 and roundup give 1
847
  if not Glyphs.Graphic.Empty then
848
  begin
849
    if FTextureWidth = 0 then
850
      FTextureWidth := RoundUpToPowerOf2(Glyphs.Width);
851
    if FTextureHeight = 0 then
852
      FTextureHeight := RoundUpToPowerOf2(Glyphs.Height);
853
  end;
854
end;
855

856
// RegisterUser
857
//
858
procedure TGLCustomBitmapFont.RegisterUser(anObject: TGLBaseSceneObject);
859
begin
860
  Assert(FUsers.IndexOf(anObject) < 0);
861
  FUsers.Add(anObject);
862
end;
863

864
// UnRegisterUser
865
//
866
procedure TGLCustomBitmapFont.UnRegisterUser(anObject: TGLBaseSceneObject);
867
begin
868
  FUsers.Remove(anObject);
869
end;
870

871
// PrepareImage
872
//
873
procedure TGLCustomBitmapFont.PrepareImage(var ARci: TGLRenderContextInfo);
874
var
875
  bitmap: TGLBitmap;
876
  bitmap32: TGLBitmap32;
877
  cap: Integer;
878
  X, Y, w, h: Integer;
879
  t: TGLTextureHandle;
880
begin
881
  // only check when really used
882
  if FTextureWidth = 0 then
883
  begin
884
    FTextureWidth := ARci.GLStates.MaxTextureSize;
885
    if FTextureWidth > 512 then
886
      FTextureWidth := 512;
887
    if FTextureWidth < 64 then
888
      FTextureWidth := 64;
889
  end;
890
  if FTextureHeight = 0 then
891
  begin
892
    FTextureHeight := ARci.GLStates.MaxTextureSize;
893
    if FTextureHeight > 512 then
894
      FTextureHeight := 512;
895
    if FTextureHeight < 64 then
896
      FTextureHeight := 64;
897
  end;
898

899
  X := 0;
900
  Y := 0;
901
  w := Glyphs.Width;
902
  h := Glyphs.Height;
903

904
  // was an error...
905
  FTextRows := 1 + (h - 1) div FTextureHeight;
906
  FTextCols := 1 + (w - 1) div FTextureWidth;
907

908
  bitmap := TGLBitmap.Create;
909
  with bitmap do
910
  begin
911
{$IFDEF MSWINDOWS}
912
    // due to lazarus doesn't properly support pixel formats
913
    PixelFormat := glpf32bit;
914
{$ENDIF}
915
{$IFDEF GLS_DELPHI_XE2_UP}
916
    Width  := RoundUpToPowerOf2(FTextureWidth);
917
    Height := RoundUpToPowerOf2(FTextureHeight);
918
{$ELSE}
919
    SetSize(RoundUpToPowerOf2(FTextureWidth),
920
    RoundUpToPowerOf2(FTextureHeight));
921
{$ENDIF}
922
  end;
923

924
  bitmap32 := TGLBitmap32.Create;
925

926
  while (X < w) and (Y < h) do
927
  begin
928
    t := TGLTextureHandle.Create;
929
    FTextures.Add(t);
930
    // prepare handle
931
    t.AllocateHandle;
932
    // texture registration
933
    t.Target := ttTexture2D;
934
    ARci.GLStates.TextureBinding[0, ttTexture2D] := t.Handle;
935

936
    // copy data
937
    bitmap.Canvas.Draw(-X, -Y, Glyphs.Graphic);
938
    // Clipboard.Assign(bitmap);
939
    bitmap32.Assign(bitmap);
940
    bitmap32.Narrow;
941
    with bitmap32 do
942
    begin
943
      case FGlyphsAlpha of
944
        tiaAlphaFromIntensity:
945
          SetAlphaFromIntensity;
946
        tiaSuperBlackTransparent:
947
          SetAlphaTransparentForColor($000000);
948
        tiaLuminance:
949
          SetAlphaFromIntensity;
950
        tiaLuminanceSqrt:
951
          begin
952
            SetAlphaFromIntensity;
953
            SqrtAlpha;
954
          end;
955
        tiaOpaque:
956
          SetAlphaToValue(255);
957
        tiaDefault, tiaTopLeftPointColorTransparent:
958
          SetAlphaTransparentForColor(Data[Width * (Height - 1)]);
959
      else
960
        Assert(False);
961
      end;
962
      RegisterAsOpenGLTexture(t, not(FMinFilter in [miNearest, miLinear]),
963
        TextureFormat, cap, cap, cap);
964
    end;
965

966
    PrepareParams(ARci);
967
    t.NotifyDataUpdated;
968

969
    Inc(X, FTextureWidth);
970
    if X >= w then
971
    begin
972
      Inc(Y, FTextureHeight);
973
      X := 0;
974
    end;
975
  end;
976
  bitmap.Free;
977
  bitmap32.Free;
978
end;
979

980
// PrepareParams
981
//
982
procedure TGLCustomBitmapFont.PrepareParams(var ARci: TGLRenderContextInfo);
983
const
984
  cTextureMagFilter: array [maNearest .. maLinear] of TGLEnum = (GL_NEAREST,
985
    GL_LINEAR);
986
  cTextureMinFilter: array [miNearest .. miLinearMipmapLinear] of TGLEnum =
987
    (GL_NEAREST, GL_LINEAR, GL_NEAREST_MIPMAP_NEAREST, GL_LINEAR_MIPMAP_NEAREST,
988
    GL_NEAREST_MIPMAP_LINEAR, GL_LINEAR_MIPMAP_LINEAR);
989
begin
990

991
  with ARci.GLStates do
992
  begin
993
    UnpackAlignment := 4;
994
    UnpackRowLength := 0;
995
    UnpackSkipRows := 0;
996
    UnpackSkipPixels := 0;
997
  end;
998

999
  with GL do
1000
  begin
1001
    Hint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
1002

1003
    TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
1004
    TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
1005

1006
    TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
1007
      cTextureMinFilter[FMinFilter]);
1008
    TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
1009
      cTextureMagFilter[FMagFilter]);
1010
  end;
1011
end;
1012

1013
function TGLCustomBitmapFont.TileIndexToChar(aIndex: Integer): WideChar;
1014
begin
1015
  Result := FRanges.TileIndexToChar(aIndex);
1016
end;
1017

1018
function TGLCustomBitmapFont.CharacterToTileIndex(aChar: WideChar): Integer;
1019
begin
1020
  Result := FRanges.CharacterToTileIndex(aChar);
1021
end;
1022

1023
// RenderString
1024
//
1025
procedure TGLCustomBitmapFont.RenderString(var ARci: TGLRenderContextInfo;
1026
  const aText: UnicodeString; aAlignment: TAlignment; aLayout: TGLTextLayout;
1027
  const aColor: TColorVector; aPosition: PVector = nil;
1028
  aReverseY: boolean = False);
1029

1030
  function AlignmentAdjustement(p: Integer): Single;
1031
  var
1032
    i: Integer;
1033
  begin
1034
    i := 0;
1035
    while (p <= Length(aText)) and (aText[p] <> #13) do
1036
    begin
1037
      Inc(p);
1038
      Inc(i);
1039
    end;
1040
    case aAlignment of
1041
      taLeftJustify:
1042
        Result := 0;
1043
      taRightJustify:
1044
        Result := -CalcStringWidth(Copy(aText, p - i, i))
1045
    else // taCenter
1046
      Result := Round(-CalcStringWidth(Copy(aText, p - i, i)) * 0.5);
1047
    end;
1048
  end;
1049

1050
  function LayoutAdjustement: Single;
1051
  var
1052
    i, n: Integer;
1053
  begin
1054
    n := 1;
1055
    for i := 1 to Length(aText) do
1056
      if aText[i] = #13 then
1057
        Inc(n);
1058
    case TGLTextLayout(aLayout) of
1059
      tlTop:
1060
        Result := 0;
1061
      tlBottom:
1062
        Result := (n * (CharHeight + VSpace) - VSpace);
1063
    else // tlCenter
1064
      Result := Round((n * (CharHeight + VSpace) - VSpace) * 0.5);
1065
    end;
1066
  end;
1067

1068
var
1069
  i, chi: Integer;
1070
  pch: PCharInfo;
1071
  TopLeft, BottomRight: TTexPoint;
1072
  vTopLeft, vBottomRight: TVector;
1073
  deltaV, spaceDeltaH: Single;
1074
  currentChar: WideChar;
1075
begin
1076
  if (aText = '') then
1077
    Exit;
1078
  // prepare texture if necessary
1079
  CheckTexture(ARci);
1080
  // precalcs
1081
  if Assigned(aPosition) then
1082
    MakePoint(vTopLeft, aPosition.V[0] + AlignmentAdjustement(1),
1083
      aPosition.V[1] + LayoutAdjustement, 0)
1084
  else
1085
    MakePoint(vTopLeft, AlignmentAdjustement(1), LayoutAdjustement, 0);
1086
  deltaV := -(CharHeight + VSpace);
1087
  if aReverseY then
1088
    vBottomRight.V[1] := vTopLeft.V[1] + CharHeight
1089
  else
1090
    vBottomRight.V[1] := vTopLeft.V[1] - CharHeight;
1091
  vBottomRight.V[2] := 0;
1092
  vBottomRight.V[3] := 1;
1093
  spaceDeltaH := GetCharWidth(#32) + HSpaceFix + HSpace;
1094
  // set states
1095
  with ARci.GLStates do
1096
  begin
1097
    ActiveTextureEnabled[ttTexture2D] := true;
1098
    Disable(stLighting);
1099
    Enable(stBlend);
1100
    SetBlendFunc(bfSrcAlpha, bfOneMinusSrcAlpha);
1101
    FLastTexture := nil;
1102
  end;
1103

1104
  // start rendering
1105
  GL.Color4fv(@aColor);
1106
  GL.Begin_(GL_QUADS);
1107
  for i := 1 to Length(aText) do
1108
  begin
1109
    currentChar := WideChar(aText[i]);
1110
    case currentChar of
1111
      #0 .. #12, #14 .. #31:
1112
        ; // ignore
1113
      #13:
1114
        begin
1115
          if Assigned(aPosition) then
1116
            vTopLeft.V[0] := aPosition.V[0] + AlignmentAdjustement(i + 1)
1117
          else
1118
            vTopLeft.V[0] := AlignmentAdjustement(i + 1);
1119
          vTopLeft.V[1] := vTopLeft.V[1] + deltaV;
1120
          if aReverseY then
1121
            vBottomRight.V[1] := vTopLeft.V[1] + CharHeight
1122
          else
1123
            vBottomRight.V[1] := vTopLeft.V[1] - CharHeight;
1124
        end;
1125
      #32:
1126
        vTopLeft.V[0] := vTopLeft.V[0] + spaceDeltaH;
1127
    else
1128
      chi := CharacterToTileIndex(currentChar);
1129
      if chi < 0 then
1130
        continue; // not found
1131
      pch := @FChars[chi];
1132
      if pch.w > 0 then
1133
        with GL do
1134
        begin
1135
          GetICharTexCoords(ARci, chi, TopLeft, BottomRight);
1136
          vBottomRight.V[0] := vTopLeft.V[0] + pch.w;
1137

1138
          TexCoord2fv(@TopLeft);
1139
          Vertex4fv(@vTopLeft);
1140

1141
          TexCoord2f(TopLeft.S, BottomRight.t);
1142
          Vertex2f(vTopLeft.V[0], vBottomRight.V[1]);
1143

1144
          TexCoord2fv(@BottomRight);
1145
          Vertex4fv(@vBottomRight);
1146

1147
          TexCoord2f(BottomRight.S, TopLeft.t);
1148
          Vertex2f(vBottomRight.V[0], vTopLeft.V[1]);
1149

1150
          vTopLeft.V[0] := vTopLeft.V[0] + pch.w + HSpace;
1151
        end;
1152
    end;
1153
  end;
1154
  GL.End_;
1155
  // unbind texture
1156
  ARci.GLStates.TextureBinding[0, ttTexture2D] := 0;
1157
  ARci.GLStates.ActiveTextureEnabled[ttTexture2D] := False;
1158
end;
1159

1160
// TextOut
1161
//
1162
procedure TGLCustomBitmapFont.TextOut(var rci: TGLRenderContextInfo; X, Y: Single;
1163
  const Text: UnicodeString; const Color: TColorVector);
1164
var
1165
  V: TVector;
1166
begin
1167
  V.X := X;
1168
  V.Y := Y;
1169
  V.Z := 0;
1170
  V.w := 1;
1171
  RenderString(rci, Text, taLeftJustify, tlTop, Color, @V, true);
1172
end;
1173

1174
// TextOut
1175
//
1176

1177
procedure TGLCustomBitmapFont.TextOut(var rci: TGLRenderContextInfo; X, Y: Single;
1178
  const Text: UnicodeString; const Color: TColor);
1179
begin
1180
  TextOut(rci, X, Y, Text, ConvertWinColor(Color));
1181
end;
1182

1183
// TextWidth
1184
//
1185
function TGLCustomBitmapFont.TextWidth(const Text: UnicodeString): Integer;
1186
begin
1187
  Result := CalcStringWidth(Text);
1188
end;
1189

1190
// CharactersPerRow
1191
//
1192
function TGLCustomBitmapFont.CharactersPerRow: Integer;
1193
begin
1194
  if FGlyphs.Width > 0 then
1195
    Result := (FGlyphs.Width + FGlyphsIntervalX)
1196
      div (FGlyphsIntervalX + FCharWidth)
1197
  else
1198
    Result := 0;
1199
end;
1200

1201
function TGLCustomBitmapFont.CharacterCount: Integer;
1202
begin
1203
  Result := FRanges.CharacterCount;
1204
end;
1205

1206
procedure TGLCustomBitmapFont.GetCharTexCoords(Ch: WideChar;
1207
  var TopLeft, BottomRight: TTexPoint);
1208
var
1209
  chi, tileIndex: Integer;
1210
  ci: TCharInfo;
1211
  r: Integer;
1212
begin
1213
  chi := CharacterToTileIndex(ch);
1214
  if not FCharsLoaded then
1215
  begin
1216
    ResetCharWidths;
1217
    FCharsLoaded := true;
1218
    r := CharactersPerRow;
1219
    for tileIndex := 0 to CharacterCount - 1 do
1220
    begin
1221
      FChars[tileIndex].l := (tileIndex mod r) * (CharWidth + GlyphsIntervalX);
1222
      FChars[tileIndex].t := (tileIndex div r) * (CharHeight + GlyphsIntervalY);
1223
    end;
1224
  end;
1225

1226
  if (chi < 0) or (chi >= CharacterCount) then
1227
  begin
1228
    // invalid char
1229
    TopLeft := NullTexPoint;
1230
    BottomRight := NullTexPoint;
1231
    Exit;
1232
  end;
1233

1234
  ci := FChars[chi];
1235
  ci.l := ci.l mod FTextureWidth;
1236
  ci.t := ci.t mod FTextureHeight;
1237

1238
  TopLeft.S := ci.l / FTextureWidth;
1239
  TopLeft.t := 1 - ci.t / FTextureHeight;
1240
  BottomRight.S := (ci.l + ci.w) / FTextureWidth;
1241
  BottomRight.t := 1 - (ci.t + CharHeight) / FTextureHeight;
1242
end;
1243

1244
// TileIndexToTexCoords
1245
// it also activates the target texture
1246
//
1247
procedure TGLCustomBitmapFont.GetICharTexCoords(var ARci: TGLRenderContextInfo;
1248
  Chi: Integer; out TopLeft, BottomRight: TTexPoint);
1249
var
1250
  tileIndex: Integer;
1251
  ci: TCharInfo;
1252
  t: TGLTextureHandle;
1253
  r, c: Integer;
1254
begin
1255
  if not FCharsLoaded then
1256
  begin
1257
    r := CharactersPerRow;
1258
    if r = 0 then
1259
      Exit;
1260
    ResetCharWidths;
1261
    FCharsLoaded := true;
1262
    for tileIndex := 0 to CharacterCount - 1 do
1263
    begin
1264
      FChars[tileIndex].l := (tileIndex mod r) * (CharWidth + GlyphsIntervalX);
1265
      FChars[tileIndex].t := (tileIndex div r) * (CharHeight + GlyphsIntervalY);
1266
    end;
1267
  end;
1268

1269
  if (chi < 0) or (chi >= CharacterCount) then
1270
  begin
1271
    // invalid char
1272
    TopLeft := NullTexPoint;
1273
    BottomRight := NullTexPoint;
1274
    Exit;
1275
  end;
1276

1277
  ci := FChars[chi];
1278

1279
  c := ci.l div FTextureWidth;
1280
  r := ci.t div FTextureHeight;
1281
  ci.l := ci.l mod FTextureWidth;
1282
  ci.t := ci.t mod FTextureHeight;
1283
  t := FTextures[r * FTextCols + c];
1284

1285
  TopLeft.S := ci.l / FTextureWidth;
1286
  TopLeft.t := 1 - ci.t / FTextureHeight;
1287
  BottomRight.S := (ci.l + ci.w) / FTextureWidth;
1288
  BottomRight.t := 1 - (ci.t + CharHeight) / FTextureHeight;
1289

1290
  if t <> FLastTexture then
1291
    with GL do
1292
    begin
1293
      FLastTexture := t;
1294
      End_;
1295
      ARci.GLStates.TextureBinding[0, ttTexture2D] := t.Handle;
1296
      TexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
1297
      Begin_(GL_QUADS);
1298
    end;
1299
end;
1300

1301
// InvalidateUsers
1302
//
1303
procedure TGLCustomBitmapFont.InvalidateUsers;
1304
var
1305
  i: Integer;
1306
begin
1307
  FCharsLoaded := False;
1308
  FTextureModified := true;
1309
  for i := FUsers.Count - 1 downto 0 do
1310
    TGLBaseSceneObject(FUsers[i]).NotifyChange(Self);
1311
end;
1312

1313
// FreeTextureHandle
1314
//
1315
procedure TGLCustomBitmapFont.FreeTextureHandle;
1316
var
1317
  i: Integer;
1318
begin
1319
  FTextureModified := true;
1320
  for i := 0 to FTextures.Count - 1 do
1321
    TObject(FTextures[i]).Free;
1322
  FTextures.Clear;
1323
end;
1324

1325
procedure TGLCustomBitmapFont.TextureChanged;
1326
begin
1327
  FTextureModified := true;
1328
end;
1329

1330
// force texture when needed
1331
procedure TGLCustomBitmapFont.CheckTexture(var ARci: TGLRenderContextInfo);
1332
var
1333
  i: Integer;
1334
begin
1335
  // important: IsDataNeedUpdate might come from another source!
1336
  for i := 0 to FTextures.Count - 1 do
1337
    FTextureModified := FTextureModified or TGLTextureHandle(FTextures[i])
1338
      .IsDataNeedUpdate;
1339

1340
  if FTextureModified then
1341
  begin
1342
    FreeTextureHandle; // instances are recreated in prepare
1343
    PrepareImage(ARci);
1344
    FTextureModified := False;
1345
  end;
1346
end;
1347

1348
// TextureFormat
1349
//
1350
function TGLCustomBitmapFont.TextureFormat: Integer;
1351
begin
1352
  Result := GL_RGBA;
1353
end;
1354

1355
// ------------------
1356
// ------------------ TGLFlatText ------------------
1357
// ------------------
1358

1359
// Create
1360
//
1361
constructor TGLFlatText.Create(AOwner: TComponent);
1362
begin
1363
  inherited;
1364
  ObjectStyle := ObjectStyle + [osDirectDraw, osNoVisibilityCulling];
1365
  FModulateColor := TGLColor.CreateInitialized(Self, clrWhite);
1366
end;
1367

1368
// Destroy
1369
//
1370
destructor TGLFlatText.Destroy;
1371
begin
1372
  FModulateColor.Free;
1373
  BitmapFont := nil;
1374
  inherited;
1375
end;
1376

1377
// Notification
1378
//
1379
procedure TGLFlatText.Notification(AComponent: TComponent;
1380
  Operation: TOperation);
1381
begin
1382
  if (Operation = opRemove) and (AComponent = FBitmapFont) then
1383
    BitmapFont := nil;
1384
  inherited;
1385
end;
1386

1387
// SetBitmapFont
1388
//
1389
procedure TGLFlatText.SetBitmapFont(const val: TGLCustomBitmapFont);
1390
begin
1391
  if val <> FBitmapFont then
1392
  begin
1393
    if Assigned(FBitmapFont) then
1394
      FBitmapFont.UnRegisterUser(Self);
1395
    FBitmapFont := val;
1396
    if Assigned(FBitmapFont) then
1397
    begin
1398
      FBitmapFont.RegisterUser(Self);
1399
      FBitmapFont.FreeNotification(Self);
1400
    end;
1401
    StructureChanged;
1402
  end;
1403
end;
1404

1405
// SetText
1406
//
1407
procedure TGLFlatText.SetText(const val: UnicodeString);
1408
begin
1409
  FText := val;
1410
  StructureChanged;
1411
end;
1412

1413
// SetAlignment
1414
//
1415
procedure TGLFlatText.SetAlignment(const val: TAlignment);
1416
begin
1417
  FAlignment := val;
1418
  StructureChanged;
1419
end;
1420

1421
// SetLayout
1422
//
1423
procedure TGLFlatText.SetLayout(const val: TGLTextLayout);
1424
begin
1425
  FLayout := val;
1426
  StructureChanged;
1427
end;
1428

1429
// SetModulateColor
1430
//
1431
procedure TGLFlatText.SetModulateColor(const val: TGLColor);
1432
begin
1433
  FModulateColor.Assign(val);
1434
end;
1435

1436
// SetOptions
1437
//
1438
procedure TGLFlatText.SetOptions(const val: TGLFlatTextOptions);
1439
begin
1440
  if val <> FOptions then
1441
  begin
1442
    FOptions := val;
1443
    StructureChanged;
1444
  end;
1445
end;
1446

1447
// DoRender
1448
//
1449
procedure TGLFlatText.DoRender(var rci: TGLRenderContextInfo;
1450
  renderSelf, renderChildren: boolean);
1451
begin
1452
  if Assigned(FBitmapFont) and (Text <> '') then
1453
  begin
1454
    rci.GLStates.PolygonMode := pmFill;
1455
    if FModulateColor.Alpha <> 1 then
1456
    begin
1457
      rci.GLStates.Enable(stBlend);
1458
      rci.GLStates.SetBlendFunc(bfSrcAlpha, bfOneMinusSrcAlpha);
1459
    end;
1460
    if ftoTwoSided in FOptions then
1461
      rci.GLStates.Disable(stCullFace);
1462
    FBitmapFont.RenderString(rci, Text, FAlignment, FLayout,
1463
      FModulateColor.Color);
1464
  end;
1465
  if Count > 0 then
1466
    Self.renderChildren(0, Count - 1, rci);
1467
end;
1468

1469
 
1470
//
1471
procedure TGLFlatText.Assign(Source: TPersistent);
1472
begin
1473
  if Assigned(Source) and (Source is TGLFlatText) then
1474
  begin
1475
    BitmapFont := TGLFlatText(Source).BitmapFont;
1476
    Text := TGLFlatText(Source).Text;
1477
    Alignment := TGLFlatText(Source).Alignment;
1478
    Layout := TGLFlatText(Source).Layout;
1479
    ModulateColor := TGLFlatText(Source).ModulateColor;
1480
    Options := TGLFlatText(Source).Options;
1481
  end;
1482
  inherited Assign(Source);
1483
end;
1484

1485
// ------------------------------------------------------------------
1486
// ------------------------------------------------------------------
1487
// ------------------------------------------------------------------
1488

1489
initialization
1490

1491
// ------------------------------------------------------------------
1492
// ------------------------------------------------------------------
1493
// ------------------------------------------------------------------
1494

1495
// class registrations
1496
RegisterClasses([TGLBitmapFont, TGLFlatText]);
1497

1498
end.
1499

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.