(* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
                         -****************+.
               .-=++*+::*###############*-
           :=+##*+=-::*##**############=
        .=*#*=:    .+#*=+############+.
       =##+.      +#+-=############*-:
     :*#+.      =+-.=#############- =#*.
    -##-      -=..+#############*:.  ---.
   -##:     .: .+################= :+#*-:.
  .##-        :==========*#####= :*#*- -#*
  =##                   -####*:-*#*-   .##:
  +#+                  -###*--*#*-      *#=
  *#+                 +###==*#*:        *#=
  +#*                *##+=*#*-          ##-
  :##.             .*##*##*:           -##.
   +#*            -#####*:             *#=
    *#+          =####+:             .*#+
     +#*.       +###+.              :##=
      -##+.    *##+:              :+#*:
        =*#+..*#+:             .-*#*-
          :-:#+::.        .:-=*##+:
           -+..+*###****####*+-.
          :.      ..:::::..
        ____                   _
       / ___| _ __   __ _ _ __| | __
       \___ \| '_ \ / _` | '__| |/ /
        ___) | |_) | (_| | |  |   <
       |____/| .__/ \__,_|_|  |_|\_\
             |_|   Game Toolkit™

Copyright © 2024-present tinyBigGAMES™ LLC
         All Rights Reserved.

Website: https://tinybiggames.com
Email  : support@tinybiggames.com

See LICENSE for license information
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *)

unit SGT.Deps.Ext;

{$I SGT.Defines.inc}

interface

uses
  System.SysUtils,
  System.Classes,
  System.Math,
  System.AnsiStrings,
  WinApi.Windows,
  SGT.Deps;

//=== CIMGUI ==================================================================
function  ImFontAtlas_AddFontFromResTTF(self: PImFontAtlas; const AInstance: HINST; const AResName: string; size_pixels: Single; const glyph_ranges: PImWchar): PImFont;
function  ImFontAtlas_AddDefaultFontTTF(self: PImFontAtlas; size_pixels: Single; const glyph_ranges: PImWchar): PImFont;
procedure ImFontAtlas_ResizeDefaultFont(self: PImFontAtlas; const ASize: Single);

//=== LUAJIT ================================================================
function  lua_isfunction(aState: Pointer; n: Integer): Boolean; inline;
function  lua_isvariable(aState: Pointer; n: Integer): Boolean; inline;
procedure lua_newtable(aState: Pointer); inline;
procedure lua_pop(aState: Pointer; n: Integer); inline;
procedure lua_getglobal(aState: Pointer; aName: PAnsiChar); inline;
procedure lua_setglobal(aState: Pointer; aName: PAnsiChar); inline;
procedure lua_pushcfunction(aState: Pointer; aFunc: lua_CFunction); inline;
procedure lua_register(aState: Pointer; aName: PAnsiChar; aFunc: lua_CFunction); inline;
function  lua_isnil(aState: Pointer; n: Integer): Boolean; inline;
function  lua_tostring(aState: Pointer; idx: Integer): string; inline;
function  luaL_dofile(aState: Pointer; aFilename: PAnsiChar): Integer; inline;
function  luaL_dostring(aState: Pointer; aStr: PAnsiChar): Integer; inline;
function  luaL_dobuffer(aState: Pointer; aBuffer: Pointer; aSize: NativeUInt; aName: PAnsiChar): Integer; inline;
function  lua_upvalueindex(i: Integer): Integer; inline;
function  luaL_checkstring(L: Plua_State; n: Integer): PAnsiChar; inline;
procedure luaL_requiref(L: Plua_State; modname: PAnsiChar; openf: lua_CFunction; glb: Integer); inline;

//=== LLAMACPP ==============================================================
{ llama sampling }
var
  _llama_sampling_init: function(): Pointer; cdecl;
  _llama_sampling_sample: function(ctx_sampling: Pointer; ctx_main, ctx_cfg: Pllama_context; idx: integer = -1): llama_token; cdecl;
  _llama_sampling_accept: procedure(ctx_sampling: Pointer; ctx_main: Pllama_context; id: llama_token; apply_grammar: Boolean); cdecl;
  _llama_sampling_free: procedure(ctx_sampling: Pointer); cdecl;

{ cerr }
type
  cerr_callback = procedure(const text: PUTF8Char; user_data: Pointer); cdecl;
var
  redirect_cerr_to_callback: procedure(callback: cerr_callback; user_data: Pointer); cdecl;
  restore_cerr: procedure(); cdecl;

procedure GetExports(const aDLLHandle: THandle);

implementation

uses
  SGT.Core;

procedure GetExports(const aDLLHandle: THandle);
begin
  if aDllHandle = 0 then Exit;
  _llama_sampling_init :=  GetProcAddress(aDLLHandle, '_llama_sampling_init');
  _llama_sampling_sample :=  GetProcAddress(aDLLHandle, '_llama_sampling_sample');
  _llama_sampling_accept :=  GetProcAddress(aDLLHandle, '_llama_sampling_accept');
  _llama_sampling_free :=  GetProcAddress(aDLLHandle, '_llama_sampling_free');
  redirect_cerr_to_callback :=  GetProcAddress(aDLLHandle, 'redirect_cerr_to_callback');
  restore_cerr :=  GetProcAddress(aDLLHandle, 'restore_cerr');
end;

//=== CIMGUI ==================================================================
function ImFontAtlas_AddFontFromResTTF(self: PImFontAtlas; const AInstance: HINST; const AResName: string; size_pixels: Single; const glyph_ranges: PImWchar): PImFont;
type
  TImWchar = Word;
var
  LResStream: TResourceStream;
  LConfig: ImFontConfig;
  LName: UTF8String;
