diff --git a/.gitmodules b/.gitmodules
index 782dfea..3a0982b 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -1,3 +1,9 @@
[submodule "TextSuite"]
path = TextSuite
url = ../textsuite.git
+[submodule "Utils"]
+ path = Utils
+ url = ../utils.git
+[submodule "OpenGlCore"]
+ path = OpenGlCore
+ url = ../lazopenglcore.git
diff --git a/OpenGlCore b/OpenGlCore
new file mode 160000
index 0000000..f3387a1
--- /dev/null
+++ b/OpenGlCore
@@ -0,0 +1 @@
+Subproject commit f3387a1344abac9b32dad078fe0aa083fa6cea14
diff --git a/TextSuite b/TextSuite
index 47bb935..893e916 160000
--- a/TextSuite
+++ b/TextSuite
@@ -1 +1 @@
-Subproject commit 47bb93569afcfc25da2aae5c7dd49d7a122fde21
+Subproject commit 893e9166cd762b505bb8cd72ce7f999a1b5e97b3
diff --git a/Utils b/Utils
new file mode 160000
index 0000000..2e95929
--- /dev/null
+++ b/Utils
@@ -0,0 +1 @@
+Subproject commit 2e95929d4ef5ada8ac42e840a7e247c98b257581
diff --git a/libTextSuite.lpi b/libTextSuite.lpi
index 264397d..6930e7e 100644
--- a/libTextSuite.lpi
+++ b/libTextSuite.lpi
@@ -47,6 +47,7 @@
+
@@ -57,6 +58,11 @@
+
+
+
+
+
diff --git a/libTextSuite.lpr b/libTextSuite.lpr
index b0da502..1a9b018 100644
--- a/libTextSuite.lpr
+++ b/libTextSuite.lpr
@@ -3,8 +3,396 @@ library libTextSuite;
{$mode objfpc}{$H+}
uses
- Classes;
+ Classes, SysUtils,
+ utsTextSuite, utsTypes, utsRendererOpenGL, utsRendererOpenGLES,
+ uutlGenerics;
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+//external types and contstants/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+type
+ {$Z4}
+ TltsErrorCode = (
+ ltsErrUnknown = -1,
+ ltsErrNone = 0,
+
+ // misc
+ ltsErrNotInitialized = 1,
+ ltsErrInvalidEnum = 2,
+ ltsErrInvalidValue = 3,
+ ltsErrInvalidOperation = 4,
+
+ // invalid handles
+ ltsErrInvalidContextHandle = 100,
+ ltsErrInvalidRendererHandle = 101
+ );
+
+ {$Z4}
+ TltsRendererType = (
+ ltsRendererOpenGL,
+ ltsRendererOpenGLES,
+ ltsRendererCustom
+ );
+
+ TltsContextHandle = Pointer;
+ TltsRendererHandle = Pointer;
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+//internal types and contstants/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ TltsContext = class(TtsContext)
+ public
+ destructor Destroy; override;
+ end;
+ TtsContextHashSet = specialize TutlHashSet;
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ TltsRendererOpenGL = class(TtsRendererOpenGL)
+ public
+ // TODO destructor Destroy; override;
+ end;
+
+ TltsRendererOpenGLES = class(TtsRendererOpenGLES)
+ public
+ // TODO destructor Destroy; override;
+ end;
+
+ { TODO
+ TltsRendererCustom = class(TtsRenderer)
+ protected
+ function CreateRenderRef(const aChar: TtsChar; const aCharImage: TtsImage): TtsCharRenderRef; override;
+ procedure FreeRenderRef(const aCharRef: TtsCharRenderRef); override;
+
+ procedure BeginRender; override;
+ procedure EndRender; override;
+
+ procedure SetDrawPos(const X, Y: Integer); override;
+ function GetDrawPos: TtsPosition; override;
+ procedure MoveDrawPos(const X, Y: Integer); override;
+ procedure SetColor(const aColor: TtsColor4f); override;
+ procedure Render(const aCharRef: TtsCharRenderRef; const aForcedWidth: Integer = 0); override;
+ public
+ // TODO destructor Destroy; override;
+ end;
+ }
+
+ TtsRendererHashSet = specialize TutlHashSet;
+
+var
+ IsInitilized: Boolean = false;
+ Contexts: TtsContextHashSet = nil;
+ Renderers: TtsRendererHashSet = nil;
+ LastErrorCode: TltsErrorCode = ltsErrNone;
+ LastErrorMsg: String;
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+//helper methods////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+procedure SetLastError(const aEx: Exception);
+begin
+ LastErrorCode := ltsErrUnknown;
+ LastErrorMsg := aEx.Message;
+end;
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+procedure SetLastError(const aErrorCode: TltsErrorCode; const aErrorMsg: String);
+begin
+ LastErrorCode := aErrorCode;
+ LastErrorMsg := aErrorMsg;
+end;
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+function CheckIfInitialized: Boolean;
+begin
+ result := IsInitilized;
+ if not result then
+ SetLastError(ltsErrNotInitialized, 'libTextSuite has not been initialized. call ltsInitialize before using any other methods.');
+end;
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+function CheckContextHandle(const aHandle: TltsContextHandle; out aContext: TtsContext): Boolean;
+begin
+ result := CheckIfInitialized;
+ if result then begin
+ aContext := TltsContext(aHandle);
+ result := Contexts.Contains(aContext);
+ if not result then
+ SetLastError(ltsErrInvalidContextHandle, Format('0x%.16x is not a valid context handle', [{%H-}PtrUInt(aHandle)]));
+ end;
+end;
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+function CheckRendererHandle(const aHandle: TltsContextHandle; out aRenderer: TtsRenderer): Boolean;
+begin
+ result := CheckIfInitialized;
+ if result then begin
+ aRenderer := TtsRenderer(aHandle);
+ result := Renderers.Contains(aRenderer);
+ if not result then
+ SetLastError(ltsErrInvalidRendererHandle, Format('0x%.16x is not a valid renderer handle', [{%H-}PtrUInt(aHandle)]));
+ end;
+end;
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+function ValidateCodePage(const aValue: TtsCodePage): Boolean;
+begin
+ result := (aValue >= Low(TtsCodePage)) and (aValue <= High(TtsCodePage));
+end;
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+function ValidateFormat(const aValue: TtsFormat): Boolean;
+begin
+ result := (aValue >= Low(TtsFormat)) and (aValue <= High(TtsFormat));
+end;
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+//Context///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+function ltsContextCreate: TltsContextHandle; stdcall;
+var
+ c: TltsContext;
+begin
+ try
+ result := nil;
+ if not CheckIfInitialized then
+ exit;
+ c := TltsContext.Create;
+ Contexts.Add(c);
+ result := c;
+ except
+ on ex: Exception do begin
+ SetLastError(ex);
+ result := nil;
+ end;
+ end;
+end;
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+function ltsContextGetCodePage(const aHandle: TltsContextHandle; var aCodePage: TtsCodePage): TltsErrorCode; stdcall;
+var
+ c: TtsContext;
begin
+ try
+ result := ltsErrNone;
+ if CheckContextHandle(aHandle, c)
+ then aCodePage := c.CodePage
+ else result := LastErrorCode;
+ except
+ on ex: Exception do begin
+ SetLastError(ex);
+ result := LastErrorCode;
+ end;
+ end;
+end;
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+function ltsContextGetDefaultChar(const aHandle: TltsContextHandle; var aValue: WideChar): TltsErrorCode; stdcall;
+var
+ c: TtsContext;
+begin
+ try
+ result := ltsErrNone;
+ if CheckContextHandle(aHandle, c)
+ then aValue := c.CodePageDefault
+ else result := LastErrorCode;
+ except
+ on ex: Exception do begin
+ SetLastError(ex);
+ result := LastErrorCode;
+ end;
+ end;
+end;
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+function ltsContextSetCodePage(const aHandle: TltsContextHandle; const aCodePage: TtsCodePage): TltsErrorCode; stdcall;
+var
+ c: TtsContext;
+begin
+ try
+ result := ltsErrNone;
+ if CheckContextHandle(aHandle, c) then begin
+ if not ValidateCodePage(aCodePage) then begin
+ SetLastError(ltsErrInvalidEnum, Format('%d is not a valid enum value for CodePage', [aCodePage]));
+ result := LastErrorCode;
+ end else
+ c.CodePage := aCodePage;
+ end else
+ result := LastErrorCode;
+ except
+ on ex: Exception do begin
+ SetLastError(ex);
+ result := LastErrorCode;
+ end;
+ end;
+end;
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+function ltsContextSetDefaultChar(const aHandle: TltsContextHandle; const aValue: WideChar): TltsErrorCode; stdcall;
+var
+ c: TtsContext;
+begin
+ try
+ result := ltsErrNone;
+ if CheckContextHandle(aHandle, c)
+ then c.CodePageDefault := aValue
+ else result := LastErrorCode;
+ except
+ on ex: Exception do begin
+ SetLastError(ex);
+ result := LastErrorCode;
+ end;
+ end;
+end;
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+function ltsContextDestroy(const aHandle: TltsContextHandle): TltsErrorCode; stdcall;
+var
+ c: TtsContext;
+begin
+ try
+ result := ltsErrNone;
+ if CheckContextHandle(aHandle, c)
+ then Contexts.Remove(c)
+ else result := LastErrorCode;
+ except
+ on ex: Exception do begin
+ SetLastError(ex);
+ result := LastErrorCode;
+ end;
+ end;
+end;
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+//Renderer//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+function ltsRendererCreate(const aHandle: TltsContextHandle; const aType: TltsRendererType; const aFormat: TtsFormat): TltsRendererHandle; stdcall;
+var
+ c: TtsContext;
+ r: TtsRenderer;
+begin
+ try
+ result := nil;
+ if not CheckContextHandle(aHandle, c) then
+ exit;
+
+ if not ValidateFormat(aFormat) then begin
+ SetLastError(ltsErrInvalidEnum, Format('%d is not a valid format', [aFormat]));
+ exit;
+ end;
+
+ case aType of
+ ltsRendererOpenGL: r := TltsRendererOpenGL.Create(c, aFormat);
+ ltsRendererOpenGLES: r := TltsRendererOpenGLES.Create(c, aFormat);
+ // TODO ltsRendererCustom: r := TltsRendererCustom.Create(c, aFormat);
+ else
+ SetLastError(ltsErrInvalidEnum, Format('%d is not a valid renderer type', [aType]));
+ exit;
+ end;
+ Renderers.Add(r);
+ result := r;
+ except
+ on ex: Exception do begin
+ SetLastError(ex);
+ result := nil;
+ end;
+ end;
+end;
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+function ltsRendererDestroy(const aHandle: TltsRendererHandle): TltsErrorCode; stdcall;
+var
+ r: TtsRenderer;
+begin
+ try
+ result := ltsErrNone;
+ if CheckRendererHandle(aHandle, r)
+ then Renderers.Remove(r)
+ else result := LastErrorCode;
+ except
+ on ex: Exception do begin
+ SetLastError(ex);
+ result := LastErrorCode;
+ end;
+ end;
+end;
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+//Global////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+function ltsInitialize: TltsErrorCode; stdcall;
+begin
+ try
+ Contexts := TtsContextHashSet.Create(true);
+ Renderers := TtsRendererHashSet.Create(true);
+ IsInitilized := true;
+ result := ltsErrNone;
+ except
+ on ex: Exception do begin
+ SetLastError(ex);
+ result := LastErrorCode;
+ end;
+ end;
+end;
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+function ltsGetLastErrorCode: TltsErrorCode; stdcall;
+begin
+ result := LastErrorCode;
+end;
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+function ltsGetLastErrorMsg: PAnsiChar; stdcall;
+begin
+ result := PAnsiChar(LastErrorMsg);
+end;
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+function ltsFinalize: TltsErrorCode; stdcall;
+begin
+ try
+ IsInitilized := false;
+ FreeAndNil(Renderers);
+ FreeAndNil(Contexts);
+ result := ltsErrNone;
+ except
+ on ex: Exception do begin
+ SetLastError(ex);
+ result := LastErrorCode;
+ end;
+ end;
+end;
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+exports
+ ltsContextCreate,
+ ltsContextGetCodePage,
+ ltsContextGetDefaultChar,
+ ltsContextSetCodePage,
+ ltsContextSetDefaultChar,
+ ltsContextDestroy,
+
+ ltsRendererCreate,
+ ltsRendererDestroy,
+
+ ltsInitialize,
+ ltsGetLastErrorCode,
+ ltsGetLastErrorMsg,
+ ltsFinalize;
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+//TltsContext///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+destructor TltsContext.Destroy;
+var
+ i: Integer;
+begin
+ if Assigned(Renderers) then begin
+ for i := fRenderers.Count-1 downto 0 do
+ Renderers.Remove(fRenderers[i] as TtsRenderer);
+ end;
+ // TODO cleanup generators
+ inherited Destroy;
+end;
+
end.