///////////////////////////////////////////////////////////////////////
// Copyright (C) Andru 2007                                          //
// mail: dr.andru@gmail.com                                          //
// site: http://andru.2x4.ru                                         //
//                                                                   //
// OMEGA Engine is free software.                                    //
//                                                                   //
// You may redistribute it and/or modify it under the terms of the   //
// GNU General Public License, as published by the Free Software     //
// Foundation; either version 2 of the License, or (at your option)  //
// any later version.                                                //
//                                                                   //
// this module is distributed in the hope that it will be useful,    //
// but WITHOUT ANY WARRANTY; without even the implied warranty of    //
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.              //
// See the GNU General Public License for more details.              //
//                                                                   //
// You should have received a copy of the GNU General Public License //
// along with this module.  If not, write to:                        //
// 	The Free Software Foundation, Inc.,                              //
// 	51 Franklin Street, Fifth Floor                                  //
// 	Boston, MA  02110-1301, USA.                                     //
///////////////////////////////////////////////////////////////////////
unit G2D_TEXT;

{$I DEFINES.pas}

interface
uses
  Windows,
  minClasses,
  minFile,
  OpenGL,

  ENGINE_TYPES,
  ENGINE_VAR,
  ENGINE_CONST,

  ENGINE_LOG,
  ENGINE_UTILS,
  ENGINE_FLAGS,

  G2D_FX,

  G2D_CAMERA,
  G2D_PRIMITIVES,
  G2D_CSPRITE,

  TEXTURE_LOADER,
  TEXTURE_MANAGER,
  TEXTURE_EFFECTS,

  MATH_FAST,

  UTILS;

type
  TSymbol = record
    X, Y  : WORD;
    Width : Byte;
end;

type
  TFont2D = record
    Height  : Byte;
    Sizes   : array[ 0..255 ] of TSymbol;
    Texture : PTexture;
    Next    : Pointer;
end;
PFont2D = ^TFont2D;

var
  FontManager : PFont2D;
  FontCount   : Integer;

function Text_LoadFontFromFile( FontTexture      : PChar;
                                FontInfo         : PChar;
                                TransparentColor : Integer;
                                TexFlags         : Integer ) : PFont2D; stdcall;
function Text_LoadFontFromMemory( FontTexture      : PMemory;
                                  FontTexType      : Integer;
                                  FontInfo         : PMemory;
                                  TransparentColor : Integer;
                                  TexFlags         : Integer ) : PFont2D; stdcall;

procedure Text_FreeFont( var Font : PFont2D ); stdcall;
procedure Text_FreeFontAll; stdcall;

procedure Text_Draw( Font  : PFont2D;
                     X, Y  : Single;
                     Text  : PChar;
                     Scale : Single;
                     Step  : Single;
                     Alpha : Byte;
                     Color : Integer ); stdcall;

function Text_GetWidth( Font  : PFont2D;
                        Text  : PChar;
                        Scale : Single;
                        Step  : Single ) : Single; stdcall;

function Font_Add : Pointer; stdcall;


//----------------------------------------------------------------------------//
                                 IMPLEMENTATION
//----------------------------------------------------------------------------//

function Font_Add;
  var
    new : PFont2D;
    i   : Integer;
begin

Result := nil;

new := FontManager;
while new^.Next <> nil do
  new := new^.Next;

Mem_Get( new^.Next, SizeOf( TFont2D ) );
PFont2D( new^.Next )^.Height := 0;
for i := 0 to 255 do
  begin
    PFont2D( new^.Next )^.Sizes[ i ].X := 0;
    PFont2D( new^.Next )^.Sizes[ i ].Y := 0;
    PFont2D( new^.Next )^.Sizes[ i ].Width := 0;
  end;
PFont2D( new^.Next )^.Texture := nil;
PFont2D( new^.Next )^.Next    := nil;

INC( FontCount );
Result := new^.Next;

End;

procedure Text_FreeFont;
  var
    old : PFont2D;
Begin

old := FontManager;
while old^.Next <> Font do
  old := old^.Next;

old^.Next := PFont2D( old^.Next )^.Next;

Tex_Free( old^.Texture );
Mem_Free( old^.Next );

DEC( FontCount );
Font := nil;

if app_Log Then
  LOG_AddMessage( LOGT_APP, LOG_FREE_FONT );

End;

procedure Text_FreeFontAll;
  var
    old : PFont2D;
    i   : DWORD;
Begin
FontCount := -1;
while FontManager <> nil do
  begin
    old := FontManager.Next;
    if FontCount >= 0 Then
      begin
        i := FontManager.Texture.ID;
        glDeleteTextures( 1, @FontManager.Texture.ID );
        Tex_Del( i );
      end;
    Mem_Free( FontManager );
    FontManager := old;
    INC( FontCount );
  end;
  Mem_Get( Pointer( FontManager ), SizeOf( TFont2D ) );
  FontManager^.Next := nil;

if ( app_Log ) and ( FontCount > 0 ) Then
  LOG_AddMessage( LOGT_ENGINE, PChar( LOG_FREE_FONTS + '[' + U_IntToStr( FontCount ) + ']' ) );
End;

function Text_LoadFontFromFile;
  var
    Stm : TMemoryStream;
    i : Integer;
    log : Boolean;
begin

FontInfo := PChar( String( app_Dir ) + String( FontInfo ) );