begin
  Result := nil;
  if not Utils.ResourceExist(AInstance, AResName) then Exit;
  LResStream := TResourceStream.Create(AInstance, AResName, RT_RCDATA);
  try
    FillChar(LConfig, SizeOf(LConfig), 0);
    LConfig.FontData := LResStream.Memory;
    LConfig.FontDataSize := LResStream.Size;
    LConfig.SizePixels := size_pixels;
    LConfig.FontDataOwnedByAtlas := False;
    LConfig.OversampleH := 2;
    LConfig.OversampleV := 1;
    LConfig.GlyphMaxAdvanceX := MaxSingle;
    LConfig.RasterizerMultiply := 1.0;
    LConfig.RasterizerDensity := 1.0;
    LConfig.EllipsisChar := TImWchar(-1);
    LName := UTF8String(Format('Default Font, %0.gpx', [size_pixels]));

    System.AnsiStrings.StrLCopy(@LConfig.Name[0], PUTF8Char(LName), Length(LName));

    Result := ImFontAtlas_AddFontFromMemoryTTF(self, LResStream.Memory, LResStream.Size, size_pixels, @LConfig, glyph_ranges);
  finally
    LResStream.Free;
  end;
end;

function ImFontAtlas_AddDefaultFontTTF(self: PImFontAtlas; size_pixels: Single; const glyph_ranges: PImWchar): PImFont;
begin
  Result := ImFontAtlas_AddFontFromResTTF(self, HInstance, 'a22a034b88d844578c672a8073d49229', size_pixels, glyph_ranges);
end;

procedure ImFontAtlas_ResizeDefaultFont(self: PImFontAtlas; const ASize: Single);
begin
  ImFontAtlas_Clear(self);
  ImGui_ImplOpenGL2_DestroyFontsTexture();
  ImFontAtlas_AddDefaultFontTTF(self, ASize, nil);
  ImGui_ImplOpenGL2_CreateFontsTexture();
end;

//=== LUAJIT ================================================================
{$REGION ' Lua Macros ' }
function lua_isfunction(aState: Pointer; n: Integer): Boolean; inline;
begin
  Result := Boolean(lua_type(aState, n) = LUA_TFUNCTION);
end;

function lua_isvariable(aState: Pointer; n: Integer): Boolean; inline;
var
  aType: Integer;
begin
  aType := lua_type(aState, n);

  if (aType = LUA_TBOOLEAN) or (aType = LUA_TLIGHTUSERDATA) or (aType = LUA_TNUMBER) or (aType = LUA_TSTRING) then
    Result := True
  else
    Result := False;
end;

procedure lua_newtable(aState: Pointer); inline;
begin
  lua_createtable(aState, 0, 0);
end;

procedure lua_pop(aState: Pointer; n: Integer); inline;
begin
  lua_settop(aState, -n - 1);
end;

procedure lua_getglobal(aState: Pointer; aName: PAnsiChar); inline;
begin
  lua_getfield(aState, LUA_GLOBALSINDEX, aName);
end;

procedure lua_setglobal(aState: Pointer; aName: PAnsiChar); inline;
begin
  lua_setfield(aState, LUA_GLOBALSINDEX, aName);
end;

procedure lua_pushcfunction(aState: Pointer; aFunc: lua_CFunction); inline;
begin
  lua_pushcclosure(aState, aFunc, 0);
end;

procedure lua_register(aState: Pointer; aName: PAnsiChar; aFunc: lua_CFunction); inline;
begin
  lua_pushcfunction(aState, aFunc);
  lua_setglobal(aState, aName);
end;

function lua_isnil(aState: Pointer; n: Integer): Boolean; inline;
begin
  Result := Boolean(lua_type(aState, n) = LUA_TNIL);
end;

function lua_tostring(aState: Pointer; idx: Integer): string; inline;
begin
  Result := string(lua_tolstring(aState, idx, nil));
end;

function luaL_dofile(aState: Pointer; aFilename: PAnsiChar): Integer; inline;
Var
  Res: Integer;
begin
  Res := luaL_loadfile(aState, aFilename);
  if Res = 0 then
    Res := lua_pcall(aState, 0, 0, 0);
  Result := Res;
end;

function luaL_dostring(aState: Pointer; aStr: PAnsiChar): Integer; inline;
Var
  Res: Integer;
begin
  Res := luaL_loadstring(aState, aStr);
  if Res = 0 then
    Res := lua_pcall(aState, 0, 0, 0);
  Result := Res;
end;

function luaL_dobuffer(aState: Pointer; aBuffer: Pointer; aSize: NativeUInt;
  aName: PAnsiChar): Integer; inline;
var
  Res: Integer;
begin
  Res := luaL_loadbuffer(aState, aBuffer, aSize, aName);
  if Res = 0 then
    Res := lua_pcall(aState, 0, 0, 0);
  Result := Res;
end;

function lua_upvalueindex(i: Integer): Integer; inline;
begin
  Result := LUA_GLOBALSINDEX - i;
end;

function luaL_checkstring(L: Plua_State; n: Integer): PAnsiChar; inline;
begin
  Result := luaL_checklstring(L, n, nil);
end;

procedure luaL_requiref(L: Plua_State; modname: PAnsiChar; openf: lua_CFunction; glb: Integer); inline;
begin
  lua_pushcfunction(L, openf);
  lua_pushstring(L, modname);
  lua_call(L, 1, 1);
  lua_getfield(L, LUA_REGISTRYINDEX, '_LOADED');
  lua_pushvalue(L, -2);
  lua_setfield(L, -2, modname);
  lua_pop(L, 1);
  if glb <> 0 then
  begin
    lua_pushvalue(L, -1);
    lua_setglobal(L, modname);
  end;
end;

{$ENDREGION}

end.
