aboutsummaryrefslogblamecommitdiffstats
path: root/Game/Code/Classes/TextGL.pas
blob: 5ce3ebf7358953d2b0039f650a690b60b13adcb3 (plain) (tree)
























































































































                                                                                                       


                                                          






                                                                       

                                                           





                                                                        
                                                           





                                                                                
                                                            









































































                                                                                                               





































                                                                                            
 


                              



























































                                                                                          

                         
      

                                                                      
 


                              

                       
                                                    



                           










                                                                 

















































































                                                                              
unit TextGL;

interface

{$IFDEF FPC}
  {$MODE Delphi}
{$ENDIF}


uses  OpenGL12,
      SDL,
      UTexture,
      Classes,
      ULog;

procedure BuildFont;			                // Build Our Bitmap Font
procedure KillFont;     		                // Delete The Font
function  glTextWidth(text: pchar): real;     // Returns Text Width
procedure glPrintDone(text: pchar; Done: real; ColR, ColG, ColB: real);
procedure glPrintLetter(letter: char);
procedure glPrintLetterCut(letter: char; Start, Finish: real);
procedure glPrint(text: pchar);	                  // Custom GL "Print" Routine
procedure glPrintCut(text: pchar);
procedure SetFontPos(X, Y: real);                     // Sets X And Y
procedure SetFontSize(Size: real);
procedure SetFontStyle(Style: integer); // sets active font style (normal, bold, etc)
procedure SetFontItalic(Enable: boolean); // sets italic type letter (works for all fonts)
procedure SetFontAspectW(Aspect: real);

type
  TTextGL = record
    X:        real;
    Y:        real;
    Text:     string;
    Size:     real;
    ColR:     real;
    ColG:     real;
    ColB:     real;
  end;

  TFont = record
    Tex:      TTexture;
    Width:    array[0..255] of byte;
    AspectW:  real;
    Centered: boolean;
    Done:     real;
    Outline:  real;
    Italic:   boolean;
  end;


var
  base:       GLuint;			                // Base Display List For The Font Set
  Fonts:      array of TFont;
  ActFont:    integer;
  PColR:      real;  // temps for glPrintDone
  PColG:      real;
  PColB:      real;

implementation

uses UMain,
     UCommon,
     {$IFDEF win32}
     windows,
     {$ELSE}
     lclintf,
     lcltype,
     {$ENDIF}
     SysUtils,
     {$IFDEF FPC}
     LResources,
     {$ENDIF}
     UGraphic;

procedure BuildFont;			                // Build Our Bitmap Font

  procedure loadfont( aID : integer; aType, aResourceName : String);
  {$IFDEF FPC}
  var
    lLazRes  : TLResource;
    lResData : TStringStream;
  begin
      try
        lLazRes := LazFindResource( aResourceName, aType );
        if lLazRes <> nil then
        begin
          lResData := TStringStream.create( lLazRes.value );
          try
            lResData.position := 0;
            lResData.Read(Fonts[ aID ].Width, 256);
          finally
            freeandnil( lResData );
          end;
        end;
      
  {$ELSE}
  var
    Rejestr:  TResourceStream;
  begin
    try
        Rejestr := TResourceStream.Create(HInstance, aResourceName , pchar( aType ) );
        try
          Rejestr.Read(Fonts[ aID ].Width, 256);
        finally
          Rejestr.Free;
        end;
  {$ENDIF}
      
    except
      Log.LogStatus( 'Could not load font : loadfont( '+ inttostr( aID ) +' , '+aType+' )' , 'ERROR');
    end;
  end;

var
  font:     HFONT;              	          // Windows Font ID
  h_dc:     hdc;
  Pet:      integer;
begin
  ActFont := 0;

  Log.LogStatus( '' , '---------------------------');

  Log.LogStatus( 'Font' , '---------------------------');
  SetLength(Fonts, 5);
  Fonts[0].Tex := Texture.LoadTexture(true, 'Font', 'PNG', 'Font', 0);
  Fonts[0].Tex.H := 30;
  Fonts[0].AspectW := 0.9;
  Fonts[0].Done := -1;
  Fonts[0].Outline := 0;

  Log.LogStatus( 'FontB' , '---------------------------');

  Fonts[1].Tex := Texture.LoadTexture(true, 'FontB', 'PNG', 'Font', 0);
  Fonts[1].Tex.H := 30;
  Fonts[1].AspectW := 1;
  Fonts[1].Done := -1;
  Fonts[1].Outline := 0;

  Log.LogStatus( 'FontO' , '---------------------------');
  Fonts[2].Tex := Texture.LoadTexture(true, 'FontO', 'PNG', 'Font Outline', 0);
  Fonts[2].Tex.H := 30;
  Fonts[2].AspectW := 0.95;
  Fonts[2].Done := -1;
  Fonts[2].Outline := 5;

  Log.LogStatus( 'FontO2' , '---------------------------');
  Fonts[3].Tex := Texture.LoadTexture(true, 'FontO2', 'PNG', 'Font Outline 2', 0);
  Fonts[3].Tex.H := 30;
  Fonts[3].AspectW := 0.95;
  Fonts[3].Done := -1;
  Fonts[3].Outline := 4;

