restore freetype2
This commit is contained in:
parent
c65b5401ab
commit
d6580c58f4
@ -16,9 +16,9 @@
|
||||
# include <GL/glxext.h>
|
||||
#endif
|
||||
|
||||
// # include <ft2build.h>
|
||||
// # include FT_FREETYPE_H
|
||||
// # include FT_GLYPH_H
|
||||
# include <ft2build.h>
|
||||
# include FT_FREETYPE_H
|
||||
# include FT_GLYPH_H
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
263
dlib/fonts.d
263
dlib/fonts.d
@ -1,5 +1,7 @@
|
||||
module dlib.fonts;
|
||||
|
||||
import dlibincludes;
|
||||
|
||||
import dlib.externdecl;
|
||||
import dlib.aliases;
|
||||
import dlib.util;
|
||||
@ -12,7 +14,9 @@ import std.traits;
|
||||
|
||||
import stb_truetype;
|
||||
|
||||
alias FontFace = stbtt_fontinfo;
|
||||
__gshared FT_Library FT_LIB;
|
||||
alias FontFace = FT_Face;
|
||||
alias STBFontFace = stbtt_fontinfo;
|
||||
|
||||
const u32 FONT_MAX_BANDS = 8;
|
||||
const u32 FONT_TEX_WIDTH = 4096;
|
||||
@ -140,6 +144,19 @@ struct SlugBuffer
|
||||
}
|
||||
|
||||
struct FontAtlas
|
||||
{
|
||||
Glyph[128] glyphs;
|
||||
u8[] data;
|
||||
u32 size;
|
||||
UVec2 dimensions;
|
||||
f32 ascent;
|
||||
f32 descent;
|
||||
f32 line_gap;
|
||||
f32 line_height;
|
||||
f32 max_advance;
|
||||
}
|
||||
|
||||
struct MSDFFontAtlas
|
||||
{
|
||||
Glyph[128] glyphs;
|
||||
u32 pixel_size;
|
||||
@ -210,6 +227,225 @@ struct MSDFGlyph
|
||||
GlyphBounds atlas; // Pixels
|
||||
}
|
||||
|
||||
shared static this()
|
||||
{
|
||||
FT_Init_FreeType(&FT_LIB);
|
||||
}
|
||||
|
||||
shared static ~this()
|
||||
{
|
||||
FT_Done_FreeType(FT_LIB);
|
||||
}
|
||||
|
||||
FontFace
|
||||
OpenFont(u8[] data)
|
||||
{
|
||||
FontFace font;
|
||||
FT_New_Memory_Face(FT_LIB, data.ptr, cast(FT_Long)data.length, 0, &font);
|
||||
return font;
|
||||
}
|
||||
|
||||
void
|
||||
CloseFont(FontFace font)
|
||||
{
|
||||
if(font != null)
|
||||
{
|
||||
FT_Done_Face(font);
|
||||
}
|
||||
}
|
||||
|
||||
i32
|
||||
Float26(f32 f)
|
||||
{
|
||||
return cast(i32)round(cast(f32)(1 << 6) * f);
|
||||
}
|
||||
|
||||
u8
|
||||
DeMultiply(u8 color, u8 alpha)
|
||||
{
|
||||
u32 v = cast(u32)(255.0 * cast(f32)(color) / cast(f32)(alpha + f32.epsilon) + 0.5);
|
||||
return v > 255 ? 255 : cast(u8)v;
|
||||
}
|
||||
|
||||
u32
|
||||
TextSize(f32 s)
|
||||
{
|
||||
return cast(u32)((96.0f/72.0f) * s);
|
||||
}
|
||||
|
||||
FontAtlas
|
||||
CreateAtlas(Arena* arena, FontFace font, u32 size, UVec2 atlas_dim)
|
||||
{
|
||||
FontAtlas atlas = {
|
||||
data: Alloc!(u8)(arena, atlas_dim.x * atlas_dim.y * 4),
|
||||
size: size,
|
||||
dimensions: atlas_dim,
|
||||
};
|
||||
|
||||
// TODO: proper packing algorithm
|
||||
if(font != null)
|
||||
{
|
||||
FT_Set_Pixel_Sizes(font, 0, TextSize(size));
|
||||
|
||||
i64 bbox_ymax = font.bbox.yMax >> 6;
|
||||
i64 bbox_ymin = font.bbox.yMin >> 6;
|
||||
|
||||
u64 baseline = font.size.metrics.ascender >> 6;
|
||||
u64 line_height = (font.size.metrics.height >> 6)+1;
|
||||
|
||||
atlas.line_height = line_height;
|
||||
atlas.max_advance = font.size.metrics.max_advance >> 6;
|
||||
|
||||
u32 max_w, max_h, count;
|
||||
|
||||
i32 font_size = Float26(size);
|
||||
|
||||
const u32 PADDING = 2;
|
||||
foreach(FT_ULong char_code; 0 .. 0x7F)
|
||||
{
|
||||
FT_Error res = FT_Load_Char(font, char_code, cast(FT_Int32)FT_LOAD_RENDER);
|
||||
if(res != 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
u32 bmp_w = font.glyph.bitmap.width;
|
||||
u32 bmp_h = font.glyph.bitmap.rows;
|
||||
if(max_w + bmp_w > atlas_dim.x)
|
||||
{
|
||||
max_h += line_height+PADDING;
|
||||
max_w = 0;
|
||||
}
|
||||
|
||||
if(max_h > atlas_dim.y)
|
||||
{
|
||||
Logf("Unable to pack atlas within dimensions provided");
|
||||
assert(false);
|
||||
}
|
||||
|
||||
max_w += bmp_w;
|
||||
count += 1;
|
||||
}
|
||||
|
||||
max_w = max_h = count = 0;
|
||||
|
||||
foreach(FT_ULong char_code; 0 .. 0x7F)
|
||||
{
|
||||
FT_Error res = FT_Load_Char(font, char_code, cast(FT_Int32)FT_LOAD_RENDER);
|
||||
if(res != 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
FT_GlyphSlot glyph = font.glyph;
|
||||
FT_Bitmap* bmp = &font.glyph.bitmap;
|
||||
|
||||
if(max_w + bmp.rows > atlas_dim.x)
|
||||
{
|
||||
max_h += line_height+PADDING;
|
||||
max_w = PADDING;
|
||||
}
|
||||
|
||||
i64 base = Max(baseline, font.glyph.bitmap_top);
|
||||
|
||||
switch(bmp.pixel_mode)
|
||||
{
|
||||
case FT_PIXEL_MODE_BGRA:
|
||||
{
|
||||
u64 x, y;
|
||||
foreach(r; 0 .. bmp.rows)
|
||||
{
|
||||
y = (base - font.glyph.bitmap_top + r) + max_h;
|
||||
foreach(c; 0 .. bmp.width)
|
||||
{
|
||||
x = max_w + c;
|
||||
u64 offset = (y*atlas_dim.y + x) * 4;
|
||||
|
||||
u8 p_b = bmp.buffer[offset+0];
|
||||
u8 p_g = bmp.buffer[offset+1];
|
||||
u8 p_r = bmp.buffer[offset+2];
|
||||
u8 p_a = bmp.buffer[offset+3];
|
||||
|
||||
atlas.data[offset .. offset+4] = [DeMultiply(p_r, p_a), DeMultiply(p_b, p_a), DeMultiply(p_g, p_a), p_a];
|
||||
}
|
||||
}
|
||||
} break;
|
||||
case FT_PIXEL_MODE_MONO:
|
||||
{
|
||||
u32 pitch = bmp.pitch;
|
||||
u8* buf = bmp.buffer;
|
||||
u64 x, y;
|
||||
foreach(r; 0 .. bmp.rows)
|
||||
{
|
||||
u8 bits = 0;
|
||||
u8* buf_ptr = buf;
|
||||
y = (base - font.glyph.bitmap_top + r) + max_h;
|
||||
foreach(c; 0 .. bmp.width)
|
||||
{
|
||||
if((c & 7) == 0)
|
||||
{
|
||||
bits = *buf_ptr;
|
||||
buf_ptr += 1;
|
||||
}
|
||||
|
||||
x = max_w + c;
|
||||
u64 offset = (y*atlas_dim.y + x) * 4;
|
||||
|
||||
atlas.data[offset .. offset+4] = [255, 255, 255, bits & 0x80 ? 255 : 0];
|
||||
bits <<= 1;
|
||||
}
|
||||
|
||||
buf += pitch;
|
||||
}
|
||||
} break;
|
||||
case FT_PIXEL_MODE_GRAY:
|
||||
{
|
||||
u64 x, y;
|
||||
foreach(r; 0 .. bmp.rows)
|
||||
{
|
||||
y = (base - font.glyph.bitmap_top + r) + max_h;
|
||||
foreach(c; 0 .. bmp.width)
|
||||
{
|
||||
x = max_w + c;
|
||||
u64 offset = (y*atlas_dim.y + x) * 4;
|
||||
|
||||
atlas.data[offset .. offset+4] = [255, 255, 255, bmp.buffer[r*bmp.pitch + c]];
|
||||
}
|
||||
}
|
||||
} break;
|
||||
default:
|
||||
assert(false, "Unknown pixel_mode value");
|
||||
break;
|
||||
}
|
||||
|
||||
Glyph* g = atlas.glyphs.ptr + char_code;
|
||||
|
||||
f32 height = glyph.metrics.height >> 6;
|
||||
f32 width = glyph.metrics.width >> 6;
|
||||
f32 top = font.glyph.bitmap_top;
|
||||
f32 left = font.glyph.bitmap_left;
|
||||
|
||||
g.ch = cast(dchar)char_code;
|
||||
g.advance = cast(f32)(glyph.advance.x >> 6);
|
||||
g.plane.left = left;
|
||||
g.plane.right = g.plane.left + bmp.width;
|
||||
g.plane.top = 0.0;
|
||||
g.plane.bottom = line_height;
|
||||
|
||||
g.atlas.top = max_h;
|
||||
g.atlas.left = max_w;
|
||||
g.atlas.bottom = max_h + line_height;
|
||||
g.atlas.right = max_w + bmp.width;
|
||||
|
||||
max_w += bmp.width + PADDING;
|
||||
|
||||
count += 1;
|
||||
}
|
||||
}
|
||||
|
||||
return atlas;
|
||||
}
|
||||
|
||||
static MSDFInfo
|
||||
GenerateMSDF(string file_path)()
|
||||
{
|
||||
@ -338,31 +574,18 @@ GenerateMSDF(string file_path)()
|
||||
return result;
|
||||
}
|
||||
|
||||
FontFace
|
||||
OpenFont(u8[] data)
|
||||
STBFontFace
|
||||
STBOpenFont(u8[] data)
|
||||
{
|
||||
FontFace font;
|
||||
STBFontFace font;
|
||||
stbtt_InitFont(&font, data.ptr, stbtt_GetFontOffsetForIndex(data.ptr, 0));
|
||||
return font;
|
||||
}
|
||||
|
||||
u8
|
||||
DeMultiply(u8 color, u8 alpha)
|
||||
MSDFFontAtlas
|
||||
PopulateAtlasGlyphInfo(STBFontFace* font, u32 pixel_size, const MSDFInfo* msdf_info)
|
||||
{
|
||||
u32 v = cast(u32)(255.0 * cast(f32)(color) / cast(f32)(alpha + f32.epsilon) + 0.5);
|
||||
return v > 255 ? 255 : cast(u8)v;
|
||||
}
|
||||
|
||||
u32
|
||||
TextSize(f32 s)
|
||||
{
|
||||
return cast(u32)((96.0f/72.0f) * s);
|
||||
}
|
||||
|
||||
FontAtlas
|
||||
PopulateAtlasGlyphInfo(FontFace* font, u32 pixel_size, const MSDFInfo* msdf_info)
|
||||
{
|
||||
FontAtlas atlas;
|
||||
MSDFFontAtlas atlas;
|
||||
|
||||
// TODO: proper packing algorithm
|
||||
if(font != null)
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user