proper font fixes
This commit is contained in:
parent
eee6918981
commit
be8814cda2
123
fonts.d
123
fonts.d
@ -4,19 +4,26 @@ import dlibincludes;
|
|||||||
import dlib.aliases;
|
import dlib.aliases;
|
||||||
import dlib.util;
|
import dlib.util;
|
||||||
import dlib.alloc;
|
import dlib.alloc;
|
||||||
|
import dlib.math;
|
||||||
|
import std.math.traits : isNaN;
|
||||||
|
|
||||||
struct FontAtlas
|
struct FontAtlas
|
||||||
{
|
{
|
||||||
f32 size;
|
Glyph[128] glyphs;
|
||||||
f32 units_per_em;
|
FontMetrics metrics;
|
||||||
f32 ascent;
|
u32 size;
|
||||||
f32 descent;
|
UVec2 dimensions;
|
||||||
f32 line_gap;
|
|
||||||
f32 max_advance;
|
alias metrics this;
|
||||||
f32 line_height;
|
}
|
||||||
u32 width;
|
|
||||||
u32 height;
|
struct FontMetrics
|
||||||
Glyph[128] glyphs;
|
{
|
||||||
|
f32 ascent;
|
||||||
|
f32 descent;
|
||||||
|
f32 line_gap;
|
||||||
|
f32 line_height;
|
||||||
|
f32 max_advance;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Glyph
|
struct Glyph
|
||||||
@ -86,39 +93,46 @@ DeMultiply(u8 color, u8 alpha)
|
|||||||
return v > 255 ? 255 : cast(u8)v;
|
return v > 255 ? 255 : cast(u8)v;
|
||||||
}
|
}
|
||||||
|
|
||||||
FontAtlasBuf
|
u32
|
||||||
CreateAtlas(Arena* arena, FontFace font, f32 size, u32 dimension, bool y_origin_top = true)
|
TextSize(f32 s)
|
||||||
{
|
{
|
||||||
assert(dimension >= 128, "Dimension must be at least 128");
|
return cast(u32)((96.0f/72.0f) * s);
|
||||||
|
}
|
||||||
|
|
||||||
|
FontAtlasBuf
|
||||||
|
CreateAtlas(Arena* arena, FontFace font, u32 size, UVec2 atlas_dim, bool y_origin_top = true)
|
||||||
|
{
|
||||||
FontAtlasBuf abuf = {
|
FontAtlasBuf abuf = {
|
||||||
data: Alloc!(u8)(arena, dimension * dimension * 4),
|
data: Alloc!(u8)(arena, atlas_dim.x * atlas_dim.y * 4),
|
||||||
atlas: {
|
atlas: {
|
||||||
size: size,
|
size: size,
|
||||||
width: dimension,
|
dimensions: atlas_dim,
|
||||||
height: dimension,
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
// TODO: proper packing algorithm
|
// TODO: proper packing algorithm
|
||||||
if(font != null)
|
if(font != null)
|
||||||
{
|
{
|
||||||
FT_Set_Pixel_Sizes(font, 0, cast(FT_UInt)((96.0f/72.0f) * size));
|
FT_Set_Pixel_Sizes(font, 0, TextSize(size));
|
||||||
|
|
||||||
i64 bbox_ymax = font.bbox.yMax >> 6;
|
i64 bbox_ymax = font.bbox.yMax >> 6;
|
||||||
i64 bbox_ymin = font.bbox.yMin >> 6;
|
i64 bbox_ymin = font.bbox.yMin >> 6;
|
||||||
|
|
||||||
abuf.atlas.line_height = size;
|
i64 line_h = bbox_ymax - bbox_ymin;
|
||||||
abuf.atlas.units_per_em = cast(f32)font.units_per_EM;
|
|
||||||
abuf.atlas.ascent = cast(f32)font.ascender;
|
|
||||||
abuf.atlas.descent = cast(f32)font.descender;
|
|
||||||
abuf.atlas.line_gap = cast(f32)(font.height - font.ascender + font.descender);
|
|
||||||
abuf.atlas.max_advance = cast(f32)(font.max_advance_width>>6);
|
|
||||||
|
|
||||||
u32 max_w, max_h, current_h, count;
|
u64 baseline = font.size.metrics.ascender >> 6;
|
||||||
|
u64 line_height = (font.size.metrics.height >> 6)+1;
|
||||||
|
|
||||||
|
Logf("%s %s", baseline, line_height);
|
||||||
|
|
||||||
|
abuf.atlas.line_height = line_height;
|
||||||
|
abuf.atlas.max_advance = font.size.metrics.max_advance >> 6;
|
||||||
|
|
||||||
|
u32 max_w, max_h, count;
|
||||||
|
|
||||||
i32 font_size = Float26(size);
|
i32 font_size = Float26(size);
|
||||||
|
|
||||||
|
const u32 PADDING = 2;
|
||||||
foreach(FT_ULong char_code; 0 .. 0x7F)
|
foreach(FT_ULong char_code; 0 .. 0x7F)
|
||||||
{
|
{
|
||||||
FT_Error res = FT_Load_Char(font, char_code, cast(FT_Int32)FT_LOAD_RENDER);
|
FT_Error res = FT_Load_Char(font, char_code, cast(FT_Int32)FT_LOAD_RENDER);
|
||||||
@ -129,25 +143,23 @@ CreateAtlas(Arena* arena, FontFace font, f32 size, u32 dimension, bool y_origin_
|
|||||||
|
|
||||||
u32 bmp_w = font.glyph.bitmap.width;
|
u32 bmp_w = font.glyph.bitmap.width;
|
||||||
u32 bmp_h = font.glyph.bitmap.rows;
|
u32 bmp_h = font.glyph.bitmap.rows;
|
||||||
if(max_w + bmp_w > dimension)
|
if(max_w + bmp_w > atlas_dim.x)
|
||||||
{
|
{
|
||||||
max_h += current_h;
|
max_h += line_height+PADDING;
|
||||||
max_w = 0;
|
max_w = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(max_h < dimension, "Unable to pack atlas within dimensions");
|
if(max_h > atlas_dim.y)
|
||||||
|
{
|
||||||
|
Logf("Unable to pack atlas within dimensions provided");
|
||||||
|
assert(false);
|
||||||
|
}
|
||||||
|
|
||||||
max_w += bmp_w;
|
max_w += bmp_w;
|
||||||
current_h = bmp_h > current_h ? bmp_h : current_h;
|
|
||||||
count += 1;
|
count += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
const u32 PADDING = 2;
|
max_w = max_h = count = 0;
|
||||||
|
|
||||||
max_w = PADDING;
|
|
||||||
max_h = PADDING;
|
|
||||||
current_h = 0;
|
|
||||||
count = 0;
|
|
||||||
|
|
||||||
foreach(FT_ULong char_code; 0 .. 0x7F)
|
foreach(FT_ULong char_code; 0 .. 0x7F)
|
||||||
{
|
{
|
||||||
@ -160,24 +172,26 @@ CreateAtlas(Arena* arena, FontFace font, f32 size, u32 dimension, bool y_origin_
|
|||||||
FT_GlyphSlot glyph = font.glyph;
|
FT_GlyphSlot glyph = font.glyph;
|
||||||
FT_Bitmap* bmp = &font.glyph.bitmap;
|
FT_Bitmap* bmp = &font.glyph.bitmap;
|
||||||
|
|
||||||
if(max_w + bmp.rows > dimension)
|
if(max_w + bmp.rows > atlas_dim.x)
|
||||||
{
|
{
|
||||||
max_h += cast(u32)(size) + PADDING;
|
max_h += line_height+PADDING;
|
||||||
max_w = PADDING;
|
max_w = PADDING;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
i64 base = Max(baseline, font.glyph.bitmap_top);
|
||||||
|
|
||||||
switch(bmp.pixel_mode)
|
switch(bmp.pixel_mode)
|
||||||
{
|
{
|
||||||
case FT_PIXEL_MODE_BGRA:
|
case FT_PIXEL_MODE_BGRA:
|
||||||
{
|
{
|
||||||
i32 x, y;
|
u64 x, y;
|
||||||
foreach(r; 0 .. bmp.rows)
|
foreach(r; 0 .. bmp.rows)
|
||||||
{
|
{
|
||||||
y = cast(i32)(max_h + r);
|
y = (base - font.glyph.bitmap_top + r) + max_h;
|
||||||
foreach(c; 0 .. bmp.width)
|
foreach(c; 0 .. bmp.width)
|
||||||
{
|
{
|
||||||
x = max_w + c;
|
x = max_w + c;
|
||||||
u64 offset = (y*dimension + x) * 4;
|
u64 offset = (y*atlas_dim.y + x) * 4;
|
||||||
|
|
||||||
u8 p_b = bmp.buffer[offset+0];
|
u8 p_b = bmp.buffer[offset+0];
|
||||||
u8 p_g = bmp.buffer[offset+1];
|
u8 p_g = bmp.buffer[offset+1];
|
||||||
@ -191,13 +205,13 @@ CreateAtlas(Arena* arena, FontFace font, f32 size, u32 dimension, bool y_origin_
|
|||||||
case FT_PIXEL_MODE_MONO:
|
case FT_PIXEL_MODE_MONO:
|
||||||
{
|
{
|
||||||
u32 pitch = bmp.pitch;
|
u32 pitch = bmp.pitch;
|
||||||
u8* buf = bmp.buffer;
|
u8* buf = bmp.buffer;
|
||||||
i32 x, y;
|
u64 x, y;
|
||||||
foreach(r; 0 .. bmp.rows)
|
foreach(r; 0 .. bmp.rows)
|
||||||
{
|
{
|
||||||
u8 bits = 0;
|
u8 bits = 0;
|
||||||
u8* buf_ptr = buf;
|
u8* buf_ptr = buf;
|
||||||
y = cast(i32)(max_h + r);
|
y = (base - font.glyph.bitmap_top + r) + max_h;
|
||||||
foreach(c; 0 .. bmp.width)
|
foreach(c; 0 .. bmp.width)
|
||||||
{
|
{
|
||||||
if((c & 7) == 0)
|
if((c & 7) == 0)
|
||||||
@ -207,7 +221,7 @@ CreateAtlas(Arena* arena, FontFace font, f32 size, u32 dimension, bool y_origin_
|
|||||||
}
|
}
|
||||||
|
|
||||||
x = max_w + c;
|
x = max_w + c;
|
||||||
u64 offset = (y*dimension + x) * 4;
|
u64 offset = (y*atlas_dim.y + x) * 4;
|
||||||
|
|
||||||
abuf.data[offset .. offset+4] = [255, 255, 255, bits & 0x80 ? 255 : 0];
|
abuf.data[offset .. offset+4] = [255, 255, 255, bits & 0x80 ? 255 : 0];
|
||||||
bits <<= 1;
|
bits <<= 1;
|
||||||
@ -218,14 +232,15 @@ CreateAtlas(Arena* arena, FontFace font, f32 size, u32 dimension, bool y_origin_
|
|||||||
} break;
|
} break;
|
||||||
case FT_PIXEL_MODE_GRAY:
|
case FT_PIXEL_MODE_GRAY:
|
||||||
{
|
{
|
||||||
i32 x, y;
|
u64 x, y;
|
||||||
foreach(r; 0 .. bmp.rows)
|
foreach(r; 0 .. bmp.rows)
|
||||||
{
|
{
|
||||||
y = cast(i32)(max_h + r);
|
y = (base - font.glyph.bitmap_top + r) + max_h;
|
||||||
|
Logf("y %s %s %s %s", baseline - font.glyph.bitmap_top +r, baseline, font.glyph.bitmap_top, r);
|
||||||
foreach(c; 0 .. bmp.width)
|
foreach(c; 0 .. bmp.width)
|
||||||
{
|
{
|
||||||
x = max_w + c;
|
x = max_w + c;
|
||||||
u64 offset = (y*dimension + x) * 4;
|
u64 offset = (y*atlas_dim.y + x) * 4;
|
||||||
|
|
||||||
abuf.data[offset .. offset+4] = [255, 255, 255, bmp.buffer[r*bmp.pitch + c]];
|
abuf.data[offset .. offset+4] = [255, 255, 255, bmp.buffer[r*bmp.pitch + c]];
|
||||||
}
|
}
|
||||||
@ -248,17 +263,16 @@ CreateAtlas(Arena* arena, FontFace font, f32 size, u32 dimension, bool y_origin_
|
|||||||
g.ch = cast(dchar)char_code;
|
g.ch = cast(dchar)char_code;
|
||||||
g.advance = cast(f32)(glyph.advance.x >> 6);
|
g.advance = cast(f32)(glyph.advance.x >> 6);
|
||||||
g.plane_left = left;
|
g.plane_left = left;
|
||||||
g.plane_right = g.plane_left + width;
|
g.plane_right = g.plane_left + bmp.width;
|
||||||
g.plane_top = cast(f32)(bbox_ymax) - top;
|
g.plane_top = 0.0;
|
||||||
g.plane_bottom = g.plane_top + height;
|
g.plane_bottom = line_height;
|
||||||
|
|
||||||
g.atlas_top = max_h;
|
g.atlas_top = max_h;
|
||||||
g.atlas_left = max_w;
|
g.atlas_left = max_w;
|
||||||
g.atlas_bottom = max_h + bmp.rows;
|
g.atlas_bottom = max_h + line_height;
|
||||||
g.atlas_right = max_w + bmp.width;
|
g.atlas_right = max_w + bmp.width;
|
||||||
|
|
||||||
max_w += bmp.width + PADDING;
|
max_w += bmp.width + PADDING;
|
||||||
current_h = bmp.rows > current_h ? bmp.rows : current_h;
|
|
||||||
|
|
||||||
count += 1;
|
count += 1;
|
||||||
}
|
}
|
||||||
@ -268,3 +282,4 @@ CreateAtlas(Arena* arena, FontFace font, f32 size, u32 dimension, bool y_origin_
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user