log     := app_Log;
app_Log := FALSE;

Result := nil;

if not FileExists( FontInfo ) Then
  begin
    E_Error( FNTLOAD + ERR_CANT_FIND_FILE + FontInfo );
    app_Work := FALSE;
    exit;
  end;

Result := Font_Add;

Result^.Texture := Tex_LoadFromFile( FontTexture, TransparentColor, TexFlags );

TempString := FontInfo;
Stm := TMemoryStream.Create;
Stm.LoadFromFile( TempString );
Stm.Seek( 0, 0 );
Stm.Read( Result^.Height, 1 );
for i := 0 to 255 do
  Stm.Read( Result^.Sizes[ i ], SizeOf( TSymbol ) );
Stm.Free;

app_Log := log;                                            
if app_Log Then
  LOG_AddMessage( LOGT_APP, PChar( LOG_LOADING_FONT + '[ ' + FontTexture + ' ][ ' + FontInfo + ' ]' ) ); 
end;

function Text_LoadFontFromMemory;
  var
    Stm   : TMemoryStream;
    i     : Integer;
    log   : Boolean;
begin

log     := app_Log;
app_Log := FALSE;

Result := nil;

if FontInfo^.Ptr = nil Then
  begin
    E_Error( FNTLOAD + ERR_CANT_FONT_LOAD + ERR_CANT_FIND_MEMORY );
    app_Work := FALSE;
    exit;
  end;

Result := Font_Add;

Result^.Texture := Tex_LoadFromMemory( FontTexture, FontTexType, TransparentColor, TexFlags );

Stm := TMemoryStream.Create;
Stm.Write( FontInfo^.Ptr^, FontInfo^.Size );
Stm.Seek( 0, 0 );
Stm.Read( Result^.Height, 1 );
for i := 0 to 255 do
  Stm.Read( Result^.Sizes[ i ], SizeOf( TSymbol ) );

app_Log := log;

if app_Log Then
  LOG_AddMessage( LOGT_APP, PChar( LOG_LOADING_FONT + '[ ' + FROM_MEMORY + ' ][ ' + FROM_MEMORY + ' ]' ) );

end;

procedure Text_Draw;
  var
    i      : Integer;
    oldX   : Single;
    cX, cY : Single;
    cW, cH : Single;
    r      : oeRect;
Begin

if Cam2D^.Active Then
  begin
    X := X - Cam2D^.X;
    Y := Y - Cam2D^.Y;
  end;

oldX := X;

glPushMatrix;

if F_ResolutionCorrect = 1 Then
  glScalef( scr_ScaleX, scr_ScaleY, 1 );

glEnable( GL_BLEND );

if Color <> $FFFFFF Then
  FX_SetColorMix( Color )
else
  FX_SetColorMix( $FFFFFF );
glColor4ub( FX_R, FX_G, FX_B, alpha );

glEnable( GL_TEXTURE_2D );

glBindTexture( GL_TEXTURE_2D, Font.Texture.ID );

if Font.Texture.Flags and TEX_CLAMP > 0 Then
  begin
    glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
    glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );
  end;

glBegin( GL_QUADS );

for i := 0 to Length( Text ) - 1 do
  begin
    if ( Byte( Text[ i ] ) = 13 ) Then
      begin
        Y := Y + Font^.Height * Scale;
        X := oldX;
        continue;
      end else
        if Byte( Text[ i ] ) = 10 Then
          begin
            Y := Y + Font^.Height * Scale;
            X := oldX;
            continue;
          end;

    r.X      := Font^.Sizes[ Byte( Text[ i ] ) ].X;
    r.Y      := Font^.Sizes[ Byte( Text[ i ] ) ].Y;
    r.Width  := Font^.Sizes[ Byte( Text[ i ] ) ].Width;
    r.Height := Font^.Height;

    cX := ( 1 / ( Font.Texture.Width  / Font.Texture.U ) ) * r.X;
    cY := ( 1 / ( Font.Texture.Height / Font.Texture.V ) ) * ( Font.Texture.Height - r.Y );
    cW := cX + ( 1 / ( Font.Texture.Width  / Font.Texture.U ) ) * r.Width;
    cH := cY + ( 1 / ( Font.Texture.Height / Font.Texture.V ) ) * ( - r.Height );

    glTexCoord2f( cX, cY );
    glVertex2f  ( X, Y );

    glTexCoord2f( cW, cY );
    glVertex2f  ( X + r.Width * Scale, Y );

    glTexCoord2f( cW, cH );
    glVertex2f  ( X + r.Width * Scale, Y + r.Height * Scale );

    glTexCoord2f( cX, cH );
    glVertex2f  ( X, Y + r.Height * Scale );

    X := X + Font^.Sizes[ Byte( Text[ i ] ) ].Width * Scale + Step;
  end;

glEnd;

glDisable( GL_TEXTURE_2D );
glDisable( GL_BLEND );

glPopMatrix;

End;

function Text_GetWidth;
  var
    i : Integer;
Begin

Result := 0;
for i := 0 to Length( Text ) - 1 do
  Result := Result + Font^.Sizes[ Byte( Text[ i ] ) ].Width * Scale + Step;

End;

initialization
  Mem_Get( Pointer( FontManager ), SizeOf( TFont2D ) );
  FontManager^.Next := nil;

end.
