start work on font atlas creation
This commit is contained in:
parent
ead9c307bb
commit
2780f811f0
4
dub.json
4
dub.json
@ -11,11 +11,11 @@
|
|||||||
"sourceFiles-windows": [],
|
"sourceFiles-windows": [],
|
||||||
"importPaths": ["src/gears", "src/codegen", "src/shared", "external/xxhash", "external/inteli"],
|
"importPaths": ["src/gears", "src/codegen", "src/shared", "external/xxhash", "external/inteli"],
|
||||||
"sourcePaths": ["src/gears", "src/codegen", "src/shared", "external/xxhash", "external/inteli"],
|
"sourcePaths": ["src/gears", "src/codegen", "src/shared", "external/xxhash", "external/inteli"],
|
||||||
"libs-linux": ["xcb", "X11", "X11-xcb", "vulkan", "stdc++", "xcb-xfixes"],
|
"libs-linux": ["xcb", "X11", "X11-xcb", "vulkan", "stdc++", "xcb-xfixes", "freetype"],
|
||||||
"libs-windows": [],
|
"libs-windows": [],
|
||||||
"preGenerateCommands-linux": ["./build.sh", "build/Packer"],
|
"preGenerateCommands-linux": ["./build.sh", "build/Packer"],
|
||||||
"preGenerateCommands-windows": [],
|
"preGenerateCommands-windows": [],
|
||||||
"dflags": ["-Xcc=-mno-sse"],
|
"dflags": ["-Xcc=-mno-sse", "-P-I/usr/include/freetype2"],
|
||||||
"dflags-dmd": ["-P=-DSTBI_NO_SIMD"]
|
"dflags-dmd": ["-P=-DSTBI_NO_SIMD"]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
@ -116,7 +116,8 @@ InitGame(PlatformWindow* window)
|
|||||||
u8[] img_slice = img[0 .. width * height * 4];
|
u8[] img_slice = img[0 .. width * height * 4];
|
||||||
|
|
||||||
CreateImageView(&g.rd, &g.font_tex, FONT_ATLAS.width, FONT_ATLAS.height, 4, img_slice);
|
CreateImageView(&g.rd, &g.font_tex, FONT_ATLAS.width, FONT_ATLAS.height, 4, img_slice);
|
||||||
CreateImageView(&g.rd, &g.default_tex, 16, 16, 4, white_tex);
|
// TODO: fix buffer overflow between two textures
|
||||||
|
//CreateImageView(&g.rd, &g.default_tex, 16, 16, 4, white_tex);
|
||||||
|
|
||||||
WriteGUI(&g.rd, g.ui_desc_set, &g.font_tex);
|
WriteGUI(&g.rd, g.ui_desc_set, &g.font_tex);
|
||||||
|
|
||||||
@ -176,7 +177,7 @@ Cycle(Game* g)
|
|||||||
Reset(&g.frame_arena);
|
Reset(&g.frame_arena);
|
||||||
|
|
||||||
DrawRect(g, 500.0, 500.0, 800.0, 800.0, Vec4(0.2, 0.3, 0.7, 1.0));
|
DrawRect(g, 500.0, 500.0, 800.0, 800.0, Vec4(0.2, 0.3, 0.7, 1.0));
|
||||||
DrawText(g, 200.0, 200.0, 32.0, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ");
|
DrawText(g, 200.0, 200.0, FONT_ATLAS.size, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ");
|
||||||
|
|
||||||
BeginFrame(&g.rd);
|
BeginFrame(&g.rd);
|
||||||
|
|
||||||
@ -330,13 +331,15 @@ DrawText(Game* g, f32 x, f32 y, f32 px, string str)
|
|||||||
{
|
{
|
||||||
UIVertex* v = g.ui_vertex_buf.ptr + g.ui_count;
|
UIVertex* v = g.ui_vertex_buf.ptr + g.ui_count;
|
||||||
|
|
||||||
f32 w = px * (glyph.plane_right - glyph.plane_left);
|
f32 r = px * glyph.plane_right;
|
||||||
|
f32 l = px * glyph.plane_left;
|
||||||
|
f32 w = r - l;
|
||||||
f32 h = px * (glyph.plane_bottom - glyph.plane_top);
|
f32 h = px * (glyph.plane_bottom - glyph.plane_top);
|
||||||
f32 y_pos = px * glyph.plane_bottom;
|
f32 y_pos = px * glyph.plane_bottom;
|
||||||
|
|
||||||
v.dst_start.x = x_pos;
|
v.dst_start.x = x_pos + l;
|
||||||
v.dst_start.y = y + h - y_pos;
|
v.dst_start.y = y + h - y_pos;
|
||||||
v.dst_end.x = x_pos + w;
|
v.dst_end.x = x_pos + w + l;
|
||||||
v.dst_end.y = y - y_pos;
|
v.dst_end.y = y - y_pos;
|
||||||
|
|
||||||
v.src_start.x = glyph.atlas_left;
|
v.src_start.x = glyph.atlas_left;
|
||||||
|
|||||||
@ -9,6 +9,10 @@ import core.simd;
|
|||||||
import math;
|
import math;
|
||||||
import core.stdc.string : memcpy;
|
import core.stdc.string : memcpy;
|
||||||
|
|
||||||
|
import font;
|
||||||
|
import alloc;
|
||||||
|
import assets;
|
||||||
|
|
||||||
// TODO:
|
// TODO:
|
||||||
// 1. Determine how to better handle inputs
|
// 1. Determine how to better handle inputs
|
||||||
// 2. Set up multisampling
|
// 2. Set up multisampling
|
||||||
@ -19,6 +23,12 @@ void main(string[] argv)
|
|||||||
PlatformWindow window = CreateWindow("Video Game", 1920, 1080);
|
PlatformWindow window = CreateWindow("Video Game", 1920, 1080);
|
||||||
Game g = InitGame(&window);
|
Game g = InitGame(&window);
|
||||||
|
|
||||||
|
Arena arena = CreateArena(MB(8));
|
||||||
|
InitFreeType();
|
||||||
|
u8[] font_data = LoadAssetData(&arena, "fonts/NuberNextCondensed-DemiBold.otf");
|
||||||
|
FontFace font = OpenFont(font_data);
|
||||||
|
FontAtlasBuf atlas = CreateAtlas(&arena, font, 32.0, 256);
|
||||||
|
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
HandleEvents(&window);
|
HandleEvents(&window);
|
||||||
|
|||||||
131
src/shared/font.d
Normal file
131
src/shared/font.d
Normal file
@ -0,0 +1,131 @@
|
|||||||
|
import aliases;
|
||||||
|
import includes;
|
||||||
|
import util;
|
||||||
|
import alloc;
|
||||||
|
|
||||||
|
FT_Library FT_LIB;
|
||||||
|
alias FontFace = FT_Face;
|
||||||
|
|
||||||
|
struct FontAtlasBuf
|
||||||
|
{
|
||||||
|
u8[] data;
|
||||||
|
FontAtlas atlas;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
InitFreeType()
|
||||||
|
{
|
||||||
|
FT_Init_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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
FontAtlasBuf
|
||||||
|
CreateAtlas(Arena* arena, FontFace font, f32 size, u64 dimension)
|
||||||
|
{
|
||||||
|
assert(dimension >= 128, "Dimension must be at least 128");
|
||||||
|
|
||||||
|
FontAtlasBuf atlas = {
|
||||||
|
data: AllocArray!(u8)(arena, dimension * dimension * 4),
|
||||||
|
};
|
||||||
|
|
||||||
|
// TODO: proper packing algorithm
|
||||||
|
if (font != null)
|
||||||
|
{
|
||||||
|
FT_Set_Pixel_Sizes(font, 0, cast(FT_UInt)((96.0/72.0) * size));
|
||||||
|
|
||||||
|
i64 f_ascent = cast(i64)(font.size.metrics.ascender >> 6);
|
||||||
|
i64 f_descent = cast(i64)(font.size.metrics.descender >> 6);
|
||||||
|
i64 f_height = cast(i64)(font.size.metrics.height >> 6);
|
||||||
|
|
||||||
|
u32 max_w = 0;
|
||||||
|
u32 max_h = 0;
|
||||||
|
u32 current_h = 0;
|
||||||
|
u32 count = 0;
|
||||||
|
|
||||||
|
FT_UInt index;
|
||||||
|
FT_ULong char_code = FT_Get_First_Char(font, &index);
|
||||||
|
while (index != 0)
|
||||||
|
{
|
||||||
|
FT_Load_Char(font, char_code, cast(FT_Int32)FT_LOAD_RENDER);
|
||||||
|
|
||||||
|
u32 bmp_w = font.glyph.bitmap.width;
|
||||||
|
u32 bmp_h = font.glyph.bitmap.rows;
|
||||||
|
if (max_w + bmp_w > dimension)
|
||||||
|
{
|
||||||
|
max_h += current_h;
|
||||||
|
max_w = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(max_h < dimension, "Unable to pack atlas within dimensions");
|
||||||
|
|
||||||
|
max_w += bmp_w;
|
||||||
|
current_h = bmp_h > current_h ? bmp_h : current_h;
|
||||||
|
count += 1;
|
||||||
|
|
||||||
|
char_code = FT_Get_Next_Char(font, char_code, &index);
|
||||||
|
}
|
||||||
|
|
||||||
|
atlas.atlas.glyphs = AllocArray!(Glyph)(arena, count);
|
||||||
|
|
||||||
|
max_w = 0;
|
||||||
|
max_h = 0;
|
||||||
|
current_h = 0;
|
||||||
|
count = 0;
|
||||||
|
|
||||||
|
char_code = FT_Get_First_Char(font, &index);
|
||||||
|
while (index != 0)
|
||||||
|
{
|
||||||
|
FT_Load_Char(font, char_code, cast(FT_Int32)FT_LOAD_RENDER);
|
||||||
|
|
||||||
|
FT_Bitmap* bmp = &font.glyph.bitmap;
|
||||||
|
i32 top = font.glyph.bitmap_top;
|
||||||
|
i32 left = font.glyph.bitmap_left;
|
||||||
|
|
||||||
|
if (max_w + bmp.rows > dimension)
|
||||||
|
{
|
||||||
|
max_h += current_h;
|
||||||
|
max_w = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach(r; 0 .. bmp.rows)
|
||||||
|
{
|
||||||
|
i32 y = cast(i32)(max_h + r);
|
||||||
|
foreach(c; 0 .. bmp.width)
|
||||||
|
{
|
||||||
|
i32 x = max_w + left + c;
|
||||||
|
u64 offset = (y*dimension + x) * 4;
|
||||||
|
|
||||||
|
atlas.data[offset+0] = 255;
|
||||||
|
atlas.data[offset+1] = 255;
|
||||||
|
atlas.data[offset+2] = 255;
|
||||||
|
atlas.data[offset+3] = bmp.buffer[r*bmp.pitch + c];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
max_w += bmp.width;
|
||||||
|
current_h = bmp.rows > current_h ? bmp.rows : current_h;
|
||||||
|
|
||||||
|
char_code = FT_Get_Next_Char(font, char_code, &index);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return atlas;
|
||||||
|
}
|
||||||
|
|
||||||
@ -6,6 +6,9 @@
|
|||||||
# include <X11/Xlib.h>
|
# include <X11/Xlib.h>
|
||||||
# include <X11/keysym.h>
|
# include <X11/keysym.h>
|
||||||
# include <X11/extensions/Xfixes.h>
|
# include <X11/extensions/Xfixes.h>
|
||||||
|
# include <ft2build.h>
|
||||||
|
# include FT_FREETYPE_H
|
||||||
|
# include FT_GLYPH_H
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <xmmintrin.h>
|
#include <xmmintrin.h>
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user