{****************************************************************************}
{Unit VENOMMNG - it is a helper unit for graphics library VenomGFX.          }
{It is not intended to be called by user, because it is used internaly by    }
{      image and font loaders                                                }
{****************************************************************************}
unit VenomMng;
{$IFDEF VER2}{$DEFINE NEWFPC}{$ENDIF}
{$IFDEF VER3}{$DEFINE NEWFPC}{$ENDIF}
{$IFDEF NEWFPC}{$CALLING OLDFPCCALL}{$ENDIF}

interface

const venom_image_loaders = 12;
      venom_font_loaders = 16;
      max_venom_font = 70;       {max. pocet sad pismen}
      max_co_volat_po_init_graph = 12;

type po_init_graph = procedure;

var Venom_Image_Mng:record
    pocet:byte;  {pocet registrovanych koncovek souboru}
    koncovka:array[1..venom_image_loaders] of string[3];
    loader:array[1..venom_image_loaders] of pointer;
    end;

    Venom_FontEngines_pocet:byte; {pocet registrovanych koncovek souboru}

    Venom_FontEngines_Mng:array[1..venom_font_loaders] of record
    koncovka:string[4]; {aby to obsahlo i umele koncovky jako _HW_}
    loadproc:pointer;
    prepchar:pointer;
    outstring:pointer;
    setparams:pointer;
    getinfo:pointer;
    deleteproc:pointer;
    end;

    LoadedFontList:array[1..max_venom_font] of record
    rez:^string;
    typ:byte; {cislo FontEngine ve Venom_FontEngines_Mng}
    fontptr:pointer;
    end;


    Venom_co_volat_po_Init_Graph:array[1..max_co_volat_po_init_graph] of po_init_graph;


Procedure RegisterImageLoader(s:string;p:pointer);
Function Get_Image_Loader(s:string):pointer;

Procedure RegisterFontEngine(s:string;loadproc,prepchar,outproc,paramsproc,getinfo,delproc:pointer);
Function Zda_je_registrovany_rez_fontu(s,forceeng:string;var enginenum:byte):longint;
Function Venom_mng_PrepChar(znak:word):pointer;
Function Venom_mng_SetFontStyle(rez:string;velikost,parametry:longint):longint;
{"<rez> muze obsahovat hvezdicku jako napr.: 'cour18.xx*fn'.
 To "*fn" znamena, ze se pouzije loader FN, i kdyz ma soubor priponu XX.}
Procedure Venom_mng_outstring(kam:pointer;x,y:longint;s:string;color:word);
Function Venom_mng_GetFontInfo(param1,param2:longint):longint;
Function Venom_mng_kill_font(rez:string):longint;
Function Venom_mng_kill_font_internal2(index:longint;mode:byte):longint;
Function Venom_mng_kill_font_internal(const rez:string;velikost,mode:byte):longint;

Function Venom_mng_kill_subfont(rez:string;velikost:byte):longint;
Function Venom_mng_Init_graph_list(p:po_init_graph):longint;

Function Venom_mng_GetNumLoadedFontBitmaps:longint;
Function Venom_mng_GetActFontSlot:longint;
Function Venom_mng_SetActFontSlot(a:longint):longint;
Function Venom_mng_GetFontPtr(a:longint):pointer;
Function Venom_mng_GetFontSlot_by_name(s:string;num:longint):longint;
Function Venom_mng_GetActFontPtr:pointer;
Function Venom_mng_GetFontPtrSlot(p:pointer):longint;

Function Venom_mng_Get_Image_Loader_Index(s:string):longint;

implementation
var
LoadedFontNum:byte;
aktfontvel:byte;
aktinit_graphslot:byte;
aktfontslot:longint;

type
loadfontfunc=Function(s:string;size:longint):pointer;
{vrati odkaz na sadu bitmapovych pismen v zadanem rezu a velikosti}

prepcharfunc=Function(fnt:pointer;znak:word):pointer;

outfontproc=Procedure(kam:pointer;x,y:longint;s:string;fnt:pointer;color:word);
{fnt je odkaz na sadu bitmapovych pismen v definovanem rezu a velikosti}