{  Fonts[4].Tex := Texture.LoadTexture('FontO', 'BMP', 'Arrow', 0); // for score screen
  Fonts[4].Tex.H := 30;
  Fonts[4].AspectW := 0.95;
  Fonts[4].Done := -1;
  Fonts[4].Outline := 5;}



  loadfont( 0, 'FNT', 'Font'   );
  loadfont( 1, 'FNT', 'FontB'  );
  loadfont( 2, 'FNT', 'FontO'  );
  loadfont( 3, 'FNT', 'FontO2' );

{  Rejestr := TResourceStream.Create(HInstance, 'FontO', 'FNT');
  Rejestr.Read(Fonts[4].Width, 256);
  Rejestr.Free;}

  for Pet := 0 to 255 do
    Fonts[1].Width[Pet] := Fonts[1].Width[Pet] div 2;

  for Pet := 0 to 255 do
    Fonts[2].Width[Pet] := Fonts[2].Width[Pet] div 2 + 2;

  for Pet := 0 to 255 do
    Fonts[3].Width[Pet] := Fonts[3].Width[Pet] + 1;

{  for Pet := 0 to 255 do
    Fonts[4].Width[Pet] := Fonts[4].Width[Pet] div 2 + 2;}

end;

procedure KillFont;     		                // Delete The Font
begin
//  glDeleteLists(base, 256); 		                // Delete All 96 Characters
end;

function glTextWidth(text: pchar): real;
var
  Letter:       char;
begin
//  Log.LogStatus(Text, 'glTextWidth');
  Result := 0;
  while (length(text) > 0) do begin
    Letter := Text[0];
    text := pchar(Copy(text, 2, Length(text)-1));
    Result := Result + Fonts[ActFont].Width[Ord(Letter)] * Fonts[ActFont].Tex.H / 30 * Fonts[ActFont].AspectW;
  end; // while
end;

procedure glPrintDone(text: pchar; Done: real; ColR, ColG, ColB: real);
begin
  Fonts[ActFont].Done := Done;
  PColR := ColR;
  PColG := ColG;
  PColB := ColB;
  glPrintCut(text);
  Fonts[ActFont].Done := -1;
end;

procedure glPrintLetter(Letter: char);
var
  TexX, TexY:   real;
  TexR, TexB:   real;
  FWidth:       real;
  PL, PT:       real;
  PR, PB:       real;
  XItal:        real; // X shift for italic type letter
begin
  with Fonts[ActFont].Tex do
  begin
    FWidth := Fonts[ActFont].Width[Ord(Letter)];

    W := FWidth * (H/30) * Fonts[ActFont].AspectW;
  //  H := 30;

    // set texture positions
    TexX := (ord(Letter) mod 16) * 1/16 + 1/32 - FWidth/1024 - Fonts[ActFont].Outline/1024;
    TexY := (ord(Letter) div 16) * 1/16 + 2/1024; // 2/1024
    TexR := (ord(Letter) mod 16) * 1/16 + 1/32 + FWidth/1024 + Fonts[ActFont].Outline/1024;
    TexB := (1 + ord(Letter) div 16) * 1/16 - 2/1024;

    // set vector positions
    PL := X - Fonts[ActFont].Outline * (H/30) * Fonts[ActFont].AspectW /2;
    PT := Y;
    PR := PL + W + Fonts[ActFont].Outline * (H/30) * Fonts[ActFont].AspectW;
    PB := PT + H;

    if Fonts[ActFont].Italic = false then
      XItal := 0
    else
      XItal := 12;

    glEnable(GL_TEXTURE_2D);
    glEnable(GL_BLEND);
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
    glBindTexture(GL_TEXTURE_2D, TexNum);

    glBegin(GL_QUADS);
    try
      glTexCoord2f(TexX, TexY); glVertex2f(PL+XItal,  PT);
      glTexCoord2f(TexX, TexB); glVertex2f(PL,        PB);
      glTexCoord2f(TexR, TexB); glVertex2f(PR,        PB);
      glTexCoord2f(TexR, TexY); glVertex2f(PR+XItal,  PT);
    finally
      glEnd;
    end;

    X := X + W;
    glDisable(GL_BLEND);
    glDisable(GL_TEXTURE_2D);
  end; // with
end;

procedure glPrintLetterCut(letter: char; Start, Finish: real);
var
  TexX, TexY:   real;
  TexR, TexB:   real;
  TexTemp:      real;
  FWidth:       real;
  PL, PT:       real;
  PR, PB:       real;
  OutTemp:      real;
  XItal:        real;
