342 lines
10 KiB
Ada
342 lines
10 KiB
Ada
with
|
|
openGL.Glyph.texture,
|
|
openGL.Glyph.Container,
|
|
openGL.Palette,
|
|
openGL.Tasks,
|
|
|
|
GL.Binding,
|
|
GL.lean,
|
|
GL.Pointers,
|
|
|
|
freetype_c.Binding,
|
|
ada.unchecked_Conversion;
|
|
|
|
package body openGL.FontImpl.Texture
|
|
is
|
|
---------
|
|
-- Forge
|
|
--
|
|
|
|
function to_FontImpl_texture (ftFont : access Font.item'Class;
|
|
fontFilePath : in String) return fontImpl.texture.item
|
|
is
|
|
use freetype_c.Binding;
|
|
Success : Boolean;
|
|
begin
|
|
return Self : fontImpl.texture.item
|
|
do
|
|
define (Self'Access, ftFont, fontFilePath);
|
|
|
|
Self.load_Flags := freetype_c.FT_Int (FT_LOAD_NO_HINTING_flag or FT_LOAD_NO_BITMAP_flag);
|
|
Self.numGlyphs := Self.Face.GlyphCount;
|
|
Self.remGlyphs := Self.numGlyphs;
|
|
|
|
Success := Self.FaceSize (20);
|
|
|
|
if not Success then
|
|
raise Error with "Unable to set font facesize for '" & fontFilePath & "'.";
|
|
end if;
|
|
end return;
|
|
end to_FontImpl_texture;
|
|
|
|
|
|
|
|
function new_FontImpl_texture (ftFont : access Font.item'Class;
|
|
fontFilePath : in String) return access fontImpl.texture.item'Class
|
|
is
|
|
use freetype_c.Binding;
|
|
|
|
Self : constant fontImpl.texture.view := new fontImpl.texture.item;
|
|
Success : Boolean;
|
|
begin
|
|
define (Self, ftFont, fontFilePath);
|
|
|
|
Self.load_Flags := freetype_c.FT_Int (FT_LOAD_NO_HINTING_flag or FT_LOAD_NO_BITMAP_flag);
|
|
Self.numGlyphs := Self.Face.GlyphCount;
|
|
Self.remGlyphs := Self.numGlyphs;
|
|
|
|
Success := Self.FaceSize (20);
|
|
|
|
if not Success then
|
|
raise Error with "Unable to set font facesize for '" & fontFilePath & "'.";
|
|
end if;
|
|
|
|
return Self;
|
|
end new_FontImpl_texture;
|
|
|
|
|
|
|
|
function to_FontImpl_texture (ftFont : access openGL.Font.item'Class;
|
|
pBufferBytes : in unsigned_char_Pointer;
|
|
bufferSizeInBytes : in Natural) return fontImpl.texture.item
|
|
is
|
|
use freetype_c.Binding;
|
|
begin
|
|
return Self : fontImpl.texture.item
|
|
do
|
|
define (Self'Access, ftFont, pBufferBytes, bufferSizeInBytes);
|
|
|
|
Self.load_Flags := freetype_c.FT_Int ( FT_LOAD_NO_HINTING_flag
|
|
or FT_LOAD_NO_BITMAP_flag);
|
|
Self.numGlyphs := Self.face.GlyphCount;
|
|
Self.remGlyphs := Self.numGlyphs;
|
|
end return;
|
|
end to_FontImpl_texture;
|
|
|
|
|
|
|
|
function new_FontImpl_texture (ftFont : access Font.item'Class;
|
|
pBufferBytes : in unsigned_char_Pointer;
|
|
bufferSizeInBytes : in Natural) return fontImpl.texture.view
|
|
is
|
|
begin
|
|
return new fontImpl.texture.item' (to_FontImpl_texture (ftFont,
|
|
pBufferBytes,
|
|
bufferSizeInBytes));
|
|
end new_FontImpl_texture;
|
|
|
|
|
|
|
|
procedure free_Textures (Self : in out Item)
|
|
is
|
|
use texture_name_Vectors,
|
|
GL.lean;
|
|
|
|
Cursor : texture_name_Vectors.Cursor := Self.textureIDList.First;
|
|
the_Name : aliased openGL.Texture.texture_Name;
|
|
begin
|
|
Tasks.check;
|
|
|
|
while has_Element (Cursor)
|
|
loop
|
|
the_Name := Element (Cursor);
|
|
glDeleteTextures (1, the_Name'Access);
|
|
|
|
next (Cursor);
|
|
end loop;
|
|
end free_Textures;
|
|
|
|
|
|
|
|
overriding
|
|
procedure destruct (Self : in out Item)
|
|
is
|
|
use type ada.Containers.Count_type;
|
|
begin
|
|
destruct (FontImpl.item (Self)); -- Destroy base class.
|
|
|
|
if Self.textureIDList.Length > 0
|
|
then
|
|
Self.free_Textures;
|
|
end if;
|
|
end destruct;
|
|
|
|
|
|
--------------
|
|
-- Attributes
|
|
--
|
|
|
|
overriding
|
|
function FaceSize (Self : access Item; Size : in Natural;
|
|
x_Res, y_Res : in Natural := 72) return Boolean
|
|
is
|
|
type access_FontImpl is access all FontImpl.item;
|
|
Success : Boolean;
|
|
begin
|
|
if not Self.textureIDList.is_empty
|
|
then
|
|
Self.free_Textures;
|
|
Self.textureIDList.clear;
|
|
|
|
Self.numGlyphs := Self.Face.GlyphCount;
|
|
Self.remGlyphs := Self.numGlyphs;
|
|
end if;
|
|
|
|
Success := access_FontImpl (Self).FaceSize (Size, x_Res, y_Res);
|
|
return Success;
|
|
end FaceSize;
|
|
|
|
|
|
|
|
function Render (Self : access Item; Text : in String;
|
|
Length : in Integer;
|
|
Position : in Vector_3;
|
|
Spacing : in Vector_3;
|
|
Mode : in renderMode) return Vector_3
|
|
is
|
|
use GL,
|
|
GL.Binding;
|
|
|
|
function to_Integer is new ada.unchecked_Conversion (fontImpl.RenderMode, Integer);
|
|
|
|
Tmp : Vector_3;
|
|
|
|
begin
|
|
Tasks.check;
|
|
|
|
glEnable (GL_BLEND);
|
|
glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
|
glEnable (GL_TEXTURE_2D);
|
|
|
|
GlyphImpl.texture.ResetActiveTexture;
|
|
|
|
Tmp := FontImpl.item (Self.all).Render (Text, Length,
|
|
Position, Spacing,
|
|
to_Integer (Mode));
|
|
return Tmp;
|
|
end Render;
|
|
|
|
|
|
|
|
function MakeGlyphImpl (Self : access Item; ftGlyph : in freetype_c.FT_GlyphSlot.item) return access Glyph.item'Class
|
|
is
|
|
tempGlyph : Glyph.Container.Glyph_view;
|
|
begin
|
|
Self.glyphHeight := Integer (Self.charSize.Height + 0.5);
|
|
Self.glyphWidth := Integer (Self.charSize.Width + 0.5);
|
|
|
|
if Self.glyphHeight < 1 then Self.glyphHeight := 1; end if;
|
|
if Self.glyphWidth < 1 then Self.glyphWidth := 1; end if;
|
|
|
|
if Self.textureIDList.is_empty
|
|
then
|
|
Self.textureIDList.append (Self.CreateTexture);
|
|
Self.xOffset := Self.Padding;
|
|
Self.yOffset := Self.Padding;
|
|
end if;
|
|
|
|
if Self.xOffset > (Integer (Self.textureWidth) - Self.glyphWidth)
|
|
then
|
|
Self.xOffset := Self.Padding;
|
|
Self.yOffset := Self.yOffset + Self.glyphHeight;
|
|
|
|
if Self.yOffset > (Integer (Self.textureHeight) - Self.glyphHeight)
|
|
then
|
|
Self.textureIDList.append (Self.CreateTexture);
|
|
Self.yOffset := Self.Padding;
|
|
end if;
|
|
end if;
|
|
|
|
tempGlyph := openGL.Glyph.texture.new_Glyph (ftGlyph,
|
|
Self.textureIDList.last_Element,
|
|
Self.xOffset,
|
|
Self.yOffset,
|
|
Integer (Self.textureWidth),
|
|
Integer (Self.textureHeight)).all'Access;
|
|
|
|
Self.xOffset := Self.xOffset + Integer ( tempGlyph.BBox.Box.Upper (1)
|
|
- tempGlyph.BBox.Box.Lower (1)
|
|
+ Real (Self.Padding)
|
|
+ 0.5);
|
|
Self.remGlyphs := Self.remGlyphs - 1;
|
|
|
|
return tempGlyph;
|
|
end MakeGlyphImpl;
|
|
|
|
|
|
|
|
function Quad (Self : access Item; for_Character : in Character) return GlyphImpl.texture.Quad_t
|
|
is
|
|
use freetype.charMap;
|
|
|
|
Success : constant Boolean := Self.CheckGlyph (to_characterCode (for_Character)) with unreferenced;
|
|
the_Glyph : constant Glyph.Container.Glyph_view := Self.glyphList.Glyph (to_characterCode (for_Character));
|
|
begin
|
|
return Glyph.texture.item (the_Glyph.all).Quad ([0.0, 0.0, 0.0]);
|
|
end Quad;
|
|
|
|
|
|
|
|
procedure CalculateTextureSize (Self : in out Item)
|
|
is
|
|
use openGL.Texture,
|
|
GL,
|
|
GL.Binding;
|
|
|
|
use type GL.GLsizei;
|
|
|
|
H : Integer;
|
|
|
|
begin
|
|
Tasks.check;
|
|
|
|
if Self.maximumGLTextureSize = 0
|
|
then
|
|
Self.maximumGLTextureSize := 1024;
|
|
glGetIntegerv (GL_MAX_TEXTURE_SIZE, Self.maximumGLTextureSize'Access);
|
|
|
|
pragma assert (Self.maximumGLTextureSize /= 0); -- If you hit this then you have an invalid openGL context.
|
|
end if;
|
|
|
|
begin
|
|
Self.textureWidth := Power_of_2_Ceiling ( (Self.remGlyphs * Self.glyphWidth)
|
|
+ (Self.Padding * 2));
|
|
exception
|
|
when constraint_Error =>
|
|
Self.textureWidth := Self.maximumGLTextureSize;
|
|
end;
|
|
|
|
if Self.textureWidth > Self.maximumGLTextureSize
|
|
then Self.textureWidth := Self.maximumGLTextureSize;
|
|
end if;
|
|
|
|
H := Integer ( Real (Integer (Self.textureWidth) - (Self.Padding * 2))
|
|
/ Real (Self.glyphWidth)
|
|
+ 0.5);
|
|
Self.textureHeight := Power_of_2_Ceiling ( ((Self.numGlyphs / H) + 1)
|
|
* Self.glyphHeight);
|
|
|
|
if Self.textureHeight > Self.maximumGLTextureSize
|
|
then Self.textureHeight := Self.maximumGLTextureSize;
|
|
end if;
|
|
end CalculateTextureSize;
|
|
|
|
|
|
|
|
function CreateTexture (Self : access Item) return openGL.Texture.texture_Name
|
|
is
|
|
use openGL.Palette,
|
|
GL,
|
|
GL.Binding;
|
|
begin
|
|
Tasks.check;
|
|
|
|
Self.CalculateTextureSize;
|
|
|
|
declare
|
|
use GL.Pointers;
|
|
|
|
the_Image : Image (1 .. Index_t (self.textureHeight),
|
|
1 .. Index_t (Self.textureWidth)) := (others => [others => +Black]);
|
|
|
|
textID : aliased openGL.Texture.texture_Name;
|
|
begin
|
|
glGenTextures (1, textID'Access);
|
|
|
|
glBindTexture (GL_TEXTURE_2D, textID);
|
|
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
|
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
|
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
|
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
|
|
|
glTexImage2D (GL_TEXTURE_2D,
|
|
0, GL_ALPHA,
|
|
Self.textureWidth, Self.textureHeight,
|
|
0, GL_ALPHA,
|
|
GL_UNSIGNED_BYTE,
|
|
to_GLvoid_access (the_Image (1, 1).Red'Access));
|
|
return textID;
|
|
end;
|
|
end CreateTexture;
|
|
|
|
|
|
|
|
function gl_Texture (Self : in Item) return openGL.Texture.texture_Name
|
|
is
|
|
begin
|
|
return Self.textureIDList.last_Element;
|
|
end gl_Texture;
|
|
|
|
|
|
end openGL.FontImpl.Texture;
|