Finished system font listing and loading on windows

master
Allen Webster 2017-11-17 14:22:12 -05:00
parent 4f3b07168d
commit 54de2b4812
14 changed files with 652 additions and 336 deletions

View File

@ -41,7 +41,7 @@
#define FCPP_FORBID_MALLOC
#include "4cpp/4cpp_lexer.h"
#include "4ed_doubly_linked_list.cpp"
#include "4ed_linked_node_macros.h"
#include "4ed_font.cpp"

View File

@ -4514,16 +4514,8 @@ step_file_view(System_Functions *system, View *view, Models *models, View *activ
}
break;
#if 0
case CV_Mode_Font_Loading:
{
}break;
#endif
case CV_Mode_Global_Font:
case CV_Mode_Font:
case CV_Mode_Global_Font:
{
Editing_File *file = view->file_data.file;
Assert(file != 0);
@ -4535,36 +4527,31 @@ step_file_view(System_Functions *system, View *view, Models *models, View *activ
view->color_mode = CV_Mode_Library;
}
Font_ID font_id = models->global_font_id;
if (view->color_mode == CV_Mode_Font){
font_id = file->settings.font_id;
}
gui_begin_scrollable(target, scroll_context, view->gui_scroll, 9*view->line_height, show_scrollbar);
Font_ID new_font_id = font_id;
u32 total_count = system->font.get_count();
for (u32 i = 0; i < total_count; ++i){
Font_ID this_font_id = i + 1;
Font_ID font_id = file->settings.font_id;
Font_ID new_font_id = 0;
i32 total_count = system->font.get_loadable_count();
for (i32 i = 0; i < total_count; ++i){
Font_Loadable_Description loadable = {0};
system->font.get_loadable(i, &loadable);
char name_space[256];
String name = make_fixed_width_string(name_space);
name.size = system->font.get_name_by_id(this_font_id, name.str, name.memory_size);
id.id[0] = (u64)this_font_id + 1;
if (this_font_id != font_id){
if (gui_do_font_button(target, id, this_font_id, name)){
new_font_id = this_font_id;
id.id[0] = (u64)i + 1;
if (loadable.valid){
String name = make_string(loadable.display_name, loadable.display_len);
if (gui_do_button(target, id, name)){
if (new_font_id == 0){
new_font_id = font_get_id_by_name(system, name);
if (new_font_id == 0){
new_font_id = system->font.load_new_font(&loadable.stub);
}
}
}
}
else{
char message_space[256];
message = make_fixed_width_string(message_space);
copy_ss(&message, make_lit_string("currently selected: "));
append_ss(&message, name);
gui_do_font_button(target, id, this_font_id, message);
}
}
if (font_id != new_font_id){
if (new_font_id != 0 && new_font_id != font_id){
if (view->color_mode == CV_Mode_Font){
file_set_font(system, models, file, new_font_id);
}
@ -4572,6 +4559,8 @@ step_file_view(System_Functions *system, View *view, Models *models, View *activ
global_set_font(system, models, new_font_id);
}
}
gui_end_scrollable(target);
}break;
case CV_Mode_Adjusting:
@ -4588,8 +4577,7 @@ step_file_view(System_Functions *system, View *view, Models *models, View *activ
view->color_mode = CV_Mode_Library;
}
gui_begin_scrollable(target, scroll_context, view->gui_scroll,
9 * view->line_height, show_scrollbar);
gui_begin_scrollable(target, scroll_context, view->gui_scroll, 9*view->line_height, show_scrollbar);
i32 next_color_editing = view->current_color_editing;

View File

@ -14,11 +14,18 @@
// NOTE(allen): A description of an available font.
struct Font_Loadable_Stub{
b32 in_local_folder;
b32 load_from_path;
i32 len;
char name[256];
};
struct Font_Loadable_Description{
b32 valid;
Font_Loadable_Stub stub;
i32 display_len;
char display_name[64];
};
// NOTE(allen): Settings that the are specified that determine how a font should be loaded and rendered.
struct Font_Settings{
Font_Loadable_Stub stub;
@ -93,11 +100,20 @@ struct Font_Pointers{
typedef u32 Font_ID;
// NOTE(allen): Platform layer calls - implemented in a "font provider"
#define Sys_Font_Get_Count_Sig(n) u32 (n)(void)
#define Sys_Font_Get_Loadable_Count_Sig(n) i32 (n)(void)
typedef Sys_Font_Get_Loadable_Count_Sig(Font_Get_Loadable_Count_Function);
#define Sys_Font_Get_Loadable_Sig(n,i,o) void (n)(i32 i, Font_Loadable_Description *o)
typedef Sys_Font_Get_Loadable_Sig(Font_Get_Loadable_Function, index, out);
#define Sys_Font_Load_New_Font_Sig(n,s) Font_ID (n)(Font_Loadable_Stub *s)
typedef Sys_Font_Load_New_Font_Sig(Font_Load_New_Font_Function, stub);
#define Sys_Font_Get_Count_Sig(n) i32 (n)(void)
typedef Sys_Font_Get_Count_Sig(Font_Get_Count_Function);
#define Sys_Font_Get_Name_By_ID_Sig(n, str_out, capacity) i32 (n)(Font_ID font_id, char *str_out, u32 capacity)
typedef Sys_Font_Get_Name_By_ID_Sig(Font_Get_Name_By_ID_Function, str_out, capacity);
#define Sys_Font_Get_Name_By_ID_Sig(n, out, cap) i32 (n)(Font_ID font_id, char *out, u32 cap)
typedef Sys_Font_Get_Name_By_ID_Sig(Font_Get_Name_By_ID_Function, out, cap);
#define Sys_Font_Get_Pointers_By_ID_Sig(n,font_id) Font_Pointers (n)(Font_ID font_id)
typedef Sys_Font_Get_Pointers_By_ID_Sig(Font_Get_Pointers_By_ID_Function, font_id);
@ -105,13 +121,16 @@ typedef Sys_Font_Get_Pointers_By_ID_Sig(Font_Get_Pointers_By_ID_Function, font_i
#define Sys_Font_Load_Page_Sig(n,s,m,p,pn) void (n)(Font_Settings *s, Font_Metrics *m, Glyph_Page *p, u32 pn)
typedef Sys_Font_Load_Page_Sig(Font_Load_Page_Function, settings, metrics, page, page_number);
#define Sys_Font_Allocate_Sig(n) void* (n)(i32 size)
typedef Sys_Font_Allocate_Sig(Font_Allocate_Function);
#define Sys_Font_Allocate_Sig(n,size) void* (n)(i32 size)
typedef Sys_Font_Allocate_Sig(Font_Allocate_Function,size);
#define Sys_Font_Free_Sig(n) void (n)(void *ptr)
typedef Sys_Font_Free_Sig(Font_Free_Function);
#define Sys_Font_Free_Sig(n,ptr) void (n)(void *ptr)
typedef Sys_Font_Free_Sig(Font_Free_Function,ptr);
struct Font_Functions{
Font_Get_Loadable_Count_Function *get_loadable_count;
Font_Get_Loadable_Function *get_loadable;
Font_Load_New_Font_Function *load_new_font;
Font_Get_Count_Function *get_count;
Font_Get_Name_By_ID_Function *get_name_by_id;
Font_Get_Pointers_By_ID_Function *get_pointers_by_id;

View File

@ -32,12 +32,57 @@ font_ft_flags(b32 use_hinting){
return(ft_flags);
}
internal void
internal b32
font_ft_get_face(FT_Library ft, Font_Loadable_Stub *stub, FT_Face *face){
b32 success = true;
if (stub->load_from_path){
FT_Error error = FT_New_Face(ft, stub->name, 0, face);
success = (error == 0);
}
else{
Font_Raw_Data data = system_font_data(stub->name);
if (data.size > 0){
FT_Error error = FT_New_Memory_Face(ft, data.data, data.size, 0, face);
success = (error == 0);
}
else{
success = false;
}
end_temp_memory(data.temp);
}
return(success);
}
internal b32
font_load_name(Font_Loadable_Stub *stub, char *buffer, i32 capacity){
b32 success = false;
// TODO(allen): Stop redoing all this init for each call.
FT_Library ft;
FT_Init_FreeType(&ft);
FT_Face face;
if (font_ft_get_face(ft, stub, &face)){
char *name = face->family_name;
i32 name_len = str_size(name);
if (name_len < capacity){
memcpy(buffer, name, name_len + 1);
success = true;
}
}
FT_Done_FreeType(ft);
return(success);
}
internal b32
font_load_page_layout(Font_Settings *settings, Font_Metrics *metrics, Glyph_Page *page, u32 page_number){
Assert(page != 0);
memset(page, 0, sizeof(*page));
page->page_number = page_number;
page->has_layout = true;
char *filename = settings->stub.name;
u32 pt_size = settings->pt_size;
b32 use_hinting = settings->use_hinting;
@ -46,77 +91,83 @@ font_load_page_layout(Font_Settings *settings, Font_Metrics *metrics, Glyph_Page
FT_Init_FreeType(&ft);
FT_Face face;
FT_New_Face(ft, filename, 0, &face);
b32 has_a_good_face = font_ft_get_face(ft, &settings->stub, &face);
FT_Size_RequestRec_ size = {};
size.type = FT_SIZE_REQUEST_TYPE_NOMINAL;
size.height = pt_size << 6;
FT_Request_Size(face, &size);
page->page_number = page_number;
// NOTE(allen): Determine glyph layout dimensions
i32 max_glyph_w = face->size->metrics.x_ppem;
i32 max_glyph_h = metrics->height;
i32 pen_y_descent = max_glyph_h + 2;
i32 tex_width = 64;
i32 tex_height = 0;
do {
tex_width *= 2;
f32 glyphs_per_row = ceilf(tex_width/(f32)max_glyph_w);
f32 rows = ceilf(GLYPHS_PER_PAGE/glyphs_per_row);
tex_height = ceil32(rows*pen_y_descent);
} while(tex_height > tex_width);
tex_height = round_up_pot_u32(tex_height);
i32 pen_x = 0;
i32 pen_y = 0;
// NOTE(allen): Fill the glyph bounds array
u32 ft_flags = font_ft_flags(use_hinting);
u32 codepoint = (page_number << 8);
Glyph_Bounds *glyph_out = &page->glyphs[0];
f32 *advance_out = &page->advance[0];
for (u32 i = 0; i < GLYPHS_PER_PAGE; ++i, ++codepoint, ++glyph_out, ++advance_out){
if (FT_Load_Char(face, codepoint, ft_flags) == 0){
i32 w = face->glyph->bitmap.width;
i32 h = face->glyph->bitmap.rows;
i32 ascent = metrics->ascent;
// NOTE(allen): Move to next line if necessary
if (pen_x + w >= tex_width){
pen_x = 0;
pen_y += pen_y_descent;
}
// NOTE(allen): Set all this stuff the renderer needs
glyph_out->x0 = (f32)(pen_x);
glyph_out->y0 = (f32)(pen_y);
glyph_out->x1 = (f32)(pen_x + w);
glyph_out->y1 = (f32)(pen_y + h + 1);
glyph_out->xoff = (f32)(face->glyph->bitmap_left);
glyph_out->yoff = (f32)(ascent - face->glyph->bitmap_top);
glyph_out->xoff2 = glyph_out->xoff + w;
glyph_out->yoff2 = glyph_out->yoff + h + 1;
// TODO(allen): maybe advance data should be integers?
*advance_out = (f32)ceil32(face->glyph->advance.x / 64.0f);
pen_x = ceil32(glyph_out->x1 + 1);
if (has_a_good_face){
FT_Size_RequestRec_ size = {};
size.type = FT_SIZE_REQUEST_TYPE_NOMINAL;
size.height = pt_size << 6;
FT_Request_Size(face, &size);
// NOTE(allen): Determine glyph layout dimensions
i32 max_glyph_w = face->size->metrics.x_ppem;
i32 max_glyph_h = metrics->height;
i32 pen_y_descent = max_glyph_h + 2;
i32 tex_width = 64;
i32 tex_height = 0;
do {
tex_width *= 2;
f32 glyphs_per_row = ceilf(tex_width/(f32)max_glyph_w);
f32 rows = ceilf(GLYPHS_PER_PAGE/glyphs_per_row);
tex_height = ceil32(rows*pen_y_descent);
}
while(tex_height > tex_width);
tex_height = round_up_pot_u32(tex_height);
i32 pen_x = 0;
i32 pen_y = 0;
// NOTE(allen): Fill the glyph bounds array
u32 ft_flags = font_ft_flags(use_hinting);
u32 codepoint = (page_number << 8);
Glyph_Bounds *glyph_out = &page->glyphs[0];
f32 *advance_out = &page->advance[0];
for (u32 i = 0; i < GLYPHS_PER_PAGE; ++i, ++codepoint, ++glyph_out, ++advance_out){
if (FT_Load_Char(face, codepoint, ft_flags) == 0){
i32 w = face->glyph->bitmap.width;
i32 h = face->glyph->bitmap.rows;
i32 ascent = metrics->ascent;
// NOTE(allen): Move to next line if necessary
if (pen_x + w >= tex_width){
pen_x = 0;
pen_y += pen_y_descent;
}
// NOTE(allen): Set all this stuff the renderer needs
glyph_out->x0 = (f32)(pen_x);
glyph_out->y0 = (f32)(pen_y);
glyph_out->x1 = (f32)(pen_x + w);
glyph_out->y1 = (f32)(pen_y + h + 1);
glyph_out->xoff = (f32)(face->glyph->bitmap_left);
glyph_out->yoff = (f32)(ascent - face->glyph->bitmap_top);
glyph_out->xoff2 = glyph_out->xoff + w;
glyph_out->yoff2 = glyph_out->yoff + h + 1;
// TODO(allen): maybe advance data should be integers?
*advance_out = (f32)ceil32(face->glyph->advance.x / 64.0f);
pen_x = ceil32(glyph_out->x1 + 1);
}
}
// TODO(allen): Not sure setting tex_height here is right... double check.
tex_height = round_up_pot_u32(pen_y + pen_y_descent);
page->tex_width = tex_width;
page->tex_height = tex_height;
}
else{
page->tex_width = 1;
page->tex_height = 1;
}
// TODO(allen): Not sure setting tex_height here is right... double check.
tex_height = round_up_pot_u32(pen_y + pen_y_descent);
page->tex_width = tex_width;
page->tex_height = tex_height;
page->has_layout = true;
FT_Done_FreeType(ft);
return(has_a_good_face);
}
internal u32*
@ -125,7 +176,6 @@ font_load_page_pixels(Partition *part, Font_Settings *settings, Glyph_Page *page
Assert(page->has_layout);
Assert(page->page_number == page_number);
char *filename = settings->stub.name;
i32 pt_size = settings->pt_size;
b32 use_hinting = settings->use_hinting;
@ -134,51 +184,77 @@ font_load_page_pixels(Partition *part, Font_Settings *settings, Glyph_Page *page
FT_Init_FreeType(&ft);
FT_Face face;
FT_New_Face(ft, filename, 0, &face);
b32 has_a_good_face = font_ft_get_face(ft, &settings->stub, &face);
u32 *pixels = 0;
FT_Size_RequestRec_ size = {};
size.type = FT_SIZE_REQUEST_TYPE_NOMINAL;
size.height = pt_size << 6;
FT_Request_Size(face, &size);
page->page_number = page_number;
// NOTE(allen): Prepare a pixel buffer.
i32 tex_width = page->tex_width;
i32 tex_height = page->tex_height;
u32* pixels = push_array(part, u32, tex_width*tex_height);
memset(pixels, 0, tex_width*tex_height*sizeof(u32));
// NOTE(allen): Fill the texture
u32 ft_flags = font_ft_flags(use_hinting);
u32 codepoint = (page_number << 8);
Glyph_Bounds *glyph_ptr = &page->glyphs[0];
for (i32 i = 0; i < GLYPHS_PER_PAGE; ++i, ++codepoint, ++glyph_ptr){
if (FT_Load_Char(face, codepoint, ft_flags) == 0){
// NOTE(allen): Extract this glyph's dimensions.
i32 x = (i32)glyph_ptr->x0;
i32 y = (i32)glyph_ptr->y0;
i32 w = (i32)(glyph_ptr->x1 - glyph_ptr->x0);
i32 h = (i32)(glyph_ptr->y1 - glyph_ptr->y0 - 1);
if (has_a_good_face){
FT_Size_RequestRec_ size = {};
size.type = FT_SIZE_REQUEST_TYPE_NOMINAL;
size.height = pt_size << 6;
FT_Request_Size(face, &size);
page->page_number = page_number;
// NOTE(allen): Prepare a pixel buffer.
i32 tex_width = page->tex_width;
i32 tex_height = page->tex_height;
pixels = push_array(part, u32, tex_width*tex_height);
if (pixels != 0){
memset(pixels, 0, tex_width*tex_height*sizeof(u32));
// NOTE(allen): Write to the pixels.
u8 *src = face->glyph->bitmap.buffer;
i32 pitch = face->glyph->bitmap.pitch;
i32 end_x = x + w;
i32 end_y = y + h;
for (i32 Y = y, YY = 0; Y < end_y; ++Y, ++YY){
for (i32 X = x, XX = 0; X < end_x; ++X, ++XX){
pixels[Y*tex_width + X] = 0x00FFFFFF + (0x01000000*src[YY*pitch + XX]);
//pixels[Y*tex_width + X] = (0x01010101*src[YY*pitch + XX]);
// NOTE(allen): Fill the texture
u32 ft_flags = font_ft_flags(use_hinting);
u32 codepoint = (page_number << 8);
Glyph_Bounds *glyph_ptr = &page->glyphs[0];
for (i32 i = 0; i < GLYPHS_PER_PAGE; ++i, ++codepoint, ++glyph_ptr){
if (FT_Load_Char(face, codepoint, ft_flags) == 0){
// NOTE(allen): Extract this glyph's dimensions.
i32 x = (i32)glyph_ptr->x0;
i32 y = (i32)glyph_ptr->y0;
i32 w = (i32)(glyph_ptr->x1 - glyph_ptr->x0);
i32 h = (i32)(glyph_ptr->y1 - glyph_ptr->y0 - 1);
// NOTE(allen): Write to the pixels.
u8 *src = face->glyph->bitmap.buffer;
i32 end_x = x + w;
i32 end_y = y + h;
if (src != 0){
i32 pitch = face->glyph->bitmap.pitch;
for (i32 Y = y, YY = 0; Y < end_y; ++Y, ++YY){
for (i32 X = x, XX = 0; X < end_x; ++X, ++XX){
//pixels[Y*tex_width + X] = (0x01010101*src[YY*pitch + XX]);
pixels[Y*tex_width + X] = 0x00FFFFFF + (0x01000000*src[YY*pitch + XX]);
}
}
}
else{
for (i32 Y = y, YY = 0; Y < end_y; ++Y, ++YY){
for (i32 X = x, XX = 0; X < end_x; ++X, ++XX){
pixels[Y*tex_width + X] = 0xFFFFFFFF;
}
}
}
}
}
*tex_width_out = tex_width;
*tex_height_out = tex_height;
}
else{
pixels = 0;
*tex_width_out = 1;
*tex_height_out = 1;
}
}
*tex_width_out = tex_width;
*tex_height_out = tex_height;
else{
// TODO(allen): Fill in white boxes here.
pixels = 0;
*tex_width_out = 1;
*tex_height_out = 1;
}
FT_Done_FreeType(ft);
@ -187,7 +263,6 @@ font_load_page_pixels(Partition *part, Font_Settings *settings, Glyph_Page *page
internal b32
font_load(System_Functions *system, Font_Settings *settings, Font_Metrics *metrics, Font_Page_Storage *pages){
char *filename = settings->stub.name;
i32 pt_size = settings->pt_size;
// TODO(allen): Stop redoing all this init for each call.
@ -195,73 +270,140 @@ font_load(System_Functions *system, Font_Settings *settings, Font_Metrics *metri
FT_Init_FreeType(&ft);
FT_Face face;
FT_New_Face(ft, filename, 0, &face);
b32 success = font_ft_get_face(ft, &settings->stub, &face);
FT_Size_RequestRec_ size = {};
size.type = FT_SIZE_REQUEST_TYPE_NOMINAL;
size.height = (pt_size << 6);
FT_Request_Size(face, &size);
// NOTE(allen): Set size and metrics
char *name = face->family_name;
u32 name_len = 0;
for (;name[name_len];++name_len);
name_len = clamp_top(name_len, sizeof(metrics->name)-1);
memcpy(metrics->name, name, name_len);
metrics->name[name_len] = 0;
metrics->name_len = name_len;
metrics->ascent = ceil32 (face->size->metrics.ascender / 64.0f);
metrics->descent = floor32 (face->size->metrics.descender / 64.0f);
metrics->advance = ceil32 (face->size->metrics.max_advance / 64.0f);
metrics->height = ceil32 (face->size->metrics.height / 64.0f);
metrics->line_skip = metrics->height - (metrics->ascent - metrics->descent);
metrics->height -= metrics->line_skip;
metrics->line_skip = 0;
// NOTE(allen): Set texture and glyph data.
Assert(font_get_page(pages, 0) == 0);
Glyph_Page *page = font_allocate_and_hash_new_page(system, pages, 0);
font_load_page_layout(settings, metrics, page, 0);
// NOTE(allen): Whitespace spacing stuff
i32 tab_width = 4;
f32 space_adv = page->advance[' '];
f32 backslash_adv = page->advance['\\'];
f32 r_adv = page->advance['r'];
page->advance['\n'] = space_adv;
page->advance['\r'] = backslash_adv + r_adv;
page->advance['\t'] = space_adv*tab_width;
// NOTE(allen): The rest of the metrics.
f32 max_hex_advance = 0.f;
for (u32 i = '0'; i <= '9'; ++i){
f32 adv = page->advance[i];
max_hex_advance = Max(max_hex_advance, adv);
if (success){
FT_Size_RequestRec_ size = {};
size.type = FT_SIZE_REQUEST_TYPE_NOMINAL;
size.height = (pt_size << 6);
FT_Request_Size(face, &size);
// NOTE(allen): Set size and metrics
char *name = face->family_name;
if (name != 0){
i32 name_len = str_size(name);
name_len = clamp_top(name_len, sizeof(metrics->name)-1);
memcpy(metrics->name, name, name_len + 1);
metrics->name_len = name_len;
}
else{
if (!settings->stub.load_from_path){
i32 name_len = settings->stub.len;
memcpy(metrics->name, settings->stub.name, name_len + 1);
metrics->name_len = name_len;
}
}
metrics->ascent = ceil32 (face->size->metrics.ascender / 64.0f);
metrics->descent = floor32 (face->size->metrics.descender / 64.0f);
metrics->advance = ceil32 (face->size->metrics.max_advance / 64.0f);
metrics->height = ceil32 (face->size->metrics.height / 64.0f);
metrics->line_skip = metrics->height - (metrics->ascent - metrics->descent);
metrics->height -= metrics->line_skip;
metrics->line_skip = 0;
if (metrics->height > pt_size*4){
success = false;
}
else{
// NOTE(allen): Set texture and glyph data.
Assert(font_get_page(pages, 0) == 0);
Glyph_Page *page = font_allocate_and_hash_new_page(system, pages, 0);
font_load_page_layout(settings, metrics, page, 0);
// NOTE(allen): Whitespace spacing stuff
i32 tab_width = 4;
f32 space_adv = page->advance[' '];
f32 backslash_adv = page->advance['\\'];
f32 r_adv = page->advance['r'];
page->advance['\n'] = space_adv;
page->advance['\r'] = backslash_adv + r_adv;
page->advance['\t'] = space_adv*tab_width;
// NOTE(allen): The rest of the metrics.
f32 max_hex_advance = 0.f;
for (u32 i = '0'; i <= '9'; ++i){
f32 adv = page->advance[i];
max_hex_advance = Max(max_hex_advance, adv);
}
for (u32 i = 'a'; i <= 'f'; ++i){
f32 adv = page->advance[i];
max_hex_advance = Max(max_hex_advance, adv);
}
for (u32 i = 'A'; i <= 'F'; ++i){
f32 adv = page->advance[i];
max_hex_advance = Max(max_hex_advance, adv);
}
metrics->byte_advance = backslash_adv + max_hex_advance*2;
metrics->sub_advances[0] = backslash_adv;
metrics->sub_advances[1] = max_hex_advance;
metrics->sub_advances[2] = max_hex_advance;
}
}
for (u32 i = 'a'; i <= 'f'; ++i){
f32 adv = page->advance[i];
max_hex_advance = Max(max_hex_advance, adv);
}
for (u32 i = 'A'; i <= 'F'; ++i){
f32 adv = page->advance[i];
max_hex_advance = Max(max_hex_advance, adv);
}
metrics->byte_advance = backslash_adv + max_hex_advance*2;
metrics->sub_advances[0] = backslash_adv;
metrics->sub_advances[1] = max_hex_advance;
metrics->sub_advances[2] = max_hex_advance;
FT_Done_FreeType(ft);
return(true);
return(success);
}
////////////////////////////////
internal
Sys_Font_Get_Loadable_Count_Sig(system_font_get_loadable_count){
return(fontvars.loadable_count);
}
internal
Sys_Font_Get_Loadable_Sig(system_font_get_loadable, i, out){
if (0 <= i && i < fontvars.loadable_count){
memcpy(out, &fontvars.loadables[i], sizeof(*out));
}
else{
memset(out, 0, sizeof(*out));
}
}
internal
Sys_Font_Load_New_Font_Sig(system_font_load_new_font, stub){
Font_ID new_id = 0;
i32 font_count_max = ArrayCount(fontvars.slots);
if (fontvars.count < font_count_max){
i32 index = fontvars.count;
Font_Slot *slot = &fontvars.slots[index];
Font_Settings *settings = &slot->settings;
Font_Metrics *metrics = &slot->metrics;
Font_Page_Storage *pages = &slot->pages;
Assert(!slot->is_active);
char *filename = stub->name;
i32 filename_len = 0;
for (;filename[filename_len];++filename_len);
// Initialize Font Parameters
Assert(filename_len <= sizeof(settings->stub.name) - 1);
memset(settings, 0, sizeof(*settings));
memcpy(&settings->stub, stub, sizeof(*stub));
settings->pt_size = fontvars.pt_size;
settings->use_hinting = fontvars.use_hinting;
memset(metrics, 0, sizeof(*metrics));
memset(pages, 0, sizeof(*pages));
b32 success = font_load(&sysfunc, settings, metrics, pages);
if (success){
slot->is_active = true;
new_id = (Font_ID)(index + 1);
++fontvars.count;
}
}
return(new_id);
}
internal
Sys_Font_Get_Count_Sig(system_font_get_count){
return(fontvars.count);
@ -270,7 +412,7 @@ Sys_Font_Get_Count_Sig(system_font_get_count){
internal
Sys_Font_Get_Name_By_ID_Sig(system_font_get_name_by_id, str_out, capacity){
i32 length = 0;
if (0 < font_id && font_id <= fontvars.count){
if (0 < font_id && font_id <= (u32)fontvars.count){
u32 index = font_id - 1;
Font_Slot *slot = &fontvars.slots[index];
if (slot->is_active){
@ -285,7 +427,7 @@ Sys_Font_Get_Name_By_ID_Sig(system_font_get_name_by_id, str_out, capacity){
internal
Sys_Font_Get_Pointers_By_ID_Sig(system_font_get_pointers_by_id, font_id){
Font_Pointers font = {0};
if (0 < font_id && font_id <= fontvars.count){
if (0 < font_id && font_id <= (u32)fontvars.count){
u32 index = font_id - 1;
Font_Slot *slot = &fontvars.slots[index];
if (slot->is_active){
@ -305,7 +447,7 @@ Sys_Font_Load_Page_Sig(system_font_load_page, settings, metrics, page, page_numb
}
internal
Sys_Font_Allocate_Sig(system_font_allocate){
Sys_Font_Allocate_Sig(system_font_allocate, size){
i64 *size_ptr = 0;
void *result = system_memory_allocate(size + sizeof(*size_ptr));
size_ptr = (i64*)result;
@ -314,7 +456,7 @@ Sys_Font_Allocate_Sig(system_font_allocate){
}
internal
Sys_Font_Free_Sig(system_font_free){
Sys_Font_Free_Sig(system_font_free, ptr){
if (ptr != 0){
i64 *size_ptr = ((i64*)ptr) - 1;
system_memory_free(size_ptr, *size_ptr);
@ -323,10 +465,9 @@ Sys_Font_Free_Sig(system_font_free){
////////////////////////////////
internal Font_Setup*
system_font_get_stubs(Partition *part){
Font_Setup *first_setup = 0;
Font_Setup *head_setup = 0;
internal Font_Setup_List
system_font_get_local_stubs(Partition *part){
Font_Setup_List list = {0};
u32 dir_max = KB(32);
u8 *directory = push_array(part, u8, dir_max);
@ -351,96 +492,113 @@ system_font_get_stubs(Partition *part){
u32 len = 0;
for (;filename[len];++len);
if (dir_len + len + 1 <= sizeof(head_setup->stub.name)){
if (first_setup == 0){
first_setup = push_struct(part, Font_Setup);
head_setup = first_setup;
}
else{
head_setup->next_font = push_struct(part, Font_Setup);
head_setup = head_setup->next_font;
}
head_setup->next_font = 0;
head_setup->stub.in_local_folder = true;
memcpy(&head_setup->stub.name[0], directory, dir_len);
memcpy(&head_setup->stub.name[dir_len], filename, len + 1);
head_setup->stub.len = dir_len + len;
if (dir_len + len + 1 <= sizeof(list.first->stub.name)){
Font_Setup *setup = push_struct(part, Font_Setup);
partition_align(part, 8);
sll_push(list.first, list.last, setup);
setup->stub.load_from_path = true;
memcpy(&setup->stub.name[0], directory, dir_len);
memcpy(&setup->stub.name[dir_len], filename, len + 1);
setup->stub.len = dir_len + len;
}
}
system_set_file_list(&file_list, 0, 0, 0, 0);
return(first_setup);
return(list);
}
internal void
system_font_init(Font_Functions *font, u32 pt_size, b32 use_hinting, Font_Setup *font_setup_head){
system_font_init(Font_Functions *font_links, u32 pt_size, b32 use_hinting, Font_Setup_List list){
// Linking
font->get_count = system_font_get_count;
font->get_name_by_id = system_font_get_name_by_id;
font->get_pointers_by_id = system_font_get_pointers_by_id;
font->load_page = system_font_load_page;
font->allocate = system_font_allocate;
font->free = system_font_free;
font_links->get_loadable_count = system_font_get_loadable_count;
font_links->get_loadable = system_font_get_loadable;
font_links->load_new_font = system_font_load_new_font;
font_links->get_count = system_font_get_count;
font_links->get_name_by_id = system_font_get_name_by_id;
font_links->get_pointers_by_id = system_font_get_pointers_by_id;
font_links->load_page = system_font_load_page;
font_links->allocate = system_font_allocate;
font_links->free = system_font_free;
fontvars.pt_size = pt_size;
fontvars.use_hinting = use_hinting;
// Filling loadable font descriptions
for (Font_Setup *ptr = list.first;
ptr != 0;
ptr = ptr->next){
Font_Loadable_Stub *stub = &ptr->stub;
if (fontvars.loadable_count < ArrayCount(fontvars.loadables)){
Font_Loadable_Description *loadable = &fontvars.loadables[fontvars.loadable_count];
b32 name_good = false;
i32 capacity = (i32)(sizeof(loadable->display_name));
if (stub->load_from_path){
name_good = font_load_name(stub, loadable->display_name, capacity);
if (name_good){
loadable->display_len = str_size(loadable->display_name);
}
}
else{
i32 len = str_size(stub->name);
if (len < capacity){
name_good = true;
memcpy(loadable->display_name, stub->name, len + 1);
loadable->display_len = len;
}
}
if (name_good){
memcpy(&loadable->stub, stub, sizeof(*stub));
loadable->valid = true;
++fontvars.loadable_count;
}
}
}
// Filling initial fonts
//i32 font_count_max = ArrayCount(fontvars.slots);
i32 font_count_max = 1;
i32 font_count = 0;
i32 i = 0;
for (Font_Setup *ptr = font_setup_head;
for (Font_Setup *ptr = list.first;
ptr != 0;
ptr = ptr->next_font){
char *filename = ptr->stub.name;
ptr = ptr->next){
Font_Loadable_Stub *stub = &ptr->stub;
if (i < font_count_max){
Font_Slot *slot = &fontvars.slots[i];
Font_ID new_id = 0;
if (fontvars.count < font_count_max){
i32 index = fontvars.count;
Font_Slot *slot = &fontvars.slots[index];
Font_Settings *settings = &slot->settings;
Font_Metrics *metrics = &slot->metrics;
Font_Page_Storage *pages = &slot->pages;
Assert(!slot->is_active);
char *filename = stub->name;
i32 filename_len = 0;
for (;filename[filename_len];++filename_len);
if (filename_len <= sizeof(settings->stub.name) - 1){
memset(settings, 0, sizeof(*settings));
memset(metrics, 0, sizeof(*metrics));
memset(pages, 0, sizeof(*pages));
// Initialize Font Parameters
memcpy(&settings->stub, &ptr->stub, sizeof(ptr->stub));
settings->pt_size = pt_size;
settings->use_hinting = use_hinting;
b32 success = font_load(&sysfunc, settings, metrics, pages);
if (!success){
memset(font, 0, sizeof(*font));
LOGF("font \"%.*s\" failed to load, unknown error\n", filename_len, filename);
}
else{
slot->is_active = true;
++i;
}
}
else{
LOGF("font \"%.*s\" name is too long to load in current build (max %d)\n", filename_len, filename, (i32)(sizeof(settings->stub.name) - 1));
// Initialize Font Parameters
Assert(filename_len <= sizeof(settings->stub.name) - 1);
memset(settings, 0, sizeof(*settings));
memcpy(&settings->stub, stub, sizeof(*stub));
settings->pt_size = fontvars.pt_size;
settings->use_hinting = fontvars.use_hinting;
memset(metrics, 0, sizeof(*metrics));
memset(pages, 0, sizeof(*pages));
b32 success = font_load(&sysfunc, settings, metrics, pages);
if (success){
slot->is_active = true;
new_id = (Font_ID)(index + 1);
++fontvars.count;
}
}
else{
LOGF("Exceeded maximum font slots (%d) skipping %s\n", font_count_max, filename);
}
++font_count;
}
fontvars.count = clamp_top(font_count, font_count_max);
}
// BOTTOM

View File

@ -12,6 +12,7 @@
#if !defined(FCODER_FONT_PROVIDER_FREETYPE_H)
#define FCODER_FONT_PROVIDER_FREETYPE_H
// NOTE(allen): Implemented by the freetype font provider.
struct Font_Slot{
b32 is_active;
Font_Settings settings;
@ -21,16 +22,40 @@ struct Font_Slot{
struct Font_Vars{
Font_Slot slots[32];
u32 count;
i32 count;
Font_Loadable_Description loadables[4096];
i32 loadable_count;
u32 pt_size;
b32 use_hinting;
};
global Font_Vars fontvars = {0};
struct Font_Setup{
Font_Setup *next_font;
Font_Setup *next;
Font_Loadable_Stub stub;
};
struct Font_Setup_List{
Font_Setup *first;
Font_Setup *last;
};
// NOTE(allen): Procedures to be implemented per-OS for the freetype font provider.
struct Font_Raw_Data{
Temp_Memory temp;
u8 *data;
i32 size;
};
#define Sys_Font_Data(name) Font_Raw_Data system_font_data(char *name)
internal Sys_Font_Data(name);
#define Sys_Font_Data_Not_Used\
internal Sys_Font_Data(name){Font_Raw_Data data = {0}; InvalidCodePath; return(data);}
#endif
// BOTTOM

View File

@ -451,23 +451,6 @@ gui_do_color_button(GUI_Target *target, GUI_id id, u32 fore, u32 back, String te
return(result);
}
internal b32
gui_do_font_button(GUI_Target *target, GUI_id id, Font_ID font_id, String text){
b32 result = 0;
i32 font_id32 = font_id;
GUI_Interactive *b = gui_push_button_command(target, guicom_font_button, id);
GUI_Header *h = (GUI_Header*)b;
gui_push_item(target, h, &font_id32, sizeof(font_id32));
gui_push_string(target, h, text);
if (gui_id_eq(id, target->active)){
result = 1;
target->animating = 1;
}
return(result);
}
internal b32
gui_begin_list(GUI_Target *target, GUI_id id, i32 list_i,
b32 activate_item, b32 snap_into_view, GUI_Item_Update *update){
@ -565,6 +548,13 @@ gui_do_button(GUI_Target *target, GUI_id id, String message){
return(result);
}
internal b32
gui_do_button(GUI_Target *target, GUI_id id, char *message){
String str_message = make_string_slowly(message);
b32 result = gui_do_button(target, id, str_message);
return(result);
}
internal b32
gui_do_fixed_option(GUI_Target *target, GUI_id id, String message, char key){
b32 result = 0;

View File

@ -13,21 +13,26 @@
// with a next and prev pointer where the type of the struct
// is the same as the type of the next/prev pointers.
#define dll_init_sentinel(s) do{ (s)->next=(s); (s)->prev=(s); }while(0)
#define dll_insert(p,v) do{ (v)->next=(p)->next; (v)->prev=(p); (p)->next=(v); (v)->next->prev=(v); }while(0)
#define dll_back_insert(p,v) do{ (v)->prev=(p)->prev; (v)->next=(p); (p)->prev=(v); (v)->prev->next=(v); }while(0)
#define dll_remove(v) do{ (v)->next->prev = (v)->prev; (v)->prev->next = (v)->next; }while(0)
#define dll_init_sentinel(s) (s)->next=(s),(s)->prev=(s)
#define dll_insert(p,v) (v)->next=(p)->next,(v)->prev=(p),(p)->next=(v),(v)->next->prev=(v)
#define dll_back_insert(p,v) (v)->prev=(p)->prev,(v)->next=(p),(p)->prev=(v),(v)->prev->next=(v)
#define dll_remove(v) (v)->next->prev=(v)->prev,(v)->prev->next=(v)->next
// HACK(allen): I don't like this anymore, get rid of it.
// for(dll_items(iterator, sentinel_ptr)){...}
#define dll_items(it, st) ((it) = (st)->next); ((it) != (st)); ((it) = (it)->next)
#define sll_push(f,l,n) if((f)==0&&(l)==0){(f)=(l)=(n);}else{(l)->next=(n);(l)=(n);}
// NOTE(allen): These macros work on structs with a next
// pointer to the saem type as the containing struct.
#define sll_push(f,l,n) if((f)==0&&(l)==0){(f)=(l)=(n);}else{(l)->next=(n);(l)=(n);}(l)->next=0
#define sll_pop(f,l) if((f)!=(l)){(f)=(f)->next;}else{(f)=(l)=0;}
#define sll_init_sentinel(s) do{ (s)->next=(s); }while(0)
#define sll_insert(p,v) do{ (v)->next=(p)->next; (p)->next = (v); }while(0)
#define sll_remove(p,v) do{ Assert((p)->next == (v)); (p)->next = (v)->next; }while(0)
// HACK(allen): I don't like this anymore, get rid of it.
// for(sll_items(iterator, sentinel_ptr)){...}
#define sll_items(it, st) ((it) = (st)->next); ((it) != (st)); ((it) = (it)->next)

View File

@ -50,9 +50,6 @@ private_draw_set_color(Render_Target *t, u32 color){
internal void
interpret_render_buffer(Render_Target *t){
// HACK(allen): Probably should use a different partition that can be resized, but whatevs for now scro.
Partition *part = &t->buffer;
local_persist b32 first_opengl_call = true;
if (first_opengl_call){
first_opengl_call = false;
@ -165,6 +162,7 @@ interpret_render_buffer(Render_Target *t){
}
if (!page->has_gpu_setup){
Partition *part = &target.buffer;
Temp_Memory temp = begin_temp_memory(part);
i32 tex_width = 0;
i32 tex_height = 0;

View File

@ -28,6 +28,10 @@ init_shared_vars(){
void *scratch_memory = system_memory_allocate(scratch_size);
shared_vars.scratch = make_part(scratch_memory, (i32)scratch_size);
umem font_scratch_size = MB(4);
void *font_scratch_memory = system_memory_allocate(font_scratch_size);
shared_vars.font_scratch = make_part(font_scratch_memory, (i32)font_scratch_size);
shared_vars.track_table_size = KB(16);
shared_vars.track_table = system_memory_allocate(shared_vars.track_table_size);
@ -150,15 +154,6 @@ sysshared_load_file(char *filename){
return(result);
}
internal b32
usable_ascii(char c){
b32 result = true;
if ((c < ' ' || c > '~') && c != '\n' && c != '\r' && c != '\t'){
result = false;
}
return(result);
}
internal void
sysshared_filter_real_files(char **files, i32 *file_count){
i32 end = *file_count;
@ -172,6 +167,7 @@ sysshared_filter_real_files(char **files, i32 *file_count){
*file_count = j;
}
// HACK(allen): Get rid of this now!?
internal Partition
sysshared_scratch_partition(i32 size){
void *data = system_memory_allocate((umem)size);
@ -181,9 +177,10 @@ sysshared_scratch_partition(i32 size){
internal void
sysshared_partition_grow(Partition *part, i32 new_size){
Assert(part->pos == 0);
void *data = 0;
if (new_size > part->max){
// TODO(allen): attempt to grow in place by just acquiring next vpages?!
data = system_memory_allocate((umem)new_size);
memcpy(data, part->base, part->pos);
system_memory_free(part->base, part->max);
@ -192,15 +189,10 @@ sysshared_partition_grow(Partition *part, i32 new_size){
}
}
internal void
sysshared_partition_double(Partition *part){
sysshared_partition_grow(part, part->max*2);
}
internal void*
sysshared_push_block(Partition *part, i32 size){
void *result = push_block(part, size);
if (!result){
if (result == 0){
sysshared_partition_grow(part, size + part->max);
result = push_block(part, size);
}

View File

@ -34,6 +34,7 @@ struct Shared_Vars{
u32 track_node_size;
Partition scratch;
Partition font_scratch;
};
global Shared_Vars shared_vars;

View File

@ -42,6 +42,7 @@
#include "4ed_render_format.h"
#include "4ed_render_target.h"
#include "4ed.h"
#include "4ed_linked_node_macros.h"
#include "4ed_file_track.h"
#include "4ed_system_shared.h"
@ -1606,8 +1607,8 @@ main(int argc, char **argv){
Partition *scratch = &shared_vars.scratch;
Temp_Memory temp = begin_temp_memory(scratch);
Font_Setup *font_setup_head = system_font_get_stubs(scratch);
system_font_init(&sysfunc.font, plat_settings.font_size, plat_settings.use_hinting, font_setup_head);
Font_Setup_List font_setup = system_font_get_local_stubs(scratch);
system_font_init(&sysfunc.font, plat_settings.font_size, plat_settings.use_hinting, font_setup);
end_temp_memory(temp);
//

View File

@ -41,6 +41,7 @@
#include "4ed_render_format.h"
#include "4ed_render_target.h"
#include "4ed.h"
#include "4ed_linked_node_macros.h"
#include "4ed_file_track.h"
#include "4ed_system_shared.h"
@ -652,8 +653,8 @@ osx_init(){
Partition *scratch = &shared_vars.scratch;
Temp_Memory temp = begin_temp_memory(scratch);
Font_Setup *font_setup_head = system_font_get_stubs(scratch);
system_font_init(&sysfunc.font, plat_settings.font_size, plat_settings.use_hinting, font_setup_head);
Font_Setup_List font_setup = system_font_get_local_stubs(scratch);
system_font_init(&sysfunc.font, plat_settings.font_size, plat_settings.use_hinting, font_setup);
end_temp_memory(temp);
//

View File

@ -52,6 +52,7 @@
#include "4ed_render_format.h"
#include "4ed_render_target.h"
#include "4ed.h"
#include "4ed_linked_node_macros.h"
#include <Windows.h>
#include "win32_gl.h"
@ -308,11 +309,20 @@ win32_post_clipboard(char *text, i32 len){
internal
Sys_Post_Clipboard_Sig(system_post_clipboard){
LOG("Beginning clipboard post\n");
Partition *part = &win32vars.clip_post_part;
win32vars.clip_post_len = str.size;
part->pos = 0;
u8 *post = (u8*)sysshared_push_block(part, str.size + 1);
memmove(post, str.str, str.size);
post[str.size] = 0;
if (post != 0){
LOG("Copying post to clipboard buffer\n");
memcpy(post, str.str, str.size);
post[str.size] = 0;
win32vars.clip_post_len = str.size;
}
else{
LOGF("Failed to allocate buffer for clipboard post (%d)\n", str.size + 1);
}
LOG("Finished clipboard post\n");
}
internal b32
@ -505,6 +515,131 @@ Sys_CLI_End_Update_Sig(system_cli_end_update){
#include "4ed_font_provider_freetype.h"
#include "4ed_font_provider_freetype.cpp"
internal
Sys_Font_Data(name){
Font_Raw_Data data = {0};
HFONT hfont = CreateFontA(
0,
0,
0,
0,
0,
FALSE, // Italic
FALSE, // Underline
FALSE, // Strikeout
ANSI_CHARSET,
OUT_DEVICE_PRECIS,
CLIP_DEFAULT_PRECIS,
DEFAULT_QUALITY,
DEFAULT_PITCH | FF_DONTCARE,
name
);
if (hfont != 0){
HDC hdc = CreateCompatibleDC(NULL);
if (hdc != 0){
SelectObject(hdc, hfont);
DWORD size = GetFontData(hdc, 0, 0, NULL, 0);
if (size > 0){
Partition *part = &shared_vars.font_scratch;
data.temp = begin_temp_memory(part);
u8 *buffer = push_array(part, u8, size);
if (buffer == 0){
sysshared_partition_grow(part, l_round_up_i32(size, KB(4)));
buffer = push_array(part, u8, size);
}
if (buffer != 0){
push_align(part, 8);
if (GetFontData(hdc, 0, 0, buffer, size) == size){
data.data = buffer;
data.size = size;
}
}
}
DeleteDC(hdc);
}
}
return(data);
}
struct Win32_Font_Enum{
Partition *part;
Font_Setup_List *list;
};
internal int
win32_font_enum_callback(
const LOGFONT *lpelfe,
const TEXTMETRIC *lpntme,
DWORD FontType,
LPARAM lParam
){
if ((FontType & TRUETYPE_FONTTYPE) != 0){
ENUMLOGFONTEXDV *log_font = (ENUMLOGFONTEXDV*)lpelfe;
TCHAR *name = ((log_font)->elfEnumLogfontEx).elfLogFont.lfFaceName;
if ((char)name[0] == '@'){
return(1);
}
i32 len = 0;
for (;name[len]!=0;++len);
if (len >= sizeof(((Font_Loadable_Stub*)0)->name)){
return(1);
}
Win32_Font_Enum p = *(Win32_Font_Enum*)lParam;
Temp_Memory reset = begin_temp_memory(p.part);
Font_Setup *setup = push_array(p.part, Font_Setup, 1);
if (setup != 0){
memset(setup, 0, sizeof(*setup));
b32 good = true;
for (i32 i = 0; i < len; ++i){
if (name[i] >= 128){
good = false;
break;
}
setup->stub.name[i] = (char)name[i];
}
if (good){
setup->stub.load_from_path = false;
setup->stub.len = len;
sll_push(p.list->first, p.list->last, setup);
}
else{
end_temp_memory(reset);
}
}
}
return(1);
}
internal void
win32_get_loadable_fonts(Partition *part, Font_Setup_List *list){
HDC hdc= GetDC(0);
LOGFONT log_font = {0};
log_font.lfCharSet = ANSI_CHARSET;
log_font.lfFaceName[0] = 0;
Win32_Font_Enum p = {0};
p.part = part;
p.list = list;
int result = EnumFontFamiliesEx(hdc, &log_font, win32_font_enum_callback, (LPARAM)&p,0);
AllowLocal(result);
ReleaseDC(0, hdc);
}
#include <GL/gl.h>
#include "opengl/4ed_opengl_render.cpp"
@ -1118,8 +1253,9 @@ WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdS
LOG("Initializing fonts\n");
Partition *scratch = &shared_vars.scratch;
Temp_Memory temp = begin_temp_memory(scratch);
Font_Setup *font_setup_head = system_font_get_stubs(scratch);
system_font_init(&sysfunc.font, plat_settings.font_size, plat_settings.use_hinting, font_setup_head);
Font_Setup_List font_setup = system_font_get_local_stubs(scratch);
win32_get_loadable_fonts(scratch, &font_setup);
system_font_init(&sysfunc.font, plat_settings.font_size, plat_settings.use_hinting, font_setup);
end_temp_memory(temp);
//

View File

@ -224,7 +224,9 @@ API_EXPORT FSTRING_LINK i32_4tech
str_size(char *str)
/* DOC(This call returns the number of bytes before a null terminator starting at str.) */{
i32_4tech i = 0;
while (str[i]) ++i;
if (str != 0){
for (;str[i];++i);
}
return(i);
}
@ -234,7 +236,7 @@ make_string_slowly(void *str)
String result;
result.str = (char*)str;
result.size = str_size((char*)str);
result.memory_size = result.size+1;
result.memory_size = result.size + 1;
return(result);
}