begin
  with Fonts[ActFont].Tex do begin
  FWidth := Fonts[ActFont].Width[Ord(Letter)];

  W := FWidth * (H/30) * Fonts[ActFont].AspectW;
//  H := 30;
  OutTemp := Fonts[ActFont].Outline * (H/30) * Fonts[ActFont].AspectW;

  // set texture positions
  TexX := (ord(Letter) mod 16) * 1/16 + 1/32 - FWidth/1024 - Fonts[ActFont].Outline/1024;
  TexY := (ord(Letter) div 16) * 1/16 + 2/1024; // 2/1024
  TexR := (ord(Letter) mod 16) * 1/16 + 1/32 + FWidth/1024 + Fonts[ActFont].Outline/1024;
  TexB := (1 + ord(Letter) div 16) * 1/16 - 2/1024;

  TexTemp := TexX + Start * (TexR - TexX);
  TexR := TexX + Finish * (TexR - TexX);
  TexX := TexTemp;

  // set vector positions
  PL := X - OutTemp / 2 + OutTemp * Start;
  PT := Y;
  PR := PL + (W + OutTemp) * (Finish - Start);
  PB := PT + H;
  if Fonts[ActFont].Italic = false then
    XItal := 0
  else
    XItal := 12;

  glEnable(GL_TEXTURE_2D);
  glEnable(GL_BLEND);
  glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
  glBindTexture(GL_TEXTURE_2D, TexNum);
  glBegin(GL_QUADS);
    glTexCoord2f(TexX, TexY); glVertex2f(PL+XItal,  PT);
    glTexCoord2f(TexX, TexB); glVertex2f(PL,        PB);
    glTexCoord2f(TexR, TexB); glVertex2f(PR,        PB);
    glTexCoord2f(TexR, TexY); glVertex2f(PR+XItal,  PT); // not tested with XItal
  glEnd;
  X := X + W * (Finish - Start);
  glDisable(GL_BLEND);
  glDisable(GL_TEXTURE_2D);
  end; // with

end;

procedure glPrint(text: pchar);	                // Custom GL "Print" Routine
var
//  Letter :       char;
  iPos   : Integer;
begin
  if (Text = '') then     // If There's No Text
    Exit;					        // Do Nothing

(*
  while (length(text) > 0) do
  begin
    // cut
    Letter := Text[0];
    Text   := pchar(Copy(Text, 2, Length(Text)-1));

    // print
    glPrintLetter(Letter);
  end; // while
*)

  // This code is better, because doing a Copy of for every
  // letter in a string is a waste of CPU & Memory resources.
  // Copy operations are quite memory intensive, and this simple
  // code achieves the same result.
  for iPos := 0 to length( text ) - 1 do
  begin
    glPrintLetter( Text[iPos] );
  end;

end;

procedure glPrintCut(text: pchar);
var
  Letter:       char;
  PToDo:        real;
  PTotWidth:    real;
  PDoingNow:    real;
  S:            string;
begin
  if (Text = '') then   			        // If There's No Text
                Exit;					        // Do Nothing

  PTotWidth := glTextWidth(Text);
  PToDo := Fonts[ActFont].Done;

  while (length(text) > 0) do begin
    // cut
    Letter := Text[0];
    Text := pchar(Copy(Text, 2, Length(Text)-1));

    // analyze
    S := Letter;
    PDoingNow := glTextWidth(pchar(S)) / PTotWidth;

    // drawing
    if (PToDo > 0) and (PDoingNow <= PToDo) then
      glPrintLetter(Letter);

    if (PToDo > 0) and (PDoingNow > PToDo) then begin
      glPrintLetterCut(Letter, 0, PToDo / PDoingNow);
      glColor3f(PColR, PColG,  PColB);
      glPrintLetterCut(Letter, PToDo / PDoingNow, 1);
    end;

    if (PToDo <= 0) then
      glPrintLetter(Letter);

    PToDo := PToDo - PDoingNow;

  end; // while
end;


procedure SetFontPos(X, Y: real);
begin
  Fonts[ActFont].Tex.X := X;
  Fonts[ActFont].Tex.Y := Y;
end;

procedure SetFontSize(Size: real);
begin
  Fonts[ActFont].Tex.H := 30 * (Size/10);
end;

procedure SetFontStyle(Style: integer);
begin
  ActFont := Style;
end;

procedure SetFontItalic(Enable: boolean);
begin
  Fonts[ActFont].Italic := Enable;
end;

procedure SetFontAspectW(Aspect: real);
begin
  Fonts[ActFont].AspectW := Aspect;
end;


{$IFDEF FPC}
{$IFDEF win32}
initialization
  {$I UltraStar.lrs}
{$ENDIF}
{$ENDIF}


end.