setparamsfunc=Function(fnt:pointer;param1,param2,param3:longint):pointer;
getinfofunc=Function(fnt:pointer;param1,param2:longint):longint;
removefontproc=Function(fnt:pointer;mode:byte):boolean;


Procedure StartUnit;
{Je volano automaticky pri startu jednotky}
var a:byte;
begin
{vynulujeme loadery obrazku}
Venom_Image_Mng.pocet:=0;
for a:=1 to venom_image_loaders do
    begin
    Venom_Image_Mng.koncovka[a]:='';
    Venom_Image_Mng.loader[a]:=nil;
    end;

{vynulujeme engine na fonty}
Venom_FontEngines_pocet:=0;
for a:=1 to venom_font_loaders do
    begin
    Venom_FontEngines_Mng[a].koncovka:='';
    Venom_FontEngines_Mng[a].loadproc:=nil;
    Venom_FontEngines_Mng[a].outstring:=nil;
    Venom_FontEngines_Mng[a].setparams:=nil;
    Venom_FontEngines_Mng[a].getinfo:=nil;
    Venom_FontEngines_Mng[a].deleteproc:=nil;
    end;

{a vynulujeme samotnou tabulku fontu}
LoadedFontNum:=0;
for a:=1 to max_venom_font do
    begin
    LoadedFontList[a].typ:=0;
    LoadedFontList[a].fontptr:=nil;
    LoadedFontList[a].rez:=nil;
    end;

aktfontvel:=16;
aktfontslot:=0;

{vynuluju seznam procedur, ktere automaticky volat po prvnim VenomGFX.Init_Graph}
aktinit_graphslot:=0;
for a:=1 to max_co_volat_po_init_graph do
    Venom_co_volat_po_Init_Graph[a]:=nil;

end;


Procedure RegisterImageLoader(s:string;p:pointer);
{Toto je volano automaticky pri startu jednotlivych jednotek obsahujicich
 loadery obrazku}
var a:byte;
begin
for a:=1 to Length(s) do s[a]:=UpCase(s[a]);
for a:=1 to Venom_Image_Mng.pocet do  {napred zkontroluju, jestli neni dany}
    if Venom_Image_Mng.koncovka[a]=s then{typ uz zaregistrovan}
       begin  {jestli jo, tak preregistruju}
       Venom_Image_Mng.loader[a]:=p;
       Exit;
       end;
{zjistili jsme, ze dany loader jeste registrovan neni}
inc(Venom_Image_Mng.pocet);
a:=Venom_Image_Mng.pocet;
Venom_Image_Mng.koncovka[a]:=s;
Venom_Image_Mng.loader[a]:=p;
end;


Function Get_Image_Loader(s:string):pointer;
{Je volano z jednotky VenomGFX z obecneho nacitace obrazku}
var a:byte;
begin
for a:=1 to Length(s) do s[a]:=UpCase(s[a]);
for a:=1 to Venom_Image_Mng.pocet do
    if Venom_Image_Mng.koncovka[a]=s then Exit(Venom_Image_Mng.loader[a]);
Get_Image_Loader:=nil;
end;


Procedure RegisterFontEngine(s:string;loadproc,prepchar,outproc,paramsproc,getinfo,delproc:pointer);
{Toto je volano automaticky pri startu jednotlivych jednotek obhaspodarujich
 konkratni fonty}
var a:byte;
begin

