unit iz_font;

interface
uses
  OpenGL,
  iz_types,iz_texture;

type
  izFontState = (stFntNone, stFntReady);
  izFontItem = record
    State : izFontState;
    Tex : word;
    fSize : izSize_w;
    List : uint;
  end;

  izFontManager = class
    Tex : zTextureManager;
    Items : array of izFontItem;
    Count : word;

    constructor Create(Texture : zTextureManager);
    destructor Destroy();
    function Load(TexFile: string) : word;
    procedure Delete(id : word);
    procedure Clear();
    function Find() : int;
    procedure Write(id : word; Pos : izPosition_i; Str : string);
  end;

implementation
uses
  iz_gfx,iz_utils;

constructor izFontManager.Create(Texture : zTextureManager);
begin
  Tex := Texture;
  Count := 0;
  SetLength(Items, Count);
end;

destructor izFontManager.Destroy();
begin
  Clear();
end;

function izFontManager.Load(TexFile : string) : word;
var
  f : file;
  i : int;
  tSize : izSize_w;
  buf : string;
  PatternSize : izSize_w;
  PatternX, PatternY : word;
  id : int;
begin
  if not FileExists(TexFile) then
  begin
    gfx.MsgErr('File '+TexFile+' no exist.');
    exit;
  end;

  id := Find();
  if id < 0 then
  begin
    id := Count;
    inc(Count);
    SetLength(Items, Count);
  end;

  // Загружаем текстуру
  Items[id].Tex := Tex^.Load(TexFile);
  tSize := Tex^.GetSize(Items[id].Tex);
  PatternSize[0] := tSize[0] div 16;
  PatternSize[1] := tSize[1] div 16;

  Items[id].fSize := PatternSize;
  // Создём дисплейные списки
  Items[id].List := glGenLists(256);
  for i := 0 to 255 do
  begin
    PatternY := 15-(i div 16);
    PatternX := i mod 16;
    glNewList(Items[id].List+i, GL_COMPILE);       // Start Building A List
    glBegin( GL_QUADS );
      glTexCoord2f( (PatternSize[0]/tSize[0])*PatternX, (PatternSize[1]/tSize[1])*PatternY );      glVertex2f( -(PatternSize[0]/2), (PatternSize[1]/2) );
      glTexCoord2f( (PatternSize[0]/tSize[0])*(PatternX+1), (PatternSize[1]/tSize[1])*PatternY );  glVertex2f( (PatternSize[0]/2), (PatternSize[1]/2) );
      glTexCoord2f( (PatternSize[0]/tSize[0])*(PatternX+1), (PatternSize[1]/tSize[1])*(PatternY+1) );      glVertex2f( (PatternSize[0]/2), -(PatternSize[1]/2) );
      glTexCoord2f( (PatternSize[0]/tSize[0])*PatternX, (PatternSize[1]/tSize[1])*(PatternY+1) );          glVertex2f( -(PatternSize[0]/2), -(PatternSize[1]/2) );
    glEnd();
    glTranslatef(Items[id].fSize[0], 0, 0);
    glEndList();
  end;

  Result := id;
end;

procedure izFontManager.Delete(id : word);
begin
  if id >= Count then exit;
  Tex^.Delete(Items[id].Tex);
  Items[id].State := stFntNone;
end;

procedure izFontManager.Clear();
var
  i : int;
begin
  for i := 0 to Count-1 do
    Tex^.Delete(Items[i].Tex);
  Count := 0;
  SetLength(Items, Count);
end;

function izFontManager.Find() : int;
var
  i : int;
begin
  Result := -1;
  for i := 0 to Count-1 do
    if Items[i].State = stFntNone then
    begin
      Result := i;
      exit;
    end;
end;

procedure izFontManager.Write(id : word; Pos : izPosition_i; Str : string);
begin
  glPushMatrix();
  glEnable(GL_BLEND);
  glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
  glEnable(GL_TEXTURE_2D);
  Tex^.Bind(Items[id].Tex);
  glTranslatef(Pos[0], Pos[1], 0);
  glPushAttrib(GL_LIST_BIT);
  glListBase(Items[id].List);
  glCallLists(Length(Str), GL_UNSIGNED_BYTE, PChar(Str));
  glPopAttrib();
  glDisable(GL_TEXTURE_2D);
  glDisable(GL_BLEND);
  glPopMatrix();
end;

end.
