diff --git a/examples/simple/TextSuiteTest.lpi b/examples/simple/TextSuiteTest.lpi
index 0c018cf..30a9336 100644
--- a/examples/simple/TextSuiteTest.lpi
+++ b/examples/simple/TextSuiteTest.lpi
@@ -44,7 +44,6 @@
-
@@ -72,7 +71,6 @@
-
@@ -85,17 +83,14 @@
-
-
-
@@ -112,7 +107,7 @@
-
+
diff --git a/examples/simple/TextSuiteTest.lps b/examples/simple/TextSuiteTest.lps
index 0a19193..a96c285 100644
--- a/examples/simple/TextSuiteTest.lps
+++ b/examples/simple/TextSuiteTest.lps
@@ -4,7 +4,7 @@
-
+
@@ -18,7 +18,6 @@
-
@@ -28,8 +27,10 @@
-
-
+
+
+
+
@@ -37,10 +38,8 @@
-
-
-
-
+
+
@@ -54,10 +53,11 @@
-
-
-
+
+
+
+
@@ -70,10 +70,8 @@
-
-
-
+
@@ -97,7 +95,6 @@
-
@@ -106,7 +103,6 @@
-
@@ -116,7 +112,6 @@
-
@@ -124,13 +119,33 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
+
+
@@ -143,237 +158,236 @@
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
@@ -383,252 +397,249 @@
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
-
-
-
+
+
+
+
-
-
-
+
+
+
-
+
-
-
+
+
-
-
+
-
-
+
+
-
-
+
+
-
+
-
-
+
+
-
+
-
-
+
+
-
-
+
+
-
-
+
+
-
+
-
+
-
-
+
+
-
+
-
-
+
+
-
-
+
+
-
+
-
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
+
-
+
-
+
-
-
+
+
-
-
+
+
-
-
+
+
diff --git a/utsFontCreatorFreeType.pas b/utsFontCreatorFreeType.pas
index 0222580..4789631 100644
--- a/utsFontCreatorFreeType.pas
+++ b/utsFontCreatorFreeType.pas
@@ -5,7 +5,7 @@ unit utsFontCreatorFreeType;
interface
uses
- Classes, SysUtils, syncobjs, dynlibs,
+ Classes, SysUtils,
utsTextSuite, utsTypes, utsFreeType;
type
@@ -315,7 +315,7 @@ begin
if (err <> 0) then
raise EtsException.Create('unable to set char size: error=' + IntToStr(err));
- FillByte(prop, SizeOf(prop), 0);
+ FillByte(prop{%H-}, SizeOf(prop), 0);
prop.AntiAliasing := tsAANormal;
prop.FaceName := face^.family_name;
prop.StyleName := face^.style_name;
diff --git a/utsOpenGLUtils.pas b/utsOpenGLUtils.pas
index 56cf9c3..39bd380 100644
--- a/utsOpenGLUtils.pas
+++ b/utsOpenGLUtils.pas
@@ -5,19 +5,16 @@ unit utsOpenGLUtils;
interface
uses
- Classes, SysUtils, syncobjs,
+ Classes, SysUtils,
utsTextSuite, utsTypes;
type
- TtsQuadPosF = array[0..3] of TtsPositionF;
TtsCharRenderRefOpenGL = class(TtsCharRenderRef)
public
TextureID: Integer; // ID of OpenGL texture where the char is stored in
- TexCoordSize: TtsPositionF; // size of the char in texture coords (0.0 - 1.0)
- TexCoordPos: TtsPositionF; // position of the char in texture coords (0.0 - 1.0)
- VertexSize: TtsPositionF; // size of the char in world coords
- VertexPos: TtsPositionF; // size of the char in world coords
-
+ Size: TtsPosition;
+ TexMat: TtsMatrix4f;
+ VertMat: TtsMatrix4f;
constructor Create;
end;
@@ -61,9 +58,8 @@ type
function CreateNewTexture: PtsFontTexture; virtual;
procedure FreeTexture(var aTexture: PtsFontTexture); virtual;
- procedure UploadTexData(const aCharRef: TtsCharRenderRefOpenGL;
- const aCharImage: TtsImage; const X, Y: Integer); virtual;
+ procedure UploadTexData(const aCharRef: TtsCharRenderRefOpenGL; const aCharImage: TtsImage; const X, Y: Integer); virtual;
protected
function CreateRenderRef(const aChar: TtsChar; const aCharImage: TtsImage): TtsCharRenderRef; override;
procedure FreeRenderRef(const aCharRef: TtsCharRenderRef); override;
@@ -92,10 +88,9 @@ constructor TtsCharRenderRefOpenGL.Create;
begin
inherited Create;
TextureID := 0;
- FillByte(TexCoordPos, SizeOf(TexCoordPos), 0);
- FillByte(TexCoordSize, SizeOf(TexCoordSize), 0);
- FillByte(VertexPos, SizeOf(VertexPos), 0);
- FillByte(VertexSize, SizeOf(VertexSize), 0);
+ FillByte(TexMat, SizeOf(TexMat), 0);
+ FillByte(VertMat, SizeOf(VertMat), 0);
+ FillByte(Size, SizeOf(Size), 0);
end;
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -152,8 +147,7 @@ begin
end;
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-procedure TtsBaseOpenGL.UploadTexData(const aCharRef: TtsCharRenderRefOpenGL;
- const aCharImage: TtsImage; const X, Y: Integer);
+procedure TtsBaseOpenGL.UploadTexData(const aCharRef: TtsCharRenderRefOpenGL; const aCharImage: TtsImage; const X, Y: Integer);
begin
// DUMMY
end;
@@ -211,21 +205,22 @@ var
item := InsertToTree(aTexture^.Usage, 0, 0, aTexture^.Size, aTexture^.Size, x, y);
if not Assigned(item) then
raise EtsRendererOpenGL.Create('unable to add glyph to texture');
+
item^.ref := TtsCharRenderRefOpenGL.Create;
result := item^.ref;
- // Text Coords
- result.TextureID := aTexture^.ID;
- result.TexCoordPos.x := x / aTexture^.Size;
- result.TexCoordPos.y := y / aTexture^.Size;
- result.TexCoordSize.x := aCharImage.Width / aTexture^.Size;
- result.TexCoordSize.y := aCharImage.Height / aTexture^.Size;
-
- // Vertex Coords
- result.VertexPos.x := -aChar.GlyphRect.Left;
- result.VertexPos.y := -aChar.GlyphRect.Top - aChar.GlyphOrigin.y;
- result.VertexSize.x := aCharImage.Width;
- result.VertexSize.y := aCharImage.Height;
+ result.TextureID := aTexture^.ID;
+ result.Size := tsPosition(aCharImage.Width, aCharImage.Height);
+ result.TexMat := tsMatrix4f(
+ tsVector4f(aCharImage.Width / aTexture^.Size, 0.0, 0.0, 0.0),
+ tsVector4f(0.0, aCharImage.Height / aTexture^.Size, 0.0, 0.0),
+ tsVector4f(0.0, 0.0, 1.0, 0.0),
+ tsVector4f(x / aTexture^.Size, y / aTexture^.Size, 0.0, 1.0));
+ result.VertMat := tsMatrix4f(
+ tsVector4f(aCharImage.Width, 0.0, 0.0, 0.0),
+ tsVector4f(0.0, aCharImage.Height, 0.0, 0.0),
+ tsVector4f(0.0, 0.0, 1.0, 0.0),
+ tsVector4f(-aChar.GlyphRect.Left, -aChar.GlyphRect.Top - aChar.GlyphOrigin.y, 0.0, 1.0));
UploadTexData(result, aCharImage, x, y);
end;
@@ -281,8 +276,8 @@ var
w := X2 - X1;
h := Y2 - Y1;
if not Assigned(aItem) or
- (w < ref.VertexSize.x) or
- (h < ref.VertexSize.y) then
+ (w < ref.Size.x) or
+ (h < ref.Size.y) then
exit;
result := (aItem^.ref = ref);
diff --git a/utsRendererOpenGL.pas b/utsRendererOpenGL.pas
index 8ac0d31..2087a04 100644
--- a/utsRendererOpenGL.pas
+++ b/utsRendererOpenGL.pas
@@ -184,13 +184,11 @@ begin
glMatrixMode(GL_TEXTURE);
glPushMatrix;
glLoadIdentity;
- glTranslatef(ref.TexCoordPos.x, ref.TexCoordPos.y, 0);
- glScalef(ref.TexCoordSize.x, ref.TexCoordSize.y, 1);
+ glMultMatrixf(@ref.TexMat[0, 0]);
glMatrixMode(GL_MODELVIEW);
glPushMatrix;
- glTranslatef(ref.VertexPos.x, ref.VertexPos.y, 0);
- glScalef(ref.VertexSize.x, ref.VertexSize.y, 1);
+ glMultMatrixf(@ref.VertMat[0, 0]);
glBindBuffer(GL_ARRAY_BUFFER, fVBO);
glEnableClientState(GL_VERTEX_ARRAY);
diff --git a/utsRendererOpenGLES.pas b/utsRendererOpenGLES.pas
new file mode 100644
index 0000000..4fadc57
--- /dev/null
+++ b/utsRendererOpenGLES.pas
@@ -0,0 +1,417 @@
+unit utsRendererOpenGLES;
+
+{$mode objfpc}{$H+}
+{.$DEFINE DEBUG}
+
+interface
+
+uses
+ Classes, SysUtils,
+ utsTextSuite, utsTypes, utsOpenGLUtils, dglOpenGLES;
+
+type
+ TtsRendererOpenGLES = class(TtsBaseOpenGL)
+ private
+ fModelViewMatrix: TtsMatrix4f;
+ fProjMatrix: TtsMatrix4f;
+ fShaderProgram: GLuint;
+ fVBO: GLuint;
+ fShader: GLuint;
+
+ fCharPosLocation: GLint;
+ fCharTexPosLocation: GLint;
+ fCharOffsetLocation: GLint;
+
+ procedure SetModelViewMatrix(aValue: TtsMatrix4f);
+ procedure SetProjectionMatrix(aValue: TtsMatrix4f);
+ procedure SetShaderProgram(aValue: GLuint);
+
+ function LoadShader: GLuint;
+
+ procedure UpdateUniformProjMat;
+ procedure UpdateUniformModelMat;
+ procedure UpdateUniformCharOffset;
+ protected
+ function CreateNewTexture: PtsFontTexture; override;
+ procedure FreeTexture(var aTexture: PtsFontTexture); override;
+ procedure UploadTexData(const aCharRef: TtsCharRenderRefOpenGL;
+ const aCharImage: TtsImage; const X, Y: Integer); override;
+
+ procedure BeginRender; override;
+
+ procedure SetDrawPos(const X, Y: Integer); override;
+ procedure MoveDrawPos(const X, Y: Integer); override;
+ procedure SetColor(const aColor: TtsColor4f); override;
+ procedure Render(const aCharRef: TtsCharRenderRef); override;
+ public
+ property ShaderProgram: GLuint read fShaderProgram write SetShaderProgram;
+ property ProjectionMatrix: TtsMatrix4f read fProjMatrix write SetProjectionMatrix;
+ property ModelViewMatrix: TtsMatrix4f read fModelViewMatrix write SetModelViewMatrix;
+
+ constructor Create(const aContext: TtsContext; const aFormat: TtsFormat);
+ destructor Destroy; override;
+ end;
+
+implementation
+
+type
+ TVertex = packed record
+ pos: array[0..1] of GLfloat;
+ tex: array[0..1] of GLfloat;
+ end;
+
+const
+ ATTRIB_LOCATION_POSITION = 0;
+ ATTRIB_LOCATION_TEXCOORD = 1;
+ ATTRIB_NAME_POSITION = 'inPosition';
+ ATTRIB_NAME_TEXCOORD = 'inTexCoord';
+ UNIFORM_NAME_TEXTURE = 'uTexture';
+ UNIFORM_NAME_MODELVIEWMAT = 'uModelViewMat';
+ UNIFORM_NAME_PROJMAT = 'uProjMat';
+ UNIFORM_NAME_CHARTEXPOS = 'uCharTexPos';
+ UNIFORM_NAME_CHARPOS = 'uCharPos';
+ UNIFORM_NAME_CHAROFFSET = 'uCharOffset';
+ VERTEX_SHADER =
+ 'attribute vec2 inPosition;' +
+ 'attribute vec2 inTexCoord;' +
+ 'varying vec2 vTexCoord;' +
+ 'uniform mat4 uModelViewMat;' +
+ 'uniform mat4 uProjMat;' +
+ 'uniform mat4 uCharTexPos;' +
+ 'uniform mat4 uCharPos;' +
+ 'uniform ivec2 uCharOffset;' +
+ 'void main() {' +
+ ' vec4 pos = uCharPos * vec4(inPosition, 0.0, 1.0);' +
+ ' pos += vec4(uCharOffset, 0.0, 0.0);' +
+ ' gl_Position = uProjMat * uModelViewMat * pos;' +
+ ' vTexCoord = (uCharTexPos * vec4(inTexCoord, 0.0, 1.0)).st;' +
+ '}';
+ FRAGMENT_SHADER =
+ 'uniform sampler2D uTexture;' +
+ 'varying vec2 vTexCoord;' +
+ 'void main() {' +
+ ' gl_FragColor = texture2D(uTexture, vTexCoord);' +
+ '}';
+
+ FORMAT_TYPES: array[TtsFormat] of packed record
+ InternalFormat: GLenum;
+ Format: GLenum;
+ DataFormat: GLenum;
+ end = (
+ ( //tsFormatEmpty
+ InternalFormat: 0;
+ Format: 0;
+ DataFormat: 0),
+ ( //tsFormatRGBA8
+ InternalFormat: GL_RGBA;
+ Format: GL_RGBA;
+ DataFormat: GL_UNSIGNED_BYTE),
+ ( //tsFormatLumAlpha8
+ InternalFormat: GL_LUMINANCE_ALPHA;
+ Format: GL_LUMINANCE_ALPHA;
+ DataFormat: GL_UNSIGNED_BYTE),
+ ( //tsFormatAlpha8
+ InternalFormat: GL_ALPHA;
+ Format: GL_ALPHA;
+ DataFormat: GL_UNSIGNED_BYTE),
+ ( //tsFormatAlpha8
+ InternalFormat: GL_LUMINANCE;
+ Format: GL_LUMINANCE;
+ DataFormat: GL_UNSIGNED_BYTE)
+ );
+
+ VBO_DATA: array[0..3] of TVertex = (
+ (pos: (0.0, 0.0); tex: (0.0, 0.0)),
+ (pos: (0.0, 1.0); tex: (0.0, 1.0)),
+ (pos: (1.0, 0.0); tex: (1.0, 0.0)),
+ (pos: (1.0, 1.0); tex: (1.0, 1.0))
+ );
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+//TtsRendererOpenGLES///////////////////////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+procedure TtsRendererOpenGLES.SetModelViewMatrix(aValue: TtsMatrix4f);
+begin
+ fModelViewMatrix := aValue;
+ UpdateUniformModelMat;
+end;
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+procedure TtsRendererOpenGLES.SetProjectionMatrix(aValue: TtsMatrix4f);
+begin
+ fProjMatrix := aValue;
+ UpdateUniformProjMat;
+end;
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+procedure TtsRendererOpenGLES.SetShaderProgram(aValue: GLuint);
+begin
+ if (fShaderProgram = aValue) then
+ exit;
+
+ fShaderProgram := aValue;
+ fCharPosLocation := glGetUniformLocation(fShaderProgram, UNIFORM_NAME_CHARPOS);
+ fCharTexPosLocation := glGetUniformLocation(fShaderProgram, UNIFORM_NAME_CHARTEXPOS);
+ fCharOffsetLocation := glGetUniformLocation(fShaderProgram, UNIFORM_NAME_CHAROFFSET);
+
+ UpdateUniformProjMat;
+ UpdateUniformModelMat;
+ UpdateUniformCharOffset;
+end;
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+function TtsRendererOpenGLES.LoadShader: GLuint;
+
+{$IFDEF DEBUG}
+ procedure PrintShaderInfo(const aObj: GLuint);
+ var
+ msg: PChar;
+ bLen: GLint;
+ sLen: GLsizei;
+ begin
+ bLen := 0;
+ glGetShaderiv(aObj, GL_INFO_LOG_LENGTH, @bLen);
+ if bLen > 1 then begin
+ GetMem(msg, bLen * SizeOf(Char));
+ try
+ glGetShaderInfoLog(aObj, bLen, @sLen, msg);
+ WriteLn(String(msg));
+ finally
+ FreeMem(msg);
+ end;
+ end;
+ end;
+
+ procedure PrintProgramInfo(const aObj: GLuint);
+ var
+ msg: PChar;
+ bLen: GLint;
+ sLen: GLsizei;
+ begin
+ bLen := 0;
+ glGetProgramiv(aObj, GL_INFO_LOG_LENGTH, @bLen);
+ if bLen > 1 then begin
+ GetMem(msg, bLen * SizeOf(Char));
+ try
+ glGetProgramInfoLog(aObj, bLen, @sLen, msg);
+ WriteLn(String(msg));
+ finally
+ FreeMem(msg);
+ end;
+ end;
+ end;
+{$ENDIF}
+
+ function CreateObj(const aCode: String; const aType: GLenum): GLuint;
+ var
+ code: PAnsiChar;
+ len: GLint;
+ begin
+ result := glCreateShader(aType);
+ len := Length(aCode);
+ code := PAnsiChar(aCode);
+ glShaderSource(result, 1, @code, @len);
+ glCompileShader(result);
+ {$IFDEF DEBUG}PrintShaderInfo(result);{$ENDIF}
+ end;
+
+var
+ fragObj, vertObj: GLuint;
+ uLoc: Integer;
+begin
+ result := glCreateProgram();
+ vertObj := CreateObj(VERTEX_SHADER, GL_VERTEX_SHADER);
+ fragObj := CreateObj(FRAGMENT_SHADER, GL_FRAGMENT_SHADER);
+ glAttachShader(result, vertObj);
+ glAttachShader(result, fragObj);
+ glLinkProgram(result);
+{$IFDEF DEBUG}PrintProgramInfo(result);{$ENDIF}
+ glBindAttribLocation(result, ATTRIB_LOCATION_POSITION, ATTRIB_NAME_POSITION);
+ glBindAttribLocation(result, ATTRIB_LOCATION_TEXCOORD, ATTRIB_NAME_TEXCOORD);
+ uLoc := glGetUniformLocation(result, UNIFORM_NAME_TEXTURE);
+ if (uLoc >= 0) then begin
+ glUseProgram(result);
+ glUniform1i(uLoc, 0);
+ glUseProgram(0);
+ end;
+end;
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+procedure TtsRendererOpenGLES.UpdateUniformProjMat;
+var
+ loc: Integer;
+begin
+ loc := glGetUniformLocation(fShaderProgram, UNIFORM_NAME_PROJMAT);
+ if (loc >= 0) then begin
+ glUseProgram(fShaderProgram);
+ glUniformMatrix4fv(loc, 1, false, @fProjMatrix[0, 0]);
+ glUseProgram(0);
+ end;
+end;
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+procedure TtsRendererOpenGLES.UpdateUniformModelMat;
+var
+ loc: Integer;
+begin
+ loc := glGetUniformLocation(fShaderProgram, UNIFORM_NAME_MODELVIEWMAT);
+ if (loc >= 0) then begin
+ glUseProgram(fShaderProgram);
+ glUniformMatrix4fv(loc, 1, false, @fModelViewMatrix[0, 0]);
+ glUseProgram(0);
+ end;
+end;
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+procedure TtsRendererOpenGLES.UpdateUniformCharOffset;
+begin
+ if (fCharOffsetLocation >= 0) then begin
+ glUseProgram(fShaderProgram);
+ glUniform2iv(fCharOffsetLocation, 1, @RenderPos.x);
+ glUseProgram(0);
+ end;
+end;
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+function TtsRendererOpenGLES.CreateNewTexture: PtsFontTexture;
+begin
+ new(result);
+ try
+ FillByte(result^, SizeOf(result^), 0);
+ new(result^.Usage);
+ FillByte(result^.Usage^, SizeOf(result^.Usage^), 0);
+ result^.Size := TextureSize;
+
+ glGenTextures(1, @result^.ID);
+ glBindTexture(GL_TEXTURE_2D, result^.ID);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexImage2D(
+ GL_TEXTURE_2D,
+ 0,
+ FORMAT_TYPES[Format].InternalFormat,
+ result^.Size,
+ result^.Size,
+ 0,
+ FORMAT_TYPES[Format].Format,
+ FORMAT_TYPES[Format].DataFormat,
+ nil);
+
+ PushTexture(result);
+ except
+ if Assigned(result^.Usage) then
+ Dispose(result^.Usage);
+ Dispose(result);
+ end;
+end;
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+procedure TtsRendererOpenGLES.FreeTexture(var aTexture: PtsFontTexture);
+begin
+ if Assigned(aTexture) then
+ glDeleteTextures(1, @aTexture^.ID);
+ inherited FreeTexture(aTexture);
+end;
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+procedure TtsRendererOpenGLES.UploadTexData(const aCharRef: TtsCharRenderRefOpenGL; const aCharImage: TtsImage; const X, Y: Integer);
+begin
+ glBindTexture(GL_TEXTURE_2D, aCharRef.TextureID);
+ glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
+ glTexSubImage2D(GL_TEXTURE_2D, 0,
+ x, y, aCharImage.Width, aCharImage.Height,
+ FORMAT_TYPES[aCharImage.Format].Format,
+ FORMAT_TYPES[aCharImage.Format].DataFormat,
+ aCharImage.Data);
+end;
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+procedure TtsRendererOpenGLES.BeginRender;
+begin
+ inherited BeginRender;
+ glColor4f(Color.r, Color.g, Color.b, Color.a);
+end;
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+procedure TtsRendererOpenGLES.SetDrawPos(const X, Y: Integer);
+begin
+ inherited SetDrawPos(X, Y);
+ UpdateUniformCharOffset;
+end;
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+procedure TtsRendererOpenGLES.MoveDrawPos(const X, Y: Integer);
+begin
+ inherited MoveDrawPos(X, Y);
+ UpdateUniformCharOffset;
+end;
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+procedure TtsRendererOpenGLES.SetColor(const aColor: TtsColor4f);
+begin
+ inherited SetColor(aColor);
+ glColor4f(Color.r, Color.g, Color.b, Color.a);
+end;
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+procedure TtsRendererOpenGLES.Render(const aCharRef: TtsCharRenderRef);
+var
+ ref: TtsCharRenderRefOpenGL;
+begin
+ if Assigned(aCharRef) and (aCharRef is TtsCharRenderRefOpenGL) then begin
+ ref := (aCharRef as TtsCharRenderRefOpenGL);
+
+ glBindTexture(GL_TEXTURE_2D, ref.TextureID);
+ glBindBuffer(GL_ARRAY_BUFFER, fVBO);
+ glEnableVertexAttribArray(ATTRIB_LOCATION_POSITION);
+ glVertexAttribPointer(ATTRIB_LOCATION_POSITION, 2, GL_FLOAT, false, SizeOf(TVertex), Pointer(0));
+ glEnableVertexAttribArray(ATTRIB_LOCATION_TEXCOORD);
+ glVertexAttribPointer(ATTRIB_LOCATION_TEXCOORD, 2, GL_FLOAT, false, SizeOf(TVertex), Pointer(8));
+ glUseProgram(fShaderProgram);
+
+ if (fCharPosLocation >= 0) then
+ glUniformMatrix4fv(fCharPosLocation, 1, false, @ref.VertMat);
+ if (fCharTexPosLocation >= 0) then
+ glUniformMatrix4fv(fCharTexPosLocation, 1, false, @ref.TexMat);
+
+ glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
+
+ glUseProgram(0);
+ glDisableVertexAttribArray(ATTRIB_LOCATION_TEXCOORD);
+ glDisableVertexAttribArray(ATTRIB_LOCATION_POSITION);
+ glBindTexture(GL_TEXTURE_2D, 0);
+ end;
+end;
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+constructor TtsRendererOpenGLES.Create(const aContext: TtsContext; const aFormat: TtsFormat);
+var
+ viewport: array[0..3] of Integer;
+begin
+ inherited Create(aContext, aFormat);
+
+ glGenBuffers(1, @fVBO);
+ glBindBuffer(GL_ARRAY_BUFFER, fVBO);
+ glBufferData(GL_ARRAY_BUFFER, SizeOf(TVertex) * Length(VBO_DATA), @VBO_DATA[0].pos[0], GL_STATIC_DRAW);
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+
+ glGetIntegerv(GL_VIEWPORT, @viewport);
+ fProjMatrix := tsMatrix4f(
+ tsVector4f(2 / viewport[2], 0.0, 0.0, 0.0),
+ tsVector4f( 0.0, -2 / viewport[3], 0.0, 0.0),
+ tsVector4f( 0.0, 0.0, -0.1, 0.0),
+ tsVector4f( -1.0, 1.0, 0.0, 1.0));
+ fModelViewMatrix := TS_MATRIX_IDENTITY;
+ fShader := LoadShader;
+ ShaderProgram := fShader;
+end;
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+destructor TtsRendererOpenGLES.Destroy;
+begin
+ glDeleteBuffers(1, @fVBO);
+ glDeleteProgram(fShader);
+ inherited Destroy;
+end;
+
+end.
diff --git a/utsTypes.pas b/utsTypes.pas
index 69854eb..850384e 100644
--- a/utsTypes.pas
+++ b/utsTypes.pas
@@ -159,6 +159,9 @@ type
end;
PtsColor4ub = ^TtsColor4ub;
+ TtsVector4f = array[0..3] of Single;
+ TtsMatrix4f = array[0..3] of TtsVector4f;
+
TtsTextMetric = packed record
Ascent: Integer;
Descent: Integer;
@@ -179,10 +182,15 @@ const
TS_MODES_MODULATE_ALL: TtsImageModes = (tsModeModulate, tsModeModulate, tsModeModulate, tsModeModulate);
TS_MODES_MODULATE_ALPHA: TtsImageModes = (tsModeReplace, tsModeReplace, tsModeReplace, tsModeModulate);
+ TS_MATRIX_IDENTITY: TtsMatrix4f = ((1, 0, 0, 0), (0, 1, 0, 0), (0, 0, 1, 0), (0, 0, 0, 1));
+
function tsColor4f(r, g, b, a: Single): TtsColor4f;
function tsModes(r, g, b, a: TtsImageMode): TtsImageModes;
function tsRect(const l, t, r, b: Integer): TtsRect;
function tsPosition(const x, y: Integer): TtsPosition;
+function tsPositionF(const x, y: Single): TtsPositionF;
+function tsVector4f(X, Y, Z, W: Single): TtsVector4f;
+function tsMatrix4f(X, Y, Z, P: TtsVector4f): TtsMatrix4f;
function tsFormatSize(const aFormat: TtsFormat): Integer;
procedure tsFormatMap(const aFormat: TtsFormat; var aData: PByte; const aColor: TtsColor4f);
@@ -235,6 +243,31 @@ begin
result.y := y;
end;
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+function tsPositionF(const x, y: Single): TtsPositionF;
+begin
+ result.x := x;
+ result.y := y;
+end;
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+function tsVector4f(X, Y, Z, W: Single): TtsVector4f;
+begin
+ result[0] := X;
+ result[1] := Y;
+ result[2] := Z;
+ result[3] := W;
+end;
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+function tsMatrix4f(X, Y, Z, P: TtsVector4f): TtsMatrix4f;
+begin
+ result[0] := X;
+ result[1] := Y;
+ result[2] := Z;
+ result[3] := P;
+end;
+
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function tsFormatSize(const aFormat: TtsFormat): Integer;
begin