{debug}
{writeln('FontEngine:  registruji: ',s);}
{//debug}

inc(Venom_FontEngines_pocet);
a:=Venom_FontEngines_pocet;

Venom_FontEngines_Mng[a].koncovka:=s;

Venom_FontEngines_Mng[a].loadproc:=loadproc;
Venom_FontEngines_Mng[a].prepchar:=prepchar;
Venom_FontEngines_Mng[a].outstring:=outproc;
Venom_FontEngines_Mng[a].setparams:=paramsproc;
Venom_FontEngines_Mng[a].getinfo:=getinfo;
Venom_FontEngines_Mng[a].deleteproc:=delproc;
end;


Function Zda_je_registrovany_rez_fontu(s,forceeng:string;var enginenum:byte):longint;
{predpoklada, ze S je velkymi pismeny}
{Pokud je ForceEng '', tak detekuje spravny loader podle pripony. V opacnem
 pripade podle ForceEng.
 Diky tomu je mozne nahravat soubory s nestandardnimi koncovkami.
 Napr: "SetFontStyle('cour18.xx*fn',16);)"
 to "*fn" znamena, ze se ma pouzit loader FN formatu.}


var a,b,e:longint;
    p,proc:pointer;
    konc:string;
    is_new:boolean;
begin
Zda_je_registrovany_rez_fontu:=0;
EngineNum:=0;

for a:=Length(s) downto 1 do
    if s[a]='.' then Break;
if a=1 then Exit(-1);

if forceeng=''
   then konc:=Copy(s,a+1,255)         {separuji koncovku}
   else konc:=forceeng;

for a:=1 to LoadedFontNum do         {budeme prochazet seznam nactenych}
    if s=LoadedFontList[a].rez^ then  {sad bitmapovych fontu}
       begin
       enginenum:=LoadedFontList[a].typ;
       Exit(a); {font jiz mame nacteny? Bezva.}
       end;

{Projeli jsme cely seznam a zjistili, ze font jeste nacteny nemame}
if LoadedFontNum=MAX_VENOM_FONT then Exit(-2); {plna tabulka? Konec}


{Ted budeme muset zjistit, jestli jde o registrovanou priponu}
for e:=1 to Venom_FontEngines_pocet do
    if Venom_FontEngines_Mng[e].koncovka=konc
       then begin
       EngineNum:=e;
       Exit(0);
       end;
       {Vystupni kod 0 a nastavena promenna EngineNum}
Zda_je_registrovany_rez_fontu:=-3;  {o registrovanou priponu nejde...}
end;


Function Index_pro_fontPtr(fontptr:pointer):longint;
var a:longint;
begin
for a:=1 to LoadedFontNum do
    if LoadedFontList[a].fontptr=fontptr then Exit(a);
Index_pro_fontPtr:=0;
end;


Function Index_pro_fontRez(const rez:string):longint;
{predpoklada, ze REZ je velkymi pismeny}
var a:longint;
begin
for a:=1 to LoadedFontNum do
    if LoadedFontList[a].rez^=rez then Exit(a);
Index_pro_fontRez:=0;
end;



Function Registruj_Nahrany_font(const s:string;typ:byte;fontptr:pointer):longint;
begin
inc(LoadedFontNum);
GetMem(LoadedFontList[LoadedFontNum].rez,length(s));
LoadedFontList[LoadedFontNum].rez^:=s;
LoadedFontList[LoadedFontNum].typ:=typ;
LoadedFontList[LoadedFontNum].fontptr:=fontptr;
Registruj_Nahrany_font:=LoadedFontNum;
end;


Function Nahraj_Font_a_Registruj_ho(const s:string;enginenum,velikost:longint):longint;
var i:longint;
    proc,p:pointer;
begin
{writeln('Nahraj_Font_a_Registruj_ho: ',s,'   engine: ',enginenum,'  velikost: ',velikost);}
proc:=Venom_FontEngines_Mng[enginenum].loadproc; {pripravim si loader}
p:=loadfontfunc(proc)(s,velikost);             {a loaderem nactu font}
if p<>nil then
   begin
   i:=Registruj_Nahrany_font(s,enginenum,p);
   Nahraj_Font_a_Registruj_ho:=i;
   end
   else Nahraj_Font_a_Registruj_ho:=-20;  {selhal loader?}
end;


Function Registruj_Jinou_velikost_Fontu(b:longint;p:pointer):longint;
var rez:string;
    typ:byte;
begin
rez:=LoadedFontList[b].rez^;
typ:=LoadedFontList[b].typ;
Registruj_Jinou_velikost_Fontu:=Registruj_Nahrany_font(rez,typ,p);
end;


Function Pocet_Nahranych_Velikosti_Fontu(b:longint):longint;
var a,e:longint;
    s:string;
begin
e:=0;
s:=LoadedFontList[b].rez^;
for a:=1 to LoadedFontNum do
    if s=LoadedFontList[a].rez^ then inc(e);
Pocet_Nahranych_Velikosti_Fontu:=e;
end;


Procedure Odeber_Font_Ze_Seznamu(a:longint);
var b:longint;
    s:string;
begin
for b:=a to LoadedFontNum do
    begin
    FreeMem(LoadedFontList[b].rez);
    if b<LoadedFontNum then
       begin
       s:=LoadedFontList[b+1].rez^;
       GetMem(LoadedFontList[b].rez,Length(s));
       LoadedFontList[b].rez^:=s;
       end
       else LoadedFontList[b].rez:=nil;
    LoadedFontList[b].typ:=LoadedFontList[b+1].typ;
    LoadedFontList[b].fontptr:=LoadedFontList[b+1].fontptr;
    end;
dec(LoadedFontNum);
end;


Procedure Odeber_Vsechny_vyskyty_fontu_ze_seznamu(rez:string);
{odstrani font ve vsech velikostech}
{REZ musi byt velkymi pismeny}
var a:longint;
begin
a:=1;
while a<=LoadedFontNum do {LoadedFontNum se prubezne meni v procedure}
    begin                 {Odeber_Font_Ze_Seznamu}
    if LoadedFontList[a].rez^=rez
       then Odeber_Font_ze_seznamu(a)
       else inc(a);
    end;
end;


Function Venom_mng_SetFontStyle(rez:string;velikost,parametry:longint):longint;
var a,b,c,d:longint;
    typ,enginenum:byte;
    es:string;
    p,procinf,procset:pointer;
    q:pointer;

begin
Venom_mng_SetFontStyle:=1;
for a:=1 to Length(rez) do rez[a]:=UpCase(rez[a]);  {prevedeme na velke}
es:='';

if rez='VGA' then rez:='VGARAM._HW_' else
if rez='VGAROM' then rez:='VGAROM._HW_'
   else begin
   b:=Length(rez);
   c:=b-4;
   if c<1 then c:=1;
   for a:=b downto c do
       begin
       if rez[a]='*' then
          begin
          es:=Copy(rez,a+1,b-a);
          Delete(rez,a,255);
          Break;
          end;
       end;
   end;

{debug}{if rez='COURI18.FN' then
          a:=a;}

b:=Zda_je_registrovany_rez_fontu(rez,es,enginenum);

if b<0 then Exit(b);  {zaporne hodnoty z Zda_je_registrovany_rez_fontu jsou chybove stavy}

if b=0 then        {tento rez nahrany nemame, a to pro zadnou velikost}
   b:=Nahraj_Font_a_Registruj_ho(rez,enginenum,velikost); {tak ho nactem}

if b<0 then Exit(b);  {i zde ponechme moznost osetrit chybu}

{ted vime, ze REZ jiz mame nahrany, ale neni jiste, zda v pozadovane velikosti}

p:=LoadedFontList[b].fontptr;
procinf:=Venom_FontEngines_Mng[enginenum].getinfo; {pripravim si proc. pro info}
a:=getinfofunc(procinf)(p,1,0);   {funkce 1 - zjisti, zda existuje v jinych velikostech}
                                  {1 = nejsou jine velikosti
                                   2 = jsou jine bitmapove velikosti
                                   3 = jine velikosti lze vytvorit z vektorovych dat}

{writeln('a = ',a);
writeln('b = ',b);}

if a<1 then Exit(-10);  {chybovy stav}

if a=1 then            {poresena varianta, kdy neobsahujeme jine velikosti}
   begin
   AktFontSlot:=b;
   {zde je otazka, zda nejak resit velikosti}
   Exit;
   end;



if a=2 then    {varianta, kdy je font casti bitmapoveho archivu}
   begin
   c:=getinfofunc(procinf)(p,101,velikost);   {najdi nejblizsi velikost k VELIKOST}
   q:=pointer(getinfofunc(procinf)(p,102,c)); {a je tato velikost jiz nahrana?}
   if q=nil then   {tato velikost rezu jeste nebyla nahrana...}
      begin
      procset:=Venom_FontEngines_Mng[enginenum].setparams; {pripravim si proc. pro info}
      q:=SetParamsFunc(procset)(p,1,c,0);  {podfunkce 1 - priprav velikostni sadu}
      b:=Registruj_Jinou_velikost_Fontu(b,q);
      AktFontSlot:=b;
      end
      else
      begin        {pokud jiz nahrana byla, tak ji proste vyhledam}
      b:=Index_pro_fontPtr(q);
      AktFontSlot:=b;
      end;

   {aktfontvel:=velikost;}
   end;


if a=3 then    {varianta, kdy se bitmapovy font tvori z vektorovych dat}
   begin
   q:=pointer(getinfofunc(procinf)(p,102,velikost)); {uz jsme importovali tuto velikost?}
   if q=nil then
      begin
      procset:=Venom_FontEngines_Mng[enginenum].setparams; {pripravim si proc. pro info}
      q:=SetParamsFunc(procset)(p,1,velikost,0);  {podfunkce 1 - priprav velikostni sadu}
      b:=Registruj_Jinou_velikost_Fontu(b,q);
      AktFontSlot:=b;
      end
      else
      begin
      b:=Index_pro_fontPtr(q);
      AktFontSlot:=b;
      end;
   end;

{aktfontvel:=0;}

end;


Function Venom_mng_PrepChar(znak:word):pointer;
var typ:byte;
    p,pc:pointer;

begin
if AktFontSlot=0 then Venom_mng_PrepChar:=nil
   else begin
   p:=LoadedFontList[AktFontSlot].fontptr;
   typ:=LoadedFontList[AktFontSlot].typ;
   pc:=Venom_FontEngines_Mng[typ].prepchar;
   Venom_mng_PrepChar:=prepcharfunc(pc)(p,znak);
   end;
end;


Procedure Venom_mng_outstring(kam:pointer;x,y:longint;s:string;color:word);
var typ:byte;
    p,os:pointer;
begin
if aktfontslot<>0 then
   begin
   p:=LoadedFontList[AktFontSlot].fontptr;
   typ:=LoadedFontList[AktFontSlot].typ;
   os:=Venom_FontEngines_Mng[typ].outstring;
   outfontproc(os)(kam,x,y,s,p,color);
   end;
end;


Function Venom_mng_GetFontInfo(param1,param2:longint):longint;
var typ:byte;
    p,gi:pointer;
begin
if AktFontSlot=0 then Venom_mng_GetFontInfo:=0
   else begin
   p:=LoadedFontList[AktFontSlot].fontptr;
   typ:=LoadedFontList[AktFontSlot].typ;
   gi:=Venom_FontEngines_Mng[typ].getinfo;
   Venom_mng_GetFontInfo:=getinfofunc(gi)(p,param1,param2);
   end;

end;


Function Venom_mng_kill_font_internal(const rez:string;velikost,mode:byte):longint;
{MODE = 0:  smaze font jen v jedne jedine velikosti
 MODE = 1:  smaze font ve vsech nahranych velikostech}

var a,b,c,e:byte;
    konc,rr:string;
    p,q,dp:pointer;
    procinf:pointer;
    u:boolean;
    l:longint;

begin
rr:='';
rr[0]:=rez[0];
for a:=1 to Length(rez) do rr[a]:=UpCase(rez[a]);

if rr='VGA' then rr:='VGARAM._HW_';
if rr='VGAROM' then rr:='VGAROM._HW_';

a:=Index_pro_fontRez(rr);
if a=0 then Exit(0);         {font nenalezen? nepokracujme}

e:=LoadedFontList[a].typ;

p:=LoadedFontList[a].fontptr;
procinf:=Venom_FontEngines_Mng[e].getinfo; {pripravim si proc. pro info}
b:=getinfofunc(procinf)(p,1,0);   {funkce 1 - zjisti, zda existuje v jinych velikostech}
                                  {1 = nejsou jine velikosti
                                   2 = jsou jine bitmapove velikosti
                                   3 = jine velikosti lze vytvorit z vektorovych dat}
if b=1 then mode:=1;

if mode=0 then
   begin
   c:=getinfofunc(procinf)(p,101,velikost);   {najdi nejblizsi velikost k VELIKOST}
   q:=pointer(getinfofunc(procinf)(p,102,c)); {a je tato velikost jiz nahrana?}
   if q=nil then Exit(0);
   a:=Index_pro_fontPtr(q);  {upravime index pro konkretni velikost}

   c:=Pocet_Nahranych_Velikosti_Fontu(a);
   if c=1 then mode:=1;  {posledni velikost fontu? Tak smazme i skorapku}
   end
   else q:=p;

l:=Venom_mng_kill_font_internal2(a,mode);
Venom_mng_kill_font_internal:=l;
end;


Function Venom_mng_kill_font_internal2(index:longint;mode:byte):longint;
var u:boolean;
    p,dp:pointer;
    b:byte;
    s:string;

begin

p:=LoadedFontList[index].fontptr;  {odkaz na font}
b:=LoadedFontList[index].typ;      {jaky mame pouzit engine?}
s:=LoadedFontList[index].rez^;
dp:=Venom_FontEngines_Mng[b].deleteproc; {pripravim odstranovac}
u:=removefontproc(dp)(p,mode);

{mame smazano, takze jeste musim aktualizovat seznam nactenych fontu}
if u=true then
   begin
   if mode=0
      then Odeber_Font_Ze_Seznamu(index)
      else Odeber_Vsechny_vyskyty_fontu_ze_seznamu(s);
   {a odstranime zaznamy odkazujici se na smazany font}

   if AktFontSlot>=index then AktFontSlot:=index-1;
   end;
end;


Function Venom_mng_GetNumLoadedFontBitmaps:longint;
begin
Venom_mng_GetNumLoadedFontBitmaps:=LoadedFontNum;
end;


Function Venom_mng_GetActFontSlot:longint;
begin
Venom_mng_GetActFontSlot:=aktfontslot;
end;


Function Venom_mng_GetActFontPtr:pointer;
begin
Venom_mng_GetActFontPtr:=LoadedFontList[aktfontslot].fontptr;
end;


Function Venom_mng_GetFontPtr(a:longint):pointer;
begin
Venom_mng_GetFontPtr:=LoadedFontList[a].fontptr;
end;


Function Venom_mng_GetFontPtrSlot(p:pointer):longint;
var a:byte;
begin
for a:=1 to LoadedFontNum do
    if LoadedFontList[a].fontptr=p then Exit(a);
Venom_mng_GetFontPtrSlot:=0;
end;


Function Venom_mng_GetFontSlot_by_name(s:string;num:longint):longint;
var a,b:longint;
    t:string;

begin
for a:=1 to Length(s) do s[a]:=UpCase(s[a]);  {prevedeme na velke}
b:=0;
for a:=1 to LoadedFontNum do
    begin
    if s=LoadedFontList[a].rez^ then
       begin
       inc(b);
       if b>=num then Exit(a);
       end;
    end;

Venom_mng_GetFontSlot_by_name:=0;
end;


Function Venom_mng_SetActFontSlot(a:longint):longint;
begin
if a<1 then a:=1;
if a>LoadedFontNum then a:=LoadedFontNum;
aktfontslot:=a;
Venom_mng_SetActFontSlot:=a;
end;


Function Venom_mng_kill_font(rez:string):longint;
begin
Venom_mng_kill_font:=Venom_mng_kill_font_internal(rez,0,1);
end;


Function Venom_mng_kill_subfont(rez:string;velikost:byte):longint;
begin
Venom_mng_kill_subfont:=Venom_mng_kill_font_internal(rez,velikost,0);
end;


Function Venom_mng_Init_graph_list(p:po_init_graph):longint;
begin
inc(aktinit_graphslot);
Venom_co_volat_po_Init_Graph[aktinit_graphslot]:=p;
end;


Function Venom_mng_Get_Image_Loader_Index(s:string):longint;
var t:string;
    a,b:longint;
begin
b:=0;
for a:=Length(s) downto 1 do
    if s[a]='.' then
       begin
       b:=a;
       Break;
       end;
t:=Copy(s,b+1,Length(s));
for a:=1 to Length(t) do t[a]:=UpCase(t[a]);

for a:=1 to Venom_Image_Mng.pocet do
    begin
    if Venom_Image_Mng.koncovka[a] = t then Exit(a);
    end;
Venom_mng_Get_Image_Loader_Index:=0;
end;


begin
StartUnit;
end.
