first version of font atlas generator complete
This commit is contained in:
parent
2780f811f0
commit
63c942294c
Binary file not shown.
@ -10,6 +10,7 @@ import math;
|
|||||||
import core.stdc.math : cosf, sinf;
|
import core.stdc.math : cosf, sinf;
|
||||||
import std.algorithm.sorting;
|
import std.algorithm.sorting;
|
||||||
import fonts;
|
import fonts;
|
||||||
|
import main;
|
||||||
|
|
||||||
f32 g_DELTA;
|
f32 g_DELTA;
|
||||||
|
|
||||||
@ -109,13 +110,7 @@ InitGame(PlatformWindow* window)
|
|||||||
u8[16*16*4] white_tex;
|
u8[16*16*4] white_tex;
|
||||||
white_tex[] = u8.max;
|
white_tex[] = u8.max;
|
||||||
|
|
||||||
u8[] atlas = LoadAssetData(&g.frame_arena, "textures/atlas.png");
|
CreateImageView(&g.rd, &g.font_tex, FONT_ATLAS_TEST.atlas.width, FONT_ATLAS_TEST.atlas.height, 4, FONT_ATLAS_TEST.data);
|
||||||
int width, height, has_ch;
|
|
||||||
auto img = stbi_load_from_memory(atlas.ptr, cast(int)atlas.length, &width, &height, &has_ch, 4);
|
|
||||||
assert(width == FONT_ATLAS.width && height == FONT_ATLAS.height && has_ch == 1, "atlas height and width do not match");
|
|
||||||
u8[] img_slice = img[0 .. width * height * 4];
|
|
||||||
|
|
||||||
CreateImageView(&g.rd, &g.font_tex, FONT_ATLAS.width, FONT_ATLAS.height, 4, img_slice);
|
|
||||||
// TODO: fix buffer overflow between two textures
|
// TODO: fix buffer overflow between two textures
|
||||||
//CreateImageView(&g.rd, &g.default_tex, 16, 16, 4, white_tex);
|
//CreateImageView(&g.rd, &g.default_tex, 16, 16, 4, white_tex);
|
||||||
|
|
||||||
@ -177,7 +172,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, FONT_ATLAS.size, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ");
|
DrawText(g, 200.0, 200.0, 128.0, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ");
|
||||||
|
|
||||||
BeginFrame(&g.rd);
|
BeginFrame(&g.rd);
|
||||||
|
|
||||||
@ -323,19 +318,20 @@ void
|
|||||||
DrawText(Game* g, f32 x, f32 y, f32 px, string str)
|
DrawText(Game* g, f32 x, f32 y, f32 px, string str)
|
||||||
{
|
{
|
||||||
f32 x_pos = x;
|
f32 x_pos = x;
|
||||||
|
f32 scale = px / FONT_ATLAS_TEST.atlas.size;
|
||||||
foreach(ch; str)
|
foreach(ch; str)
|
||||||
{
|
{
|
||||||
foreach(glyph; FONT_ATLAS.glyphs)
|
foreach(glyph; FONT_ATLAS_TEST.atlas.glyphs)
|
||||||
{
|
{
|
||||||
if (ch == glyph.ch)
|
if (ch == glyph.ch)
|
||||||
{
|
{
|
||||||
UIVertex* v = g.ui_vertex_buf.ptr + g.ui_count;
|
UIVertex* v = g.ui_vertex_buf.ptr + g.ui_count;
|
||||||
|
|
||||||
f32 r = px * glyph.plane_right;
|
f32 r = glyph.plane_right * scale;
|
||||||
f32 l = px * glyph.plane_left;
|
f32 l = glyph.plane_left * scale;
|
||||||
f32 w = r - l;
|
f32 w = r - l;
|
||||||
f32 h = px * (glyph.plane_bottom - glyph.plane_top);
|
f32 h = (glyph.plane_bottom - glyph.plane_top) * scale;
|
||||||
f32 y_pos = px * glyph.plane_bottom;
|
f32 y_pos = glyph.plane_top * scale;
|
||||||
|
|
||||||
v.dst_start.x = x_pos + l;
|
v.dst_start.x = x_pos + l;
|
||||||
v.dst_start.y = y + h - y_pos;
|
v.dst_start.y = y + h - y_pos;
|
||||||
@ -349,9 +345,11 @@ DrawText(Game* g, f32 x, f32 y, f32 px, string str)
|
|||||||
|
|
||||||
v.col = Vec4(1.0, 1.0, 1.0, 1.0);
|
v.col = Vec4(1.0, 1.0, 1.0, 1.0);
|
||||||
|
|
||||||
x_pos += px * glyph.advance;
|
x_pos += glyph.advance * scale;
|
||||||
|
|
||||||
AddUIIndices(g);
|
AddUIIndices(g);
|
||||||
|
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
public import includes;
|
import includes;
|
||||||
import std.stdio;
|
import std.stdio;
|
||||||
import aliases;
|
import aliases;
|
||||||
import core.memory;
|
import core.memory;
|
||||||
@ -13,6 +13,8 @@ import font;
|
|||||||
import alloc;
|
import alloc;
|
||||||
import assets;
|
import assets;
|
||||||
|
|
||||||
|
FontAtlasBuf FONT_ATLAS_TEST;
|
||||||
|
|
||||||
// TODO:
|
// TODO:
|
||||||
// 1. Determine how to better handle inputs
|
// 1. Determine how to better handle inputs
|
||||||
// 2. Set up multisampling
|
// 2. Set up multisampling
|
||||||
@ -20,14 +22,14 @@ import assets;
|
|||||||
|
|
||||||
void main(string[] argv)
|
void main(string[] argv)
|
||||||
{
|
{
|
||||||
PlatformWindow window = CreateWindow("Video Game", 1920, 1080);
|
Arena arena = CreateArena(MB(32));
|
||||||
Game g = InitGame(&window);
|
|
||||||
|
|
||||||
Arena arena = CreateArena(MB(8));
|
|
||||||
InitFreeType();
|
InitFreeType();
|
||||||
u8[] font_data = LoadAssetData(&arena, "fonts/NuberNextCondensed-DemiBold.otf");
|
u8[] font_data = LoadAssetData(&arena, "fonts/NuberNextCondensed-DemiBold.otf");
|
||||||
FontFace font = OpenFont(font_data);
|
FontFace font = OpenFont(font_data);
|
||||||
FontAtlasBuf atlas = CreateAtlas(&arena, font, 32.0, 256);
|
FONT_ATLAS_TEST = CreateAtlas(&arena, font, 128.0, 2048);
|
||||||
|
|
||||||
|
PlatformWindow window = CreateWindow("Video Game", 1920, 1080);
|
||||||
|
Game g = InitGame(&window);
|
||||||
|
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
|
|||||||
@ -1685,7 +1685,7 @@ CreateGraphicsPipeline(Vulkan* vk, GfxPipelineInfo* build_info)
|
|||||||
cullMode: VK_CULL_MODE_BACK_BIT,
|
cullMode: VK_CULL_MODE_BACK_BIT,
|
||||||
polygonMode: VK_POLYGON_MODE_FILL,
|
polygonMode: VK_POLYGON_MODE_FILL,
|
||||||
lineWidth: 1.0,
|
lineWidth: 1.0,
|
||||||
frontFace: VK_FRONT_FACE_CLOCKWISE,
|
frontFace: VK_FRONT_FACE_COUNTER_CLOCKWISE,
|
||||||
};
|
};
|
||||||
|
|
||||||
VkPipelineMultisampleStateCreateInfo multisample_info = {
|
VkPipelineMultisampleStateCreateInfo multisample_info = {
|
||||||
|
|||||||
@ -41,10 +41,10 @@ void main()
|
|||||||
vec2 src_pos = (Vertices[gl_VertexIndex] * src_half_size + src_center);
|
vec2 src_pos = (Vertices[gl_VertexIndex] * src_half_size + src_center);
|
||||||
|
|
||||||
vec2 uvs[4] = vec2[4](
|
vec2 uvs[4] = vec2[4](
|
||||||
vec2(in_src_start.x, in_src_end.y),
|
|
||||||
vec2(in_src_start.x, in_src_start.y),
|
vec2(in_src_start.x, in_src_start.y),
|
||||||
vec2(in_src_end.x, in_src_end.y),
|
vec2(in_src_start.x, in_src_end.y),
|
||||||
vec2(in_src_end.x, in_src_start.y)
|
vec2(in_src_end.x, in_src_start.y),
|
||||||
|
vec2(in_src_end.x, in_src_end.y)
|
||||||
);
|
);
|
||||||
|
|
||||||
FragData.color = in_col;
|
FragData.color = in_col;
|
||||||
|
|||||||
@ -18,6 +18,15 @@ InitFreeType()
|
|||||||
FT_Init_FreeType(&FT_LIB);
|
FT_Init_FreeType(&FT_LIB);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CloseFreeType()
|
||||||
|
{
|
||||||
|
if (FT_LIB)
|
||||||
|
{
|
||||||
|
FT_Done_FreeType(FT_LIB);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
FontFace
|
FontFace
|
||||||
OpenFont(u8[] data)
|
OpenFont(u8[] data)
|
||||||
{
|
{
|
||||||
@ -36,12 +45,17 @@ CloseFont(FontFace font)
|
|||||||
}
|
}
|
||||||
|
|
||||||
FontAtlasBuf
|
FontAtlasBuf
|
||||||
CreateAtlas(Arena* arena, FontFace font, f32 size, u64 dimension)
|
CreateAtlas(Arena* arena, FontFace font, f32 size, u32 dimension)
|
||||||
{
|
{
|
||||||
assert(dimension >= 128, "Dimension must be at least 128");
|
assert(dimension >= 128, "Dimension must be at least 128");
|
||||||
|
|
||||||
FontAtlasBuf atlas = {
|
FontAtlasBuf atlas = {
|
||||||
data: AllocArray!(u8)(arena, dimension * dimension * 4),
|
data: AllocArray!(u8)(arena, dimension * dimension * 4),
|
||||||
|
atlas: {
|
||||||
|
size: size,
|
||||||
|
width: dimension,
|
||||||
|
height: dimension,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
// TODO: proper packing algorithm
|
// TODO: proper packing algorithm
|
||||||
@ -88,11 +102,15 @@ CreateAtlas(Arena* arena, FontFace font, f32 size, u64 dimension)
|
|||||||
current_h = 0;
|
current_h = 0;
|
||||||
count = 0;
|
count = 0;
|
||||||
|
|
||||||
|
u32 font_w = font.size.metrics.x_ppem;
|
||||||
|
u32 font_h = font.size.metrics.y_ppem;
|
||||||
|
|
||||||
char_code = FT_Get_First_Char(font, &index);
|
char_code = FT_Get_First_Char(font, &index);
|
||||||
while (index != 0)
|
while (index != 0)
|
||||||
{
|
{
|
||||||
FT_Load_Char(font, char_code, cast(FT_Int32)FT_LOAD_RENDER);
|
FT_Load_Char(font, char_code, cast(FT_Int32)FT_LOAD_RENDER);
|
||||||
|
|
||||||
|
FT_GlyphSlot glyph = font.glyph;
|
||||||
FT_Bitmap* bmp = &font.glyph.bitmap;
|
FT_Bitmap* bmp = &font.glyph.bitmap;
|
||||||
i32 top = font.glyph.bitmap_top;
|
i32 top = font.glyph.bitmap_top;
|
||||||
i32 left = font.glyph.bitmap_left;
|
i32 left = font.glyph.bitmap_left;
|
||||||
@ -103,29 +121,48 @@ CreateAtlas(Arena* arena, FontFace font, f32 size, u64 dimension)
|
|||||||
max_w = 0;
|
max_w = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
i32 x, y;
|
||||||
foreach(r; 0 .. bmp.rows)
|
foreach(r; 0 .. bmp.rows)
|
||||||
{
|
{
|
||||||
i32 y = cast(i32)(max_h + r);
|
y = cast(i32)(max_h + r);
|
||||||
foreach(c; 0 .. bmp.width)
|
foreach(c; 0 .. bmp.width)
|
||||||
{
|
{
|
||||||
i32 x = max_w + left + c;
|
x = max_w + c;
|
||||||
u64 offset = (y*dimension + x) * 4;
|
u64 offset = (y*dimension + x) * 4;
|
||||||
|
|
||||||
atlas.data[offset+0] = 255;
|
atlas.data[offset+0] = bmp.buffer[r*bmp.pitch + c];
|
||||||
atlas.data[offset+1] = 255;
|
atlas.data[offset+1] = bmp.buffer[r*bmp.pitch + c];
|
||||||
atlas.data[offset+2] = 255;
|
atlas.data[offset+2] = bmp.buffer[r*bmp.pitch + c];
|
||||||
atlas.data[offset+3] = bmp.buffer[r*bmp.pitch + c];
|
atlas.data[offset+3] = 255;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Glyph* g = atlas.atlas.glyphs.ptr + count;
|
||||||
|
|
||||||
|
g.ch = cast(dchar)char_code;
|
||||||
|
g.advance = cast(f32)(glyph.advance.x >> 6);
|
||||||
|
g.plane_left = cast(f32)left;
|
||||||
|
g.plane_right = g.plane_left + bmp.width;
|
||||||
|
g.plane_top = cast(f32)top;
|
||||||
|
g.plane_bottom = g.plane_top + bmp.rows;
|
||||||
|
|
||||||
|
g.atlas_top = max_h;
|
||||||
|
g.atlas_left = max_w;
|
||||||
|
g.atlas_bottom = max_h + bmp.rows;
|
||||||
|
g.atlas_right = max_w + bmp.width;
|
||||||
|
|
||||||
max_w += bmp.width;
|
max_w += bmp.width;
|
||||||
current_h = bmp.rows > current_h ? bmp.rows : current_h;
|
current_h = bmp.rows > current_h ? bmp.rows : current_h;
|
||||||
|
|
||||||
char_code = FT_Get_Next_Char(font, char_code, &index);
|
char_code = FT_Get_Next_Char(font, char_code, &index);
|
||||||
|
|
||||||
|
count += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
return atlas;
|
return atlas;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user