From 4f3b07168d1eae1de1bb3f0c602e957606924a21 Mon Sep 17 00:00:00 2001 From: Allen Webster Date: Thu, 16 Nov 2017 18:03:36 -0500 Subject: [PATCH] Working on font cleanup all day all day all day --- 4coder_API/version.h | 2 +- 4ed.cpp | 5 +- 4ed_api_implementation.cpp | 22 +- 4ed_app_target.cpp | 5 +- 4ed_buffer.cpp | 31 +-- 4ed_file_view.cpp | 75 ++--- 4ed_font.cpp | 225 +++++++++++++++ 4ed_font.h | 127 +++++++++ 4ed_font_data.h | 74 ----- 4ed_font_interface.h | 78 ------ 4ed_font_interface_to_os.h | 24 -- 4ed_font_provider_freetype.cpp | 447 ++++++++++++++++++++++++++++++ 4ed_font_provider_freetype.h | 37 +++ 4ed_font_static_functions.cpp | 245 ---------------- 4ed_font_system_functions.cpp | 305 -------------------- 4ed_render_fill.cpp | 10 +- 4ed_system.h | 2 - 4ed_translation.cpp | 6 +- opengl/4ed_opengl_render.cpp | 76 ++--- platform_all/4ed_shared_fonts.cpp | 168 ----------- platform_linux/linux_4ed.cpp | 20 +- platform_linux/linux_font.cpp | 104 ------- platform_mac/mac_4ed.cpp | 21 +- platform_win32/win32_4ed.cpp | 19 +- 24 files changed, 993 insertions(+), 1135 deletions(-) create mode 100644 4ed_font.cpp create mode 100644 4ed_font.h delete mode 100644 4ed_font_data.h delete mode 100644 4ed_font_interface.h delete mode 100644 4ed_font_interface_to_os.h create mode 100644 4ed_font_provider_freetype.cpp create mode 100644 4ed_font_provider_freetype.h delete mode 100644 4ed_font_static_functions.cpp delete mode 100644 4ed_font_system_functions.cpp delete mode 100644 platform_all/4ed_shared_fonts.cpp delete mode 100644 platform_linux/linux_font.cpp diff --git a/4coder_API/version.h b/4coder_API/version.h index b0ee81e7..9c5f1c9c 100644 --- a/4coder_API/version.h +++ b/4coder_API/version.h @@ -1,6 +1,6 @@ #define MAJOR 4 #define MINOR 0 -#define PATCH 23 +#define PATCH 24 // string #define VN__(a,b,c) #a "." #b "." #c diff --git a/4ed.cpp b/4ed.cpp index 8d8feda5..cbce31c1 100644 --- a/4ed.cpp +++ b/4ed.cpp @@ -15,11 +15,10 @@ global_const char messages[] = "Welcome to " VERSION "\n" "If you're new to 4coder there are some tutorials at http://4coder.net/tutorials.html\n" "\n" -"New in alpha 4.0.22:\n" +"New in alpha 4.0.22 and 4.0.23:\n" "-The rendering layer is cleaned up and faster\n" "-4coder can now ship with multiple built in command bindings\n" " New built in binding \"mac-default\": For the mac version of 4coder - similar to most Mac applications\n" -" New built in binding \"mac-4coder-like\": For the mac version of 4coder - similar to 4coder on other OSes\n" "-Fullscreen now works on Windows without the '-S' flag\n" "-Set up a single 4coder project for Windows/Linux/Mac in one command: -> \"new project\"\n" "\n" @@ -1224,7 +1223,7 @@ init_command_line_settings(App_Settings *settings, Plat_Settings *plat_settings, { if (i < argc){ plat_settings->font_size = str_to_int_c(argv[i]); - plat_settings->font_size = clamp_bottom(8, plat_settings->font_size); + plat_settings->font_size = plat_settings->font_size; } action = CLAct_Nothing; }break; diff --git a/4ed_api_implementation.cpp b/4ed_api_implementation.cpp index 00a7cf4b..527d7ed9 100644 --- a/4ed_api_implementation.cpp +++ b/4ed_api_implementation.cpp @@ -1029,7 +1029,7 @@ DOC_SEE(Buffer_Setting_ID) new_value = 48; } if (new_value != file->settings.display_width){ - Render_Font *font = system->font.get_render_data_by_id(file->settings.font_id); + Font_Pointers font = system->font.get_pointers_by_id(file->settings.font_id); file->settings.display_width = new_value; file_measure_wraps_and_fix_cursor(system, models, file, font); } @@ -1042,7 +1042,7 @@ DOC_SEE(Buffer_Setting_ID) new_value = 0; } if (new_value != file->settings.minimum_base_display_width){ - Render_Font *font = system->font.get_render_data_by_id(file->settings.font_id); + Font_Pointers font = system->font.get_pointers_by_id(file->settings.font_id); file->settings.minimum_base_display_width = new_value; file_measure_wraps_and_fix_cursor(system, models, file, font); } @@ -1125,7 +1125,7 @@ DOC_SEE(Buffer_Setting_ID) } if (full_remeasure){ - Render_Font *font = system->font.get_render_data_by_id(file->settings.font_id); + Font_Pointers font = system->font.get_pointers_by_id(file->settings.font_id); file_allocate_character_starts_as_needed(&models->mem.general, file); buffer_measure_character_starts(system, font, &file->state.buffer, file->state.character_starts, 0, file->settings.virtual_white); @@ -2259,11 +2259,13 @@ DOC(This call changes 4coder's default font to one of the built in fonts.) String font_name = make_string(name, len); Font_ID font_id = font_get_id_by_name(system, font_name); - if (apply_to_all_files){ - global_set_font(system, models, font_id); - } - else{ - models->global_font_id = font_id; + if (font_id != 0){ + if (apply_to_all_files){ + global_set_font(system, models, font_id); + } + else{ + models->global_font_id = font_id; + } } } @@ -2284,7 +2286,9 @@ DOC(This call sets the display font of a particular buffer.) if (file != 0){ String font_name = make_string(name, len); Font_ID font_id = font_get_id_by_name(system, font_name); - file_set_font(system, models, file, font_id); + if (font_id != 0){ + file_set_font(system, models, file, font_id); + } } } diff --git a/4ed_app_target.cpp b/4ed_app_target.cpp index a75ee39d..6e194306 100644 --- a/4ed_app_target.cpp +++ b/4ed_app_target.cpp @@ -17,6 +17,7 @@ #include "4coder_API/custom.h" #include "4ed_math.h" +#include "4ed_font.h" #include "4ed_system.h" #define PREFERRED_ALIGNMENT 8 @@ -42,6 +43,8 @@ #include "4ed_doubly_linked_list.cpp" +#include "4ed_font.cpp" + #include "4ed_translation.cpp" #include "4ed_render_target.cpp" @@ -69,7 +72,5 @@ #include "4ed_file_view.cpp" #include "4ed.cpp" -#include "4ed_font_static_functions.cpp" - // BOTTOM diff --git a/4ed_buffer.cpp b/4ed_buffer.cpp index 1bc5bcfe..36ab9dab 100644 --- a/4ed_buffer.cpp +++ b/4ed_buffer.cpp @@ -13,7 +13,6 @@ // Buffer low level operations // -#include "4ed_font_data.h" #include "4coder_helper/4coder_seek_types.h" struct Cursor_With_Index{ @@ -668,7 +667,7 @@ buffer_measure_starts(Buffer_Measure_Starts *state, Gap_Buffer *buffer){ } internal void -buffer_measure_character_starts(System_Functions *system, Render_Font *font, Gap_Buffer *buffer, i32 *character_starts, i32 mode, i32 virtual_white){ +buffer_measure_character_starts(System_Functions *system, Font_Pointers font, Gap_Buffer *buffer, i32 *character_starts, i32 mode, i32 virtual_white){ PRFL_FUNC_GROUP(); Assert(mode == 0); @@ -749,7 +748,7 @@ struct Buffer_Measure_Wrap_Params{ Gap_Buffer *buffer; i32 *wrap_line_index; System_Functions *system; - Render_Font *font; + Font_Pointers font; b32 virtual_white; }; @@ -853,10 +852,10 @@ buffer_measure_wrap_y(Buffer_Measure_Wrap_State *S_ptr, Buffer_Measure_Wrap_Para else if (S.behavior.do_number_advance || S.behavior.do_codepoint_advance){ if (!S.skipping_whitespace){ if (S.behavior.do_codepoint_advance){ - S.current_adv = font_get_glyph_advance(params.system, params.font, S.step.value); + S.current_adv = font_get_glyph_advance(params.system, params.font.settings, params.font.metrics, params.font.pages, S.step.value); } else{ - S.current_adv = font_get_byte_advance(params.font); + S.current_adv = params.font.metrics->byte_advance; } S.did_wrap = false; @@ -986,7 +985,7 @@ buffer_remeasure_starts(Gap_Buffer *buffer, i32 line_start, i32 line_end, i32 li } internal void -buffer_remeasure_character_starts(System_Functions *system, Render_Font *font, Gap_Buffer *buffer, i32 line_start, i32 line_end, i32 line_shift, i32 *character_starts, i32 mode, i32 virtual_whitespace){ +buffer_remeasure_character_starts(System_Functions *system, Font_Pointers font, Gap_Buffer *buffer, i32 line_start, i32 line_end, i32 line_shift, i32 *character_starts, i32 mode, i32 virtual_whitespace){ Assert(mode == 0); i32 new_line_count = buffer->line_count; @@ -1299,7 +1298,7 @@ struct Buffer_Cursor_Seek_Params{ Gap_Buffer *buffer; Buffer_Seek seek; System_Functions *system; - Render_Font *font; + Font_Pointers font; i32 *wrap_line_index; i32 *character_starts; b32 virtual_white; @@ -1351,7 +1350,7 @@ buffer_cursor_seek(Buffer_Cursor_Seek_State *S_ptr, Buffer_Cursor_Seek_Params pa DrCase(4); } - S.font_height = font_get_height(params.font); + S.font_height = params.font.metrics->height; S.xy_seek = (params.seek.type == buffer_seek_wrapped_xy || params.seek.type == buffer_seek_unwrapped_xy); S.size = buffer_size(params.buffer); @@ -1539,10 +1538,10 @@ buffer_cursor_seek(Buffer_Cursor_Seek_State *S_ptr, Buffer_Cursor_Seek_Params pa else if (S.behavior.do_number_advance || S.behavior.do_codepoint_advance){ if (S.behavior.do_codepoint_advance){ - S.ch_width = font_get_glyph_advance(params.system, params.font, S.step.value); + S.ch_width = font_get_glyph_advance(params.system, params.font.settings, params.font.metrics, params.font.pages, S.step.value); } else{ - S.ch_width = font_get_byte_advance(params.font); + S.ch_width = params.font.metrics->byte_advance; } if (S.step.i >= S.wrap_unit_end){ @@ -1732,7 +1731,7 @@ struct Render_Item_Write{ Buffer_Render_Item *item; f32 x, y; System_Functions *system; - Render_Font *font; + Font_Pointers font; i32 font_height; f32 x_min; f32 x_max; @@ -1741,7 +1740,7 @@ struct Render_Item_Write{ inline Render_Item_Write write_render_item(Render_Item_Write write, i32 index, u32 codepoint, u32 flags){ - f32 ch_width = font_get_glyph_advance(write.system, write.font, codepoint); + f32 ch_width = font_get_glyph_advance(write.system, write.font.settings, write.font.metrics, write.font.pages, codepoint); if (write.x <= write.x_max && write.x + ch_width >= write.x_min){ write.item->index = index; @@ -1775,7 +1774,7 @@ struct Buffer_Render_Params{ Full_Cursor start_cursor; i32 wrapped; System_Functions *system; - Render_Font *font; + Font_Pointers font; b32 virtual_white; i32 wrap_slashes; }; @@ -1854,11 +1853,11 @@ buffer_render_data(Buffer_Render_State *S_ptr, Buffer_Render_Params params, f32 S.write.y = S.shift_y; S.write.system = params.system; S.write.font = params.font; - S.write.font_height = font_get_height(params.font); + S.write.font_height = params.font.metrics->height; S.write.x_min = params.port_x; S.write.x_max = params.port_x + params.clip_w; - S.byte_advance = font_get_byte_advance(params.font); + S.byte_advance = params.font.metrics->byte_advance; if (params.virtual_white){ S.skipping_whitespace = 1; @@ -1963,7 +1962,7 @@ buffer_render_data(Buffer_Render_State *S_ptr, Buffer_Render_Params params, f32 case '\t': { - S.ch_width = font_get_glyph_advance(params.system, params.font, '\t'); + S.ch_width = font_get_glyph_advance(params.system, params.font.settings, params.font.metrics, params.font.pages, '\t'); f32 new_x = S.write.x + S.ch_width; S.write = write_render_item(S.write, I, ' ', 0); diff --git a/4ed_file_view.cpp b/4ed_file_view.cpp index 214715ca..0ea37965 100644 --- a/4ed_file_view.cpp +++ b/4ed_file_view.cpp @@ -143,8 +143,8 @@ internal Full_Cursor view_compute_cursor(System_Functions *system, View *view, Buffer_Seek seek, b32 return_hint){ Editing_File *file = view->file_data.file; - Render_Font *font = system->font.get_render_data_by_id(file->settings.font_id); - Assert(font != 0); + Font_Pointers font = system->font.get_pointers_by_id(file->settings.font_id); + Assert(font.valid); Full_Cursor result = {0}; @@ -708,7 +708,7 @@ file_allocate_character_starts_as_needed(General_Memory *general, Editing_File * internal void file_measure_character_starts(System_Functions *system, Models *models, Editing_File *file){ file_allocate_character_starts_as_needed(&models->mem.general, file); - Render_Font *font = system->font.get_render_data_by_id(file->settings.font_id); + Font_Pointers font = system->font.get_pointers_by_id(file->settings.font_id); buffer_measure_character_starts(system, font, &file->state.buffer, file->state.character_starts, 0, file->settings.virtual_white); file_update_cursor_positions(system, models, file); } @@ -760,7 +760,7 @@ struct Code_Wrap_State{ i32 size; i32 i; - Render_Font *font; + Font_Pointers font; f32 tab_indent_amount; f32 byte_advance; @@ -772,7 +772,7 @@ struct Code_Wrap_State{ }; internal void -wrap_state_init(System_Functions *system, Code_Wrap_State *state, Editing_File *file, Render_Font *font){ +wrap_state_init(System_Functions *system, Code_Wrap_State *state, Editing_File *file, Font_Pointers font){ state->token_array = file->state.token_array; state->token_ptr = state->token_array.tokens; state->end_token = state->token_ptr + state->token_array.count; @@ -789,8 +789,8 @@ wrap_state_init(System_Functions *system, Code_Wrap_State *state, Editing_File * state->font = font; - state->tab_indent_amount = font_get_glyph_advance(system, font, '\t'); - state->byte_advance = font_get_byte_advance(font); + state->tab_indent_amount = font_get_glyph_advance(system, font.settings, font.metrics, font.pages, '\t'); + state->byte_advance = font.metrics->byte_advance; state->tran = null_buffer_translating_state; } @@ -823,7 +823,7 @@ struct Code_Wrap_Step{ }; internal Code_Wrap_Step -wrap_state_consume_token(System_Functions *system, Render_Font *font, Code_Wrap_State *state, i32 fixed_end_point){ +wrap_state_consume_token(System_Functions *system, Font_Pointers font, Code_Wrap_State *state, i32 fixed_end_point){ Code_Wrap_Step result = {0}; i32 i = state->i; @@ -913,7 +913,7 @@ wrap_state_consume_token(System_Functions *system, Render_Font *font, Code_Wrap_ u32 n = state->step.value; f32 adv = 0; if (state->behavior.do_codepoint_advance){ - adv = font_get_glyph_advance(system, state->font, n); + adv = font_get_glyph_advance(system, state->font.settings, state->font.metrics, state->font.pages, n); if (n != ' ' && n != '\t'){ skipping_whitespace = false; @@ -1231,7 +1231,7 @@ get_current_shift(Code_Wrap_State *wrap_state, i32 next_line_start){ } internal void -file_measure_wraps(System_Functions *system, Models *models, Editing_File *file, Render_Font *font){ +file_measure_wraps(System_Functions *system, Models *models, Editing_File *file, Font_Pointers font){ PRFL_FUNC_GROUP(); General_Memory *general = &models->mem.general; @@ -1339,7 +1339,7 @@ file_measure_wraps(System_Functions *system, Models *models, Editing_File *file, word_stage = 1; } else{ - f32 adv = font_get_glyph_advance(params.system, params.font, codepoint); + f32 adv = font_get_glyph_advance(params.system, params.font.settings, params.font.metrics, params.font.pages, codepoint); x += adv; self_x += adv; @@ -1484,7 +1484,7 @@ file_measure_wraps(System_Functions *system, Models *models, Editing_File *file, goto doublebreak_stage1; } - f32 adv = font_get_glyph_advance(params.system, params.font, buffer_step.value); + f32 adv = font_get_glyph_advance(params.system, params.font.settings, params.font.metrics, params.font.pages, buffer_step.value); x += adv; if (!first_word && x > current_width){ @@ -1520,7 +1520,7 @@ file_measure_wraps(System_Functions *system, Models *models, Editing_File *file, goto doublebreak_stage2; } - f32 adv = font_get_glyph_advance(params.system, params.font, buffer_step.value); + f32 adv = font_get_glyph_advance(params.system, params.font.settings, params.font.metrics, params.font.pages, buffer_step.value); x += adv; } } @@ -1737,7 +1737,7 @@ file_measure_wraps(System_Functions *system, Models *models, Editing_File *file, } internal void -file_measure_wraps_and_fix_cursor(System_Functions *system, Models *models, Editing_File *file, Render_Font *font){ +file_measure_wraps_and_fix_cursor(System_Functions *system, Models *models, Editing_File *file, Font_Pointers font){ if (file->state.hacks.suppression_mode){ file->state.hacks.needs_wraps_and_fix_cursor = true; } @@ -1785,7 +1785,8 @@ file_create_from_string(System_Functions *system, Models *models, Editing_File * Font_ID font_id = models->global_font_id; file->settings.font_id = font_id; - Render_Font *font = system->font.get_render_data_by_id(font_id); + Font_Pointers font = system->font.get_pointers_by_id(font_id); + Assert(font.valid); { file_measure_starts(general, &file->state.buffer); @@ -2657,8 +2658,9 @@ file_view_nullify_file(View *view){ internal void update_view_line_height(System_Functions *system, Models *models, View *view, Font_ID font_id){ - Render_Font *font = system->font.get_render_data_by_id(font_id); - view->line_height = font_get_height(font); + Font_Pointers font = system->font.get_pointers_by_id(font_id); + Assert(font.valid); + view->line_height = font.metrics->height; } inline void @@ -3142,7 +3144,9 @@ file_do_single_edit(System_Functions *system, Models *models, Editing_File *file i32 new_line_count = buffer_count_newlines(&file->state.buffer, start, start+str_len); i32 line_shift = new_line_count - replaced_line_count; - Render_Font *font = system->font.get_render_data_by_id(file->settings.font_id); + Font_Pointers font = system->font.get_pointers_by_id(file->settings.font_id); + Assert(font.valid); + file_grow_starts_as_needed(general, buffer, line_shift); buffer_remeasure_starts(buffer, line_start, line_end, line_shift, shift_amount); @@ -3262,7 +3266,8 @@ file_do_batch_edit(System_Functions *system, Models *models, Editing_File *file, // NOTE(allen): meta data file_measure_starts(general, &file->state.buffer); - Render_Font *font = system->font.get_render_data_by_id(file->settings.font_id); + Font_Pointers font = system->font.get_pointers_by_id(file->settings.font_id); + Assert(font.valid); // TODO(allen): write the remeasurement version file_allocate_character_starts_as_needed(general, file); @@ -3543,7 +3548,7 @@ style_get_color(Style *style, Cpp_Token token){ internal void file_set_font(System_Functions *system, Models *models, Editing_File *file, Font_ID font_id){ file->settings.font_id = font_id; - Render_Font *font = system->font.get_render_data_by_id(font_id); + Font_Pointers font = system->font.get_pointers_by_id(font_id); file_measure_wraps_and_fix_cursor(system, models, file, font); Editing_Layout *layout = &models->layout; @@ -4509,6 +4514,14 @@ 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: { @@ -4527,20 +4540,16 @@ step_file_view(System_Functions *system, View *view, Models *models, View *activ font_id = file->settings.font_id; } - // TODO(allen): paginate the display Font_ID new_font_id = font_id; u32 total_count = system->font.get_count(); - u32 count = Min(total_count, 10); - - for (u32 font_index = 0; font_index < count; ++font_index){ - Font_ID this_font_id = 0; - system->font.get_ids_by_index(font_index, 1, &this_font_id); + for (u32 i = 0; i < total_count; ++i){ + Font_ID this_font_id = i + 1; char name_space[256]; String name = make_fixed_width_string(name_space); - name.size = system->font.get_name_by_index(font_index, name.str, name.memory_size); + name.size = system->font.get_name_by_id(this_font_id, name.str, name.memory_size); - id.id[0] = (u64)font_index + 1; + 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; @@ -5683,7 +5692,7 @@ draw_file_loaded(System_Functions *system, View *view, Models *models, i32_Rect Buffer_Render_Item *items = push_array(part, Buffer_Render_Item, max); Font_ID font_id = file->settings.font_id; - Render_Font *font = system->font.get_render_data_by_id(font_id); + Font_Pointers font = system->font.get_pointers_by_id(font_id); f32 scroll_x = view->edit_pos->scroll.scroll_x; f32 scroll_y = view->edit_pos->scroll.scroll_y; @@ -5922,7 +5931,7 @@ draw_text_with_cursor(System_Functions *system, Render_Target *target, View *vie draw_rectangle(target, rect, back_color); if (pos >= 0 && pos < s.size){ - Render_Font *font = system->font.get_render_data_by_id(font_id); + Font_Pointers font = system->font.get_pointers_by_id(font_id); String part1 = substr(s, 0, pos); String part2 = substr(s, pos, 1); @@ -5930,7 +5939,7 @@ draw_text_with_cursor(System_Functions *system, Render_Target *target, View *vie x = draw_string(system, target, font_id, part1, floor32(x), y, text_color); - f32 adv = font_get_glyph_advance(system, font, s.str[pos]); + f32 adv = font_get_glyph_advance(system, font.settings, font.metrics, font.pages, s.str[pos]); i32_Rect cursor_rect; cursor_rect.x0 = floor32(x); cursor_rect.x1 = floor32(x) + ceil32(adv); @@ -6137,7 +6146,7 @@ draw_style_preview(System_Functions *system, GUI_Target *gui_target, Render_Targ char font_name_space[256]; String font_name = make_fixed_width_string(font_name_space); font_name.size = system->font.get_name_by_id(font_id, font_name.str, font_name.memory_size); - Render_Font *font = system->font.get_render_data_by_id(font_id); + Font_Pointers font = system->font.get_pointers_by_id(font_id); i32_Rect inner = get_inner_rect(rect, 3); @@ -6159,7 +6168,7 @@ draw_style_preview(System_Functions *system, GUI_Target *gui_target, Render_Targ draw_string(system, target, font_id, font_name, font_x, y, text_color); } - i32 height = font_get_height(font); + i32 height = font.metrics->height; x = inner.x0; y += height; x = ceil32(draw_string(system, target, font_id, "if", x, y, keyword_color)); diff --git a/4ed_font.cpp b/4ed_font.cpp new file mode 100644 index 00000000..8ff81664 --- /dev/null +++ b/4ed_font.cpp @@ -0,0 +1,225 @@ +/* + * Mr. 4th Dimention - Allen Webster + * + * 11.03.2017 + * + * Implements some basic getters for fonts set up to make the font type opaque. + * + */ + +// TOP + +internal Font_ID +font_get_id_by_name(System_Functions *system, String name){ + Font_ID id = 0; + u32 count = system->font.get_count(); + for (Font_ID id_it = 1; id_it <= count; ++id_it){ + char str[256]; + i32 str_len = system->font.get_name_by_id(id_it, str, sizeof(str)); + if (str_len > 0){ + String font_name = make_string(str, str_len); + if (match_ss(font_name, name)){ + id = id_it; + break; + } + } + } + return(id); +} + +internal Glyph_Page** +font_page_lookup(Font_Page_Storage *page_storage, u32 page_number, b32 get_empty_slot){ + Glyph_Page **result = 0; + + if (page_storage->page_max > 0){ + u32 first_index = page_number % page_storage->page_max; + + u32 range_count = 0; + u32 ranges[4]; + if (first_index == 0){ + ranges[0] = 0; + ranges[1] = page_storage->page_max; + range_count = 2; + } + else{ + ranges[0] = first_index; + ranges[1] = page_storage->page_max; + ranges[2] = 0; + ranges[3] = first_index; + range_count = 4; + } + + Glyph_Page **pages = page_storage->pages; + if (get_empty_slot){ + for (u32 j = 0; j < range_count; j += 2){ + u32 stop = ranges[j+1]; + for (u32 i = ranges[j]; i < stop; ++i){ + if (pages[i] == FONT_PAGE_EMPTY || pages[i] == FONT_PAGE_DELETED){ + result = &pages[i]; + goto break2; + } + if (pages[i]->page_number == page_number){ + goto break2; + } + } + } + } + else{ + for (u32 j = 0; j < range_count; j += 2){ + u32 stop = ranges[j+1]; + for (u32 i = ranges[j]; i < stop; ++i){ + if (pages[i] == FONT_PAGE_EMPTY){ + goto break2; + } + if (pages[i] != FONT_PAGE_DELETED && pages[i]->page_number == page_number){ + result = &pages[i]; + goto break2; + } + } + } + } + + break2:; + } + + return(result); +} + +internal Glyph_Page* +font_get_page(Font_Page_Storage *pages, u32 page_number){ + Glyph_Page *result = 0; + if (page_number <= 0x10FF){ + Glyph_Page **page_get_result = font_page_lookup(pages, page_number, false); + if (page_get_result != 0){ + result = *page_get_result; + } + } + return(result); +} + +internal Glyph_Page* +font_allocate_and_hash_new_page(System_Functions *system, Font_Page_Storage *storage, u32 page_number){ + Glyph_Page *new_page = 0; + if (page_number <= 0x10FF){ + b32 has_space = true; + + // Grow and rehash the table if we need to now. + u32 new_page_count = 1; + u32 new_max = (storage->page_count + new_page_count)*3; + if (storage->page_max < FONT_PAGE_MAX && new_max > storage->page_max*2){ + Glyph_Page **pages = (Glyph_Page**)system->font.allocate(sizeof(Glyph_Page*)*new_max); + if (pages != 0){ + u32 old_max = storage->page_max; + Glyph_Page **old_pages = storage->pages; + storage->pages = pages; + storage->page_max = new_max; + memset(pages, 0, sizeof(*pages)*new_max); + if (old_pages != 0){ + for (u32 i = 0; i < old_max; ++i){ + Glyph_Page *this_page = old_pages[i]; + if (this_page != FONT_PAGE_EMPTY && this_page != FONT_PAGE_DELETED){ + u32 this_page_number = this_page->page_number; + Glyph_Page **dest = font_page_lookup(storage, this_page_number, true); + Assert(dest != 0); + *dest = this_page; + } + } + system->font.free(old_pages); + } + } + else{ + has_space = false; + } + } + + // Allocate and hash a new page if there is room in the table. + if (has_space){ + new_page = (Glyph_Page*)system->font.allocate(sizeof(Glyph_Page)); + if (new_page != 0){ + Glyph_Page **dest = font_page_lookup(storage, page_number, true); + Assert(dest != 0); + *dest = new_page; + storage->page_count += new_page_count; + } + } + } + return(new_page); +} + +internal Glyph_Page* +font_make_page(System_Functions *system, Font_Settings *settings, Font_Metrics *metrics, Font_Page_Storage *pages, u32 page_number){ + Glyph_Page *new_page = font_allocate_and_hash_new_page(system, pages, page_number); + if (new_page != 0){ + system->font.load_page(settings, metrics, new_page, page_number); + } + return(new_page); +} + +internal b32 +font_can_render(System_Functions *system, Font_Settings *settings, Font_Metrics *metrics, Font_Page_Storage *pages, u32 codepoint){ + b32 result = (codepoint <= 0x10FFFF); + return(result); +} + +/////// +// HACK(allen): Hack optimizations +struct Font_Cached_Lookup_Result{ + Glyph_Page *page; + u32 index; +}; + +internal Font_Cached_Lookup_Result +font_cached_lookup(Font_Page_Storage *pages, u32 page_number){ + Font_Cached_Lookup_Result result = {0}; + + result.index = page_number % ArrayCount(pages->cache); + if (pages->cache[result.index].page_number == page_number){ + result.page = pages->cache[result.index].page; + } + + if (result.page == 0){ + result.page = font_get_page(pages, page_number); + } + + return(result); +} + +internal Glyph_Page* +font_cached_get_page(Font_Page_Storage *pages, u32 page_number){ + Font_Cached_Lookup_Result result = font_cached_lookup(pages, page_number); + if (result.page != 0){ + pages->cache[result.index].page = result.page; + pages->cache[result.index].page_number = page_number; + } + return(result.page); +} + +internal Glyph_Page* +font_cached_get_or_make_page(System_Functions *system, Font_Settings *settings, Font_Metrics *metrics, Font_Page_Storage *pages, u32 page_number){ + Font_Cached_Lookup_Result result = font_cached_lookup(pages, page_number); + if (result.page == 0){ + result.page = font_make_page(system, settings, metrics, pages, page_number); + } + if (result.page != 0){ + pages->cache[result.index].page = result.page; + pages->cache[result.index].page_number = page_number; + } + return(result.page); +} +/////// + +internal f32 +font_get_glyph_advance(System_Functions *system, Font_Settings *settings, Font_Metrics *metrics, Font_Page_Storage *pages, u32 codepoint){ + f32 result = 0.f; + u32 page_number = (codepoint >> 8); + Glyph_Page *page = font_cached_get_or_make_page(system, settings, metrics, pages, page_number); + + u32 glyph_index = codepoint & 0xFF; + if (page != 0 && page->advance[glyph_index] > 0.f){ + result = page->advance[glyph_index]; + } + return(result); +} + +// BOTTOM + diff --git a/4ed_font.h b/4ed_font.h new file mode 100644 index 00000000..8864c7e5 --- /dev/null +++ b/4ed_font.h @@ -0,0 +1,127 @@ +/* + * Mr. 4th Dimention - Allen Webster + * + * 11.03.2017 + * + * Font system interface. + * + */ + +// TOP + +#if !defined(FCODER_FONT_H) +#define FCODER_FONT_H + +// NOTE(allen): A description of an available font. +struct Font_Loadable_Stub{ + b32 in_local_folder; + i32 len; + char name[256]; +}; + +// NOTE(allen): Settings that the are specified that determine how a font should be loaded and rendered. +struct Font_Settings{ + Font_Loadable_Stub stub; + i32 pt_size; + b32 use_hinting; +}; + +// NOTE(allen): Results about the font true for the entire font as a whole. +struct Font_Metrics{ + i32 name_len; + char name[256]; + + i32 height; + i32 ascent; + i32 descent; + i32 line_skip; + i32 advance; + + f32 byte_advance; + f32 sub_advances[3]; +}; + +// NOTE(allen): The pages of glyph data. +#define GLYPHS_PER_PAGE 256 + +struct Glyph_Bounds{ + f32 x0, x1; + f32 y0, y1; + f32 xoff, yoff; + f32 xoff2, yoff2; +}; +global_const Glyph_Bounds null_glyph_bounds = {0}; + +struct Glyph_Page{ + u32 page_number; + + b32 has_layout; + f32 advance[GLYPHS_PER_PAGE]; + Glyph_Bounds glyphs[GLYPHS_PER_PAGE]; + i32 tex_width, tex_height; + + b32 has_gpu_setup; + u32 gpu_tex; +}; + +#define FONT_PAGE_EMPTY ((Glyph_Page*)0) +#define FONT_PAGE_DELETED ((Glyph_Page*)(1)) +#define FONT_PAGE_MAX 0x1100 + +struct Font_Page_Storage{ + Glyph_Page **pages; + u32 page_count; + u32 page_max; + + // Hack optimizations + struct Page_Cache{ + u32 page_number; + Glyph_Page *page; + }; + + Page_Cache cache[16]; +}; + +// NOTE(allen): Types of refernces fonts. +struct Font_Pointers{ + b32 valid; + Font_Settings *settings; + Font_Metrics *metrics; + Font_Page_Storage *pages; +}; + +typedef u32 Font_ID; + +// NOTE(allen): Platform layer calls - implemented in a "font provider" +#define Sys_Font_Get_Count_Sig(n) u32 (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_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); + +#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_Free_Sig(n) void (n)(void *ptr) +typedef Sys_Font_Free_Sig(Font_Free_Function); + +struct Font_Functions{ + 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; + Font_Load_Page_Function *load_page; + Font_Allocate_Function *allocate; + Font_Free_Function *free; +}; + +#endif + +// BOTTOM + + diff --git a/4ed_font_data.h b/4ed_font_data.h deleted file mode 100644 index 81588f21..00000000 --- a/4ed_font_data.h +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Mr. 4th Dimention - Allen Webster - * - * 03.03.2017 - * - * Font data type definitions. - * - */ - -// TOP - -#if !defined(FCODER_FONT_DATA_H) -#define FCODER_FONT_DATA_H - -#define ITEM_PER_FONT_PAGE 256 - -struct Glyph_Bounds{ - f32 x0, x1; - f32 y0, y1; - f32 xoff, yoff; - f32 xoff2, yoff2; -}; -global_const Glyph_Bounds null_glyph_bounds = {0}; - -struct Glyph_Page{ - u32 page_number; - - b32 has_layout; - f32 advance[ITEM_PER_FONT_PAGE]; - Glyph_Bounds glyphs[ITEM_PER_FONT_PAGE]; - i32 tex_width, tex_height; - - b32 has_gpu_setup; - u32 gpu_tex; -}; - -#define FONT_PAGE_EMPTY ((Glyph_Page*)0) -#define FONT_PAGE_DELETED ((Glyph_Page*)(1)) -#define FONT_PAGE_MAX 0x1100 - -struct Render_Font{ - Glyph_Page **pages; - u32 page_count, page_max; - f32 byte_advance; - f32 byte_sub_advances[3]; - i32 height, ascent, descent, line_skip, advance; - i32 pt_size; - b32 use_hinting; - - u32 filename_len; - u32 name_len; - char filename[256]; - char name[256]; - - // Hack optimizations - struct Page_Cache{ - u32 page_number; - Glyph_Page *page; - }; - - Page_Cache cache[16]; -}; - -struct Glyph_Data{ - Glyph_Bounds bounds; - b32 has_gpu_setup; - u32 tex; - i32 tex_width, tex_height; -}; - -#endif - -// BOTTOM - diff --git a/4ed_font_interface.h b/4ed_font_interface.h deleted file mode 100644 index 81bee274..00000000 --- a/4ed_font_interface.h +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Mr. 4th Dimention - Allen Webster - * - * 11.03.2017 - * - * Font system interface. - * - */ - -// TOP - -#if !defined(FCODER_FONT_INTERFACE_H) -#define FCODER_FONT_INTERFACE_H - -typedef u32 Font_ID; - -struct Render_Font; -struct Glyph_Page; - -#define Sys_Font_Get_Count_Sig(name_) u32 (name_)(void) -typedef Sys_Font_Get_Count_Sig(Font_Get_Count_Function); - -#define Sys_Font_Get_IDs_By_Index_Sig(name_) b32 (name_)(Font_ID first_index, u32 index_count, u32 *id_out) -typedef Sys_Font_Get_IDs_By_Index_Sig(Font_Get_IDs_By_Index_Function); - -#define Sys_Font_Get_Name_By_Index_Sig(name_) u32 (name_)(u32 font_index, char *str_out, u32 str_out_cap) -typedef Sys_Font_Get_Name_By_Index_Sig(Font_Get_Name_By_Index_Function); - -#define Sys_Font_Get_Name_By_ID_Sig(name_) u32 (name_)(Font_ID font_id, char *str_out, u32 str_out_cap) -typedef Sys_Font_Get_Name_By_ID_Sig(Font_Get_Name_By_ID_Function); - -#define Sys_Font_Get_Render_Data_By_ID_Sig(name_) Render_Font* (name_)(Font_ID font_id) -typedef Sys_Font_Get_Render_Data_By_ID_Sig(Font_Get_Render_Data_By_ID_Function); - -#define Sys_Font_Load_Page_Sig(name_) void (name_)(Render_Font *font, Glyph_Page *page, u32 page_number) -typedef Sys_Font_Load_Page_Sig(Font_Load_Page_Function); - -#define Sys_Font_Allocate_Sig(name_) void* (name_)(i32 size) -typedef Sys_Font_Allocate_Sig(Font_Allocate_Function); - -#define Sys_Font_Free_Sig(name_) void (name_)(void *ptr) -typedef Sys_Font_Free_Sig(Font_Free_Function); - -struct Font_Functions{ - Font_Get_Count_Function *get_count; - Font_Get_IDs_By_Index_Function *get_ids_by_index; - Font_Get_Name_By_Index_Function *get_name_by_index; - Font_Get_Name_By_ID_Function *get_name_by_id; - Font_Get_Render_Data_By_ID_Function *get_render_data_by_id; - Font_Load_Page_Function *load_page; - - Font_Allocate_Function *allocate; - Font_Free_Function *free; -}; - -internal u32 font_get_id_by_name(struct System_Functions *system, String name); - -internal f32 font_get_byte_advance(Render_Font *font); -internal f32*font_get_byte_sub_advances(Render_Font *font); -internal i32 font_get_height(Render_Font *font); -internal i32 font_get_ascent(Render_Font *font); -internal i32 font_get_descent(Render_Font *font); -internal i32 font_get_line_skip(Render_Font *font); -internal i32 font_get_advance(Render_Font *font); - -internal b32 font_can_render(struct System_Functions *system, Render_Font *font, u32 codepoint); -internal f32 font_get_glyph_advance(struct System_Functions *system, Render_Font *font, u32 codepoint); - -struct Glyph_Data; -internal Glyph_Data font_get_glyph(System_Functions *system, Render_Font *font, u32 codepoint); - -internal Glyph_Page *font_get_or_make_page(struct System_Functions *system, Render_Font *font, u32 page_number); - -#endif - -// BOTTOM - - diff --git a/4ed_font_interface_to_os.h b/4ed_font_interface_to_os.h deleted file mode 100644 index e93efb6c..00000000 --- a/4ed_font_interface_to_os.h +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Mr. 4th Dimention - Allen Webster - * - * 13.03.2017 - * - * Font system interface to the OS layer. - * - */ - -// TOP - -#if !defined(FCODER_FONT_INTERFACE_TO_OS_H) -#define FCODER_FONT_INTERFACE_TO_OS_H - -#define Sys_Font_Init_Sig(name_) void (name_)(Font_Functions *font, void *memory, umem memory_size, u32 font_size, b32 use_hinting) -internal Sys_Font_Init_Sig(system_font_init); - - -#endif - -// BOTTOM - - - diff --git a/4ed_font_provider_freetype.cpp b/4ed_font_provider_freetype.cpp new file mode 100644 index 00000000..d217951e --- /dev/null +++ b/4ed_font_provider_freetype.cpp @@ -0,0 +1,447 @@ +/* + * Mr. 4th Dimention - Allen Webster + * + * 18.07.2017 + * + * Freetype implementation of the font provider interface. + * + */ + +// TOP + +// NOTE(allen): Thanks to insofaras. This is copy-pasted from some work he originally did to get free type working on Linux. + +#undef internal +#include +#include FT_FREETYPE_H +#define internal static + +internal u32 +font_ft_flags(b32 use_hinting){ + u32 ft_flags = FT_LOAD_RENDER; + + if (use_hinting){ + // NOTE(inso): FT_LOAD_TARGET_LIGHT does hinting only vertically, which looks nicer imo + // maybe it could be exposed as an option for hinting, instead of just on/off. + ft_flags |= FT_LOAD_FORCE_AUTOHINT | FT_LOAD_TARGET_LIGHT; + } + else{ + ft_flags |= (FT_LOAD_NO_AUTOHINT | FT_LOAD_NO_HINTING); + } + + return(ft_flags); +} + +internal void +font_load_page_layout(Font_Settings *settings, Font_Metrics *metrics, Glyph_Page *page, u32 page_number){ + Assert(page != 0); + memset(page, 0, sizeof(*page)); + + char *filename = settings->stub.name; + u32 pt_size = settings->pt_size; + b32 use_hinting = settings->use_hinting; + + // TODO(allen): Stop redoing all this init for each call. + FT_Library ft; + FT_Init_FreeType(&ft); + + FT_Face face; + FT_New_Face(ft, filename, 0, &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); + } + } + + // 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); +} + +internal u32* +font_load_page_pixels(Partition *part, Font_Settings *settings, Glyph_Page *page, u32 page_number, i32 *tex_width_out, i32 *tex_height_out){ + Assert(page != 0); + 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; + + // TODO(allen): Stop redoing all this init for each call. + FT_Library ft; + FT_Init_FreeType(&ft); + + FT_Face face; + FT_New_Face(ft, filename, 0, &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; + + 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); + + // 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]); + } + } + } + } + + *tex_width_out = tex_width; + *tex_height_out = tex_height; + + FT_Done_FreeType(ft); + + return(pixels); +} + +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. + FT_Library ft; + FT_Init_FreeType(&ft); + + FT_Face face; + FT_New_Face(ft, filename, 0, &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); + } + 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); +} + +//////////////////////////////// + +internal +Sys_Font_Get_Count_Sig(system_font_get_count){ + return(fontvars.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){ + u32 index = font_id - 1; + Font_Slot *slot = &fontvars.slots[index]; + if (slot->is_active){ + Font_Metrics *metrics = &slot->metrics; + length = metrics->name_len; + copy_partial_cs(str_out, capacity, make_string(metrics->name, length)); + } + } + return(length); +} + +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){ + u32 index = font_id - 1; + Font_Slot *slot = &fontvars.slots[index]; + if (slot->is_active){ + font.valid = true; + font.settings = &slot->settings; + font.metrics = &slot->metrics; + font.pages = &slot->pages; + } + } + return(font); +} + +internal +Sys_Font_Load_Page_Sig(system_font_load_page, settings, metrics, page, page_number){ + Assert(page_number != 0); + font_load_page_layout(settings, metrics, page, page_number); +} + +internal +Sys_Font_Allocate_Sig(system_font_allocate){ + i64 *size_ptr = 0; + void *result = system_memory_allocate(size + sizeof(*size_ptr)); + size_ptr = (i64*)result; + *size_ptr = size + 4; + return(size_ptr + 1); +} + +internal +Sys_Font_Free_Sig(system_font_free){ + if (ptr != 0){ + i64 *size_ptr = ((i64*)ptr) - 1; + system_memory_free(size_ptr, *size_ptr); + } +} + +//////////////////////////////// + +internal Font_Setup* +system_font_get_stubs(Partition *part){ + Font_Setup *first_setup = 0; + Font_Setup *head_setup = 0; + + u32 dir_max = KB(32); + u8 *directory = push_array(part, u8, dir_max); + String dir_str = make_string_cap(directory, 0, dir_max); + u32 dir_len = dir_str.size = system_get_4ed_path(dir_str.str, dir_str.memory_size); + Assert(dir_len < dir_max); + + set_last_folder_sc(&dir_str, "fonts", SLASH); + terminate_with_null(&dir_str); + dir_len = dir_str.size; + + partition_reduce(part, dir_max - dir_len - 1); + partition_align(part, 8); + + File_List file_list = {0}; + system_set_file_list(&file_list, (char*)directory, 0, 0, 0); + + for (u32 i = 0; i < file_list.count; ++i){ + File_Info *info = &file_list.infos[i]; + + char *filename = info->filename; + 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; + + partition_align(part, 8); + } + + + } + + system_set_file_list(&file_list, 0, 0, 0, 0); + + return(first_setup); +} + +internal void +system_font_init(Font_Functions *font, u32 pt_size, b32 use_hinting, Font_Setup *font_setup_head){ + // 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; + + // 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; + ptr != 0; + ptr = ptr->next_font){ + char *filename = ptr->stub.name; + + if (i < font_count_max){ + Font_Slot *slot = &fontvars.slots[i]; + Font_Settings *settings = &slot->settings; + Font_Metrics *metrics = &slot->metrics; + Font_Page_Storage *pages = &slot->pages; + + Assert(!slot->is_active); + + 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)); + } + } + 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 + diff --git a/4ed_font_provider_freetype.h b/4ed_font_provider_freetype.h new file mode 100644 index 00000000..f473ba1a --- /dev/null +++ b/4ed_font_provider_freetype.h @@ -0,0 +1,37 @@ +/* + * Mr. 4th Dimention - Allen Webster + * + * 16.11.2017 + * + * Data types for the freetype font provider. + * + */ + +// TOP + +#if !defined(FCODER_FONT_PROVIDER_FREETYPE_H) +#define FCODER_FONT_PROVIDER_FREETYPE_H + +struct Font_Slot{ + b32 is_active; + Font_Settings settings; + Font_Metrics metrics; + Font_Page_Storage pages; +}; + +struct Font_Vars{ + Font_Slot slots[32]; + u32 count; +}; + +global Font_Vars fontvars = {0}; + +struct Font_Setup{ + Font_Setup *next_font; + Font_Loadable_Stub stub; +}; + +#endif + +// BOTTOM + diff --git a/4ed_font_static_functions.cpp b/4ed_font_static_functions.cpp deleted file mode 100644 index b9951f34..00000000 --- a/4ed_font_static_functions.cpp +++ /dev/null @@ -1,245 +0,0 @@ -/* - * Mr. 4th Dimention - Allen Webster - * - * 11.03.2017 - * - * Implements some basic getters for fonts set up to make the font type opaque. - * - */ - -// TOP - -#include "4ed_font_data.h" - -internal u32 -font_get_id_by_name(System_Functions *system, String name){ - u32 id = 0; - u32 count = system->font.get_count(); - for (u32 index = 0; index < count; ++index){ - char str[256]; - u32 str_len = system->font.get_name_by_index(index, str, sizeof(str)); - String font_name = make_string(str, str_len); - if (match_ss(font_name, name)){ - system->font.get_ids_by_index(index, 1, &id); - break; - } - } - return(id); -} - -internal f32 -font_get_byte_advance(Render_Font *font){ - return(font->byte_advance); -} - -internal f32* -font_get_byte_sub_advances(Render_Font *font){ - return(font->byte_sub_advances); -} - -internal i32 -font_get_height(Render_Font *font){ - return(font->height); -} - -internal i32 -font_get_ascent(Render_Font *font){ - return(font->ascent); -} - -internal i32 -font_get_descent(Render_Font *font){ - return(font->descent); -} - -internal i32 -font_get_line_skip(Render_Font *font){ - return(font->line_skip); -} - -internal i32 -font_get_advance(Render_Font *font){ - return(font->advance); -} - -internal b32 -font_can_render(System_Functions *system, Render_Font *font, u32 codepoint){ - b32 result = false; - u32 page_number = (codepoint >> 8); - u32 glyph_index = codepoint & 0xFF; - Glyph_Page *page = font_get_or_make_page(system, font, page_number); - if (page != 0 && page->advance[glyph_index] > 0.f){ - result = true; - } - return(result); -} - -internal f32 -font_get_glyph_advance(System_Functions *system, Render_Font *font, u32 codepoint){ - f32 result = 0.f; - u32 page_number = (codepoint >> 8); - u32 glyph_index = codepoint & 0xFF; - - Glyph_Page *page = 0; - - // Hack optimizations - u32 cache_index = page_number % ArrayCount(font->cache); - if (font->cache[cache_index].page_number == page_number){ - page = font->cache[cache_index].page; - } - - if (page == 0){ - page = font_get_or_make_page(system, font, page_number); - font->cache[cache_index].page = page; - font->cache[cache_index].page_number = page_number; - } - - if (page != 0 && page->advance[glyph_index] > 0.f){ - result = page->advance[glyph_index]; - } - return(result); -} - -internal Glyph_Data -font_get_glyph(System_Functions *system, Render_Font *font, u32 codepoint){ - Glyph_Data result = {0}; - u32 page_number = (codepoint >> 8); - u32 glyph_index = codepoint & 0xFF; - - Glyph_Page *page = 0; - - // HACK(allen): Hack optimizations - u32 cache_index = page_number % ArrayCount(font->cache); - if (font->cache[cache_index].page_number == page_number){ - page = font->cache[cache_index].page; - } - - if (page == 0){ - page = font_get_or_make_page(system, font, page_number); - font->cache[cache_index].page = page; - font->cache[cache_index].page_number = page_number; - } - - if (page != 0 && page->advance[glyph_index] > 0.f){ - result.bounds = page->glyphs[glyph_index]; - result.has_gpu_setup = page->has_gpu_setup; - result.tex = page->gpu_tex; - result.tex_width = page->tex_width; - result.tex_height = page->tex_height; - } - - return(result); -} - -internal Glyph_Page** -font_page_lookup(Render_Font *font, u32 page_number, b32 get_empty_slot){ - Glyph_Page **result = 0; - - if (font->page_max > 0){ - u32 first_index = page_number % font->page_max; - - u32 range_count = 0; - u32 ranges[4]; - if (first_index == 0){ - ranges[0] = 0; - ranges[1] = font->page_max; - range_count = 2; - } - else{ - ranges[0] = first_index; - ranges[1] = font->page_max; - ranges[2] = 0; - ranges[3] = first_index; - range_count = 4; - } - - Glyph_Page **pages = font->pages; - if (get_empty_slot){ - for (u32 j = 0; j < range_count; j += 2){ - u32 stop = ranges[j+1]; - for (u32 i = ranges[j]; i < stop; ++i){ - if (pages[i] == FONT_PAGE_EMPTY || pages[i] == FONT_PAGE_DELETED){ - result = &pages[i]; - goto break2; - } - if (pages[i]->page_number == page_number){ - goto break2; - } - } - } - } - else{ - for (u32 j = 0; j < range_count; j += 2){ - u32 stop = ranges[j+1]; - for (u32 i = ranges[j]; i < stop; ++i){ - if (pages[i] == FONT_PAGE_EMPTY){ - goto break2; - } - if (pages[i] != FONT_PAGE_DELETED && pages[i]->page_number == page_number){ - result = &pages[i]; - goto break2; - } - } - } - } - - break2:; - } - - return(result); -} - -internal Glyph_Page* -font_get_or_make_page(System_Functions *system, Render_Font *font, u32 page_number){ - Glyph_Page *result = 0; - if (page_number <= 0x10FF){ - Glyph_Page **page_get_result = font_page_lookup(font, page_number, false); - - if (page_get_result == 0){ - b32 has_space = true; - u32 new_page_count = 1; - u32 new_max = (font->page_count+new_page_count)*3; - if (font->page_max < FONT_PAGE_MAX && new_max > font->page_max*2){ - Glyph_Page **pages = (Glyph_Page**)system->font.allocate(sizeof(Glyph_Page*)*new_max); - has_space = false; - if (pages != 0){ - memset(pages, 0, sizeof(*pages)*new_max); - u32 old_max = font->page_max; - Glyph_Page **old_pages = font->pages; - font->pages = pages; - font->page_max = new_max; - for (u32 i = 0; i < old_max; ++i){ - Glyph_Page *this_page = old_pages[i]; - if (this_page != FONT_PAGE_EMPTY && this_page != FONT_PAGE_DELETED){ - u32 this_page_number = this_page->page_number; - Glyph_Page **dest = font_page_lookup(font, this_page_number, true); - Assert(dest != 0); - *dest = this_page; - } - } - system->font.free(old_pages); - has_space = true; - } - } - - if (has_space){ - Glyph_Page *new_page = (Glyph_Page*)system->font.allocate(sizeof(Glyph_Page)); - if (new_page != 0){ - Glyph_Page **dest = font_page_lookup(font, page_number, true); - Assert(dest != 0); - *dest = new_page; - font->page_count += new_page_count; - result = new_page; - system->font.load_page(font, new_page, page_number); - } - } - } - else{ - result = *page_get_result; - } - } - return(result); -} - -// BOTTOM - diff --git a/4ed_font_system_functions.cpp b/4ed_font_system_functions.cpp deleted file mode 100644 index d624517d..00000000 --- a/4ed_font_system_functions.cpp +++ /dev/null @@ -1,305 +0,0 @@ -/* - * Mr. 4th Dimention - Allen Webster - * - * 14.11.2017 - * - * FreeType font loader implementation - * - */ - -// TOP - -// NOTE(allen): Thanks to insofaras. This is copy-pasted from some work he originally did to get free type working on Linux. - -#undef internal -#include -#include FT_FREETYPE_H -#define internal static - -internal u32 -font_ft_flags(b32 use_hinting){ - u32 ft_flags = FT_LOAD_RENDER; - - if (use_hinting){ - // NOTE(inso): FT_LOAD_TARGET_LIGHT does hinting only vertically, which looks nicer imo - // maybe it could be exposed as an option for hinting, instead of just on/off. - ft_flags |= FT_LOAD_FORCE_AUTOHINT | FT_LOAD_TARGET_LIGHT; - } - else{ - ft_flags |= (FT_LOAD_NO_AUTOHINT | FT_LOAD_NO_HINTING); - } - - return(ft_flags); -} - -internal void -font_load_page_layout(Render_Font *font, Glyph_Page *page, u32 page_number, u32 pt_size, b32 use_hinting){ - Assert(page != 0); - memset(page, 0, sizeof(*page)); - - char *filename = font->filename; - - // TODO(allen): Stop redoing all this init for each call. - FT_Library ft; - FT_Init_FreeType(&ft); - - FT_Face face; - FT_New_Face(ft, filename, 0, &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; - - i32 tab_width = 4; - - // NOTE(allen): Determine glyph layout dimensions - i32 max_glyph_w = face->size->metrics.x_ppem; - i32 max_glyph_h = font_get_height(font); - 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(ITEM_PER_FONT_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 < ITEM_PER_FONT_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 = font_get_ascent(font); - - // 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; - page->has_layout = true; - - // HACK(allen): Put this somewhere else! - // NOTE(allen): whitespace spacing stuff - if (page_number == 0){ - 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; - } - - FT_Done_FreeType(ft); -} - -internal u32* -font_load_page_pixels(Partition *part, Render_Font *font, Glyph_Page *page, u32 page_number, i32 *tex_width_out, i32 *tex_height_out){ - Assert(page != 0); - Assert(page->has_layout); - Assert(page->page_number == page_number); - - char *filename = font->filename; - i32 pt_size = font->pt_size; - b32 use_hinting = font->use_hinting; - - // TODO(allen): Stop redoing all this init for each call. - FT_Library ft; - FT_Init_FreeType(&ft); - - FT_Face face; - FT_New_Face(ft, filename, 0, &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; - - 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 (u32 i = 0; i < ITEM_PER_FONT_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 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]); - } - } - } - } - - *tex_width_out = tex_width; - *tex_height_out = tex_height; - - FT_Done_FreeType(ft); - - return(pixels); -} - -internal b32 -font_load(System_Functions *system, Partition *part, Render_Font *font, i32 pt_size, b32 use_hinting){ - char *filename = font->filename; - - // TODO(allen): Stop redoing all this init for each call. - FT_Library ft; - FT_Init_FreeType(&ft); - - FT_Face face; - FT_New_Face(ft, filename, 0, &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(font->name)-1); - memcpy(font->name, name, name_len); - font->name[name_len] = 0; - font->name_len = name_len; - - font->ascent = ceil32 (face->size->metrics.ascender / 64.0f); - font->descent = floor32 (face->size->metrics.descender / 64.0f); - font->advance = ceil32 (face->size->metrics.max_advance / 64.0f); - font->height = ceil32 (face->size->metrics.height / 64.0f); - font->line_skip = font->height - (font->ascent - font->descent); - - font->height -= font->line_skip; - font->line_skip = 0; - - font->pt_size = pt_size; - font->use_hinting = use_hinting; - - // NOTE(allen): Set texture and glyph data. - Glyph_Page *page = font_get_or_make_page(system, font, 0); - - // NOTE(allen): Setup some basic spacing stuff. - f32 backslash_adv = page->advance['\\']; - 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); - } - - font->byte_advance = backslash_adv + max_hex_advance*2; - font->byte_sub_advances[0] = backslash_adv; - font->byte_sub_advances[1] = max_hex_advance; - font->byte_sub_advances[2] = max_hex_advance; - - FT_Done_FreeType(ft); - - return(true); -} - -// TODO(allen): Remove Partition -internal void -system_set_page(System_Functions *system, Partition *part, Render_Font *font, Glyph_Page *page, u32 page_number, u32 pt_size, b32 use_hinting){ - Assert(pt_size >= 8); - font_load_page_layout(font, page, page_number, pt_size, use_hinting); -} - -internal void -system_set_font(System_Functions *system, Partition *part, Render_Font *font, char *filename, u32 pt_size, b32 use_hinting){ - memset(font, 0, sizeof(*font)); - - u32 filename_len = 0; - for (;filename[filename_len];++filename_len); - - if (filename_len <= sizeof(font->filename) - 1){ - memcpy(font->filename, filename, filename_len); - font->filename[filename_len] = 0; - font->filename_len = filename_len; - - if (part->base == 0){ - *part = sysshared_scratch_partition(MB(8)); - } - - b32 success = false; - for (u32 R = 0; R < 3; ++R){ - success = font_load(system, part, font, pt_size, use_hinting); - if (success){ - break; - } - else{ - sysshared_partition_double(part); - } - } - } - else{ - LOGF("font \"%.*s\" name is too long to load in current build (max %u)\n", filename_len, filename, (u32)(sizeof(font->filename) - 1)); - } -} - -// BOTTOM - diff --git a/4ed_render_fill.cpp b/4ed_render_fill.cpp index adc11871..fa439880 100644 --- a/4ed_render_fill.cpp +++ b/4ed_render_fill.cpp @@ -106,13 +106,13 @@ internal f32 draw_string_base(System_Functions *system, Render_Target *target, Font_ID font_id, String str_, i32 x_, i32 y_, u32 color){ f32 x = 0; - Render_Font *font = system->font.get_render_data_by_id(font_id); - if (font != 0){ + Font_Pointers font = system->font.get_pointers_by_id(font_id); + if (font.valid != 0){ f32 y = (f32)y_; x = (f32)x_; - f32 byte_advance = font_get_byte_advance(font); - f32 *sub_advances = font_get_byte_sub_advances(font); + f32 byte_advance = font.metrics->byte_advance; + f32 *sub_advances = font.metrics->sub_advances; u8 *str = (u8*)str_.str; u8 *str_end = str + str_.size; @@ -131,7 +131,7 @@ draw_string_base(System_Functions *system, Render_Target *target, Font_ID font_i if (color != 0){ draw_font_glyph(target, font_id, codepoint, x, y, color); } - x += font_get_glyph_advance(system, font, codepoint); + x += font_get_glyph_advance(system, font.settings, font.metrics, font.pages, codepoint); } else if (behavior.do_number_advance){ u8 n = (u8)(step.value); diff --git a/4ed_system.h b/4ed_system.h index db5a9e37..5e728a97 100644 --- a/4ed_system.h +++ b/4ed_system.h @@ -12,8 +12,6 @@ #if !defined(FCODER_SYSTEM_INTERFACE_H) #define FCODER_SYSTEM_INTERFACE_H -#include "4ed_font_interface.h" - // types struct Plat_Handle{ u32 d[4]; diff --git a/4ed_translation.cpp b/4ed_translation.cpp index 11aa4251..5523917c 100644 --- a/4ed_translation.cpp +++ b/4ed_translation.cpp @@ -133,7 +133,7 @@ translating_select_emit_rule_ASCII(Translation_State *tran, Translation_Byte_Des } internal void -translating_select_emit_rule_with_font(System_Functions *system, Render_Font *font, Translation_State *tran, Translation_Byte_Description desc, Translation_Emit_Rule *type_out){ +translating_select_emit_rule_with_font(System_Functions *system, Font_Pointers font, Translation_State *tran, Translation_Byte_Description desc, Translation_Emit_Rule *type_out){ type_out->byte_class = desc.byte_class; type_out->last_byte_handler = desc.last_byte_handler; type_out->emit_type = desc.prelim_emit_type; @@ -148,7 +148,7 @@ translating_select_emit_rule_with_font(System_Functions *system, Render_Font *fo } else{ type_out->codepoint = cp; - if (!font_can_render(system, font, cp)){ + if (!font_can_render(system, font.settings, font.metrics, font.pages, cp)){ type_out->emit_type = BufferModelUnit_Numbers; } } @@ -213,7 +213,7 @@ translating_generate_emits(Translation_State *tran, Translation_Emit_Rule emit_r } internal void -translating_fully_process_byte(System_Functions *system, Render_Font *font, Translation_State *tran, u8 ch, u32 i, u32 size, Translation_Emits *emits_out){ +translating_fully_process_byte(System_Functions *system, Font_Pointers font, Translation_State *tran, u8 ch, u32 i, u32 size, Translation_Emits *emits_out){ Translation_Byte_Description description = {0}; translating_consume_byte(tran, ch, i, size, &description); Translation_Emit_Rule emit_rule = {0}; diff --git a/opengl/4ed_opengl_render.cpp b/opengl/4ed_opengl_render.cpp index a83c7c90..4f60866e 100644 --- a/opengl/4ed_opengl_render.cpp +++ b/opengl/4ed_opengl_render.cpp @@ -49,7 +49,7 @@ private_draw_set_color(Render_Target *t, u32 color){ } internal void -interpret_render_buffer(System_Functions *system, Render_Target *t){ +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; @@ -152,57 +152,59 @@ interpret_render_buffer(System_Functions *system, Render_Target *t){ case RenCom_Glyph: { Render_Command_Glyph *glyph = (Render_Command_Glyph*)header; - Render_Font *font = system->font.get_render_data_by_id(glyph->font_id); - if (font == 0){ + Font_Pointers font = system_font_get_pointers_by_id(glyph->font_id); + if (!font.valid){ break; } - // HACK(allen): Super stupid... gotta fucking cleanup the font loading fiasco system. - Glyph_Data g = font_get_glyph(system, font, glyph->codepoint); - if (g.tex == 0){ - if (g.has_gpu_setup){ - break; - } - else{ - u32 page_number = (glyph->codepoint/ITEM_PER_FONT_PAGE); - Glyph_Page *page = font_get_or_make_page(system, font, page_number); - - Temp_Memory temp = begin_temp_memory(part); - i32 tex_width = 0; - i32 tex_height = 0; - u32 *pixels = font_load_page_pixels(part, font, page, page_number, &tex_width, &tex_height); - page->has_gpu_setup = true; - page->gpu_tex = private_texture_initialize(tex_width, tex_height, pixels); - end_temp_memory(temp); - - g = font_get_glyph(system, font, glyph->codepoint); - if (g.tex == 0){ - break; - } - } + u32 codepoint = glyph->codepoint; + u32 page_number = codepoint/GLYPHS_PER_PAGE; + Glyph_Page *page = font_cached_get_page(font.pages, page_number); + if (page == 0){ + break; } + if (!page->has_gpu_setup){ + Temp_Memory temp = begin_temp_memory(part); + i32 tex_width = 0; + i32 tex_height = 0; + u32 *pixels = font_load_page_pixels(part, font.settings, page, page_number, &tex_width, &tex_height); + page->has_gpu_setup = true; + page->gpu_tex = private_texture_initialize(tex_width, tex_height, pixels); + end_temp_memory(temp); + } + + if (page->gpu_tex == 0){ + break; + } + + u32 glyph_index = codepoint%GLYPHS_PER_PAGE; + Glyph_Bounds bounds = page->glyphs[glyph_index]; + GLuint tex = page->gpu_tex; + i32 tex_width = page->tex_width; + i32 tex_height = page->tex_height; + f32 x = glyph->pos.x; f32 y = glyph->pos.y; f32_Rect xy = {0}; - xy.x0 = x + g.bounds.xoff; - xy.y0 = y + g.bounds.yoff; - xy.x1 = x + g.bounds.xoff2; - xy.y1 = y + g.bounds.yoff2; + xy.x0 = x + bounds.xoff; + xy.y0 = y + bounds.yoff; + xy.x1 = x + bounds.xoff2; + xy.y1 = y + bounds.yoff2; // TODO(allen): Why aren't these baked in??? - f32 unit_u = 1.f/g.tex_width; - f32 unit_v = 1.f/g.tex_height; + f32 unit_u = 1.f/tex_width; + f32 unit_v = 1.f/tex_height; f32_Rect uv = {0}; - uv.x0 = g.bounds.x0*unit_u; - uv.y0 = g.bounds.y0*unit_v; - uv.x1 = g.bounds.x1*unit_u; - uv.y1 = g.bounds.y1*unit_v; + uv.x0 = bounds.x0*unit_u; + uv.y0 = bounds.y0*unit_v; + uv.x1 = bounds.x1*unit_u; + uv.y1 = bounds.y1*unit_v; private_draw_set_color(t, glyph->color); - private_draw_bind_texture(t, g.tex); + private_draw_bind_texture(t, tex); glBegin(GL_QUADS); { glTexCoord2f(uv.x0, uv.y1); glVertex2f(xy.x0, xy.y1); diff --git a/platform_all/4ed_shared_fonts.cpp b/platform_all/4ed_shared_fonts.cpp deleted file mode 100644 index cd6ee1ef..00000000 --- a/platform_all/4ed_shared_fonts.cpp +++ /dev/null @@ -1,168 +0,0 @@ -/* - * Mr. 4th Dimention - Allen Webster - * - * 18.07.2017 - * - * Shared font functions - * - */ - -// TOP - -struct Font_Vars{ - Partition part; - Render_Font fonts[32]; - u32 font_count; -}; - -global Font_Vars fontvars = {0}; - -internal -Sys_Font_Get_Count_Sig(system_font_get_count){ - return(fontvars.font_count); -} - -internal -Sys_Font_Get_IDs_By_Index_Sig(system_font_get_ids_by_index){ - b32 result = false; - u32 stop_index = first_index + index_count; - if (stop_index <= fontvars.font_count){ - result = true; - for (u32 i = first_index; i < stop_index; ++i){ - id_out[i-first_index] = i; - } - } - return(result); -} - -internal -Sys_Font_Get_Name_By_Index_Sig(system_font_get_name_by_index){ - u32 length = 0; - if (font_index < fontvars.font_count){ - Render_Font *font = &fontvars.fonts[font_index]; - char *name = font->name; - length = font->name_len; - copy_partial_cs(str_out, str_out_cap, make_string(name, length)); - } - return(length); -} - -internal -Sys_Font_Get_Name_By_ID_Sig(system_font_get_name_by_id){ - u32 font_index = font_id; - u32 result = system_font_get_name_by_index(font_index, str_out, str_out_cap); - return(result); -} - -internal -Sys_Font_Get_Render_Data_By_ID_Sig(system_font_get_render_data_by_id){ - Render_Font *result = 0; - u32 font_index = font_id; - if (font_index < fontvars.font_count){ - result = &fontvars.fonts[font_index]; - } - return(result); -} - -internal -Sys_Font_Load_Page_Sig(system_font_load_page){ - system_set_page(&sysfunc, &fontvars.part, font, page, page_number, plat_settings.font_size, plat_settings.use_hinting); -} - -internal -Sys_Font_Allocate_Sig(system_font_allocate){ - void *result = system_memory_allocate(size); - return(result); -} - -// HACK(allen): Have to pass the size somehow or the free doesn't actually happen on linux. -internal -Sys_Font_Free_Sig(system_font_free){ - system_memory_free(ptr, 0); -} - -internal -Sys_Font_Init_Sig(system_font_init){ - Assert(font_size >= 8); - - Partition *scratch = &shared_vars.scratch; - Temp_Memory temp = begin_temp_memory(scratch); - - font->get_count = system_font_get_count; - font->get_ids_by_index = system_font_get_ids_by_index; - font->get_name_by_index = system_font_get_name_by_index; - font->get_name_by_id = system_font_get_name_by_id; - font->get_render_data_by_id = system_font_get_render_data_by_id; - font->load_page = system_font_load_page; - font->allocate = system_font_allocate; - font->free = system_font_free; - - struct Font_Setup{ - Font_Setup *next_font; - char *c_filename; - }; - - Font_Setup *first_setup = 0; - Font_Setup *head_setup = 0; - - u32 dir_max = KB(32); - u8 *directory = push_array(scratch, u8, dir_max); - String dir_str = make_string_cap(directory, 0, dir_max); - u32 dir_len = dir_str.size = system_get_4ed_path(dir_str.str, dir_str.memory_size); - Assert(dir_len < dir_max); - - set_last_folder_sc(&dir_str, "fonts", SLASH); - terminate_with_null(&dir_str); - dir_len = dir_str.size; - - partition_reduce(scratch, dir_max - dir_len - 1); - partition_align(scratch, 8); - - File_List file_list = {0}; - system_set_file_list(&file_list, (char*)directory, 0, 0, 0); - - for (u32 i = 0; i < file_list.count; ++i){ - File_Info *info = &file_list.infos[i]; - if (first_setup == 0){ - first_setup = push_struct(scratch, Font_Setup); - head_setup = first_setup; - } - else{ - head_setup->next_font = push_struct(scratch, Font_Setup); - head_setup = head_setup->next_font; - } - head_setup->next_font = 0; - - char *filename = info->filename; - u32 len = 0; - for (;filename[len];++len); - - head_setup->c_filename = push_array(scratch, char, dir_len+len+1); - memcpy(head_setup->c_filename, directory, dir_len); - memcpy(head_setup->c_filename + dir_len, filename, len+1); - - partition_align(scratch, 8); - } - - system_set_file_list(&file_list, 0, 0, 0, 0); - - u32 font_count_max = ArrayCount(fontvars.fonts); - u32 font_count = 0; - u32 i = 0; - for (Font_Setup *ptr = first_setup; ptr != 0; ptr = ptr->next_font, ++i){ - if (i < font_count_max){ - Render_Font *render_font = &fontvars.fonts[i]; - - system_set_font(&sysfunc, &fontvars.part, render_font, ptr->c_filename, font_size, use_hinting); - } - - ++font_count; - } - - fontvars.font_count = clamp_top(font_count, font_count_max); - - end_temp_memory(temp); -} - -// BOTTOM - diff --git a/platform_linux/linux_4ed.cpp b/platform_linux/linux_4ed.cpp index 6f917b9b..3a6836fa 100644 --- a/platform_linux/linux_4ed.cpp +++ b/platform_linux/linux_4ed.cpp @@ -36,6 +36,7 @@ #include "4ed_math.h" +#include "4ed_font.h" #include "4ed_system.h" #include "4ed_log.h" #include "4ed_render_format.h" @@ -43,7 +44,6 @@ #include "4ed.h" #include "4ed_file_track.h" -#include "4ed_font_interface_to_os.h" #include "4ed_system_shared.h" #include "unix_4ed_headers.h" @@ -120,9 +120,10 @@ internal void LinuxStringDup(String*, void*, size_t); global System_Functions sysfunc; #include "4ed_shared_library_constants.h" #include "unix_library_wrapper.h" -#include "4ed_standard_libraries.cpp" +#include "4ed_standard_libraries.cpp" #include "4ed_coroutine.cpp" +#include "4ed_font.cpp" //////////////////////////////// @@ -332,7 +333,6 @@ Sys_Send_Exit_Signal_Sig(system_send_exit_signal){ #include "4ed_coroutine_functions.cpp" -#include "4ed_font_data.h" #include "4ed_system_shared.cpp" // @@ -456,8 +456,8 @@ Sys_CLI_End_Update_Sig(system_cli_end_update){ return(close_me); } -#include "4ed_font_system_functions.cpp" - +#include "4ed_font_provider_freetype.h" +#include "4ed_font_provider_freetype.cpp" #include #include "opengl/4ed_opengl_render.cpp" @@ -1604,7 +1604,11 @@ main(int argc, char **argv){ // Font System Init // - system_font_init(&sysfunc.font, 0, 0, plat_settings.font_size, plat_settings.use_hinting); + 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); + end_temp_memory(temp); // // Epoll init @@ -1771,7 +1775,7 @@ main(int argc, char **argv){ } // NOTE(allen): Render - interpret_render_buffer(&sysfunc, &target); + interpret_render_buffer(&target); glXSwapBuffers(linuxvars.XDisplay, linuxvars.XWindow); // NOTE(allen): Toggle Full Screen @@ -1809,9 +1813,7 @@ main(int argc, char **argv){ return(0); } -#include "4ed_shared_fonts.cpp" #include "linux_4ed_file_track.cpp" -#include "4ed_font_static_functions.cpp" // BOTTOM // vim: expandtab:ts=4:sts=4:sw=4 diff --git a/platform_linux/linux_font.cpp b/platform_linux/linux_font.cpp deleted file mode 100644 index e54b051d..00000000 --- a/platform_linux/linux_font.cpp +++ /dev/null @@ -1,104 +0,0 @@ -/* - * Insofaras - * - * ??.??.2016 - * - * For getting the font files on Linux. - * - */ - -// TOP - -#if 0 -#undef internal -#include -#define internal static - -//TODO(inso): put in linuxvars -static FcConfig* fc; - -internal char* -linux_get_sys_font(char* name, i32 pt_size){ - char* result = 0; - - if(!fc){ - fc = FcInitLoadConfigAndFonts(); - } - - FcPattern* pat = FcPatternBuild( - NULL, - FC_POSTSCRIPT_NAME, FcTypeString, name, - FC_SIZE, FcTypeDouble, (double)pt_size, - FC_FONTFORMAT, FcTypeString, "TrueType", - NULL - ); - - FcConfigSubstitute(fc, pat, FcMatchPattern); - FcDefaultSubstitute(pat); - - FcResult res; - FcPattern* font = FcFontMatch(fc, pat, &res); - FcChar8* fname = 0; - - if(font){ - FcPatternGetString(font, FC_FILE, 0, &fname); - if(fname){ - result = strdup((char*)fname); - fprintf(stderr, "Got system font from FontConfig: %s\n", result); - } - FcPatternDestroy(font); - } - - FcPatternDestroy(pat); - - if (!result){ - char space[1024]; - String str = make_fixed_width_string(space); - if (sysshared_to_binary_path(&str, name)){ - result = strdup(space); - } - else{ - result = strdup(name); - } - } - - return result; -} - -internal b32 -linux_font_load(Partition *part, Render_Font *rf, char *name, i32 pt_size, i32 tab_width, b32 use_hinting){ - b32 result = 0; - - Temp_Memory temp = begin_temp_memory(part); - -#if 0 - char* filename = linux_get_sys_font(name, pt_size); -#else - char* filename = push_array(part, char, 256); - if (filename != 0){ - String str = make_string_cap(filename, 0, 256); - sysshared_to_binary_path(&str, name); - } -#endif - - if (filename != 0){ - struct stat st; - if(stat(filename, &st) == -1 || S_ISDIR(st.st_mode)){ - char buff[1024]; - - // NOTE(inso): if/when you can load fonts from anywhere, the message should be changed. - snprintf(buff, sizeof(buff), "Unable to load font '%s'. Make sure this file is in the same directory as the '4ed' executable.", filename); - system_error_box(buff); - } - - result = font_load_freetype(part, rf, filename, pt_size, tab_width, use_hinting); - } - - end_temp_memory(temp); - - return(result); -} -#endif - -// BOTTOM - diff --git a/platform_mac/mac_4ed.cpp b/platform_mac/mac_4ed.cpp index b757b92b..cb332aaf 100644 --- a/platform_mac/mac_4ed.cpp +++ b/platform_mac/mac_4ed.cpp @@ -35,6 +35,7 @@ #include "4ed_math.h" +#include "4ed_font.h" #include "4ed_system.h" #include "4ed_log.h" #include "4ed_render_format.h" @@ -42,7 +43,6 @@ #include "4ed.h" #include "4ed_file_track.h" -#include "4ed_font_interface_to_os.h" #include "4ed_system_shared.h" #include "unix_4ed_headers.h" @@ -75,9 +75,10 @@ __sync_val_compare_and_swap((dest), (comp), (ex)) global System_Functions sysfunc; #include "4ed_shared_library_constants.h" #include "unix_library_wrapper.h" -#include "4ed_standard_libraries.cpp" +#include "4ed_standard_libraries.cpp" #include "4ed_coroutine.cpp" +#include "4ed_font.cpp" //////////////////////////////// @@ -192,7 +193,6 @@ Sys_Send_Exit_Signal_Sig(system_send_exit_signal){ #include "4ed_coroutine_functions.cpp" -#include "4ed_font_data.h" #include "4ed_system_shared.cpp" // @@ -331,8 +331,8 @@ Sys_CLI_End_Update_Sig(system_cli_end_update){ return(close_me); } -#include "4ed_font_system_functions.cpp" - +#include "4ed_font_provider_freetype.h" +#include "4ed_font_provider_freetype.cpp" #include #include #include "opengl/4ed_opengl_render.cpp" @@ -562,7 +562,7 @@ osx_step(void){ // NOTE(allen): Render osx_begin_render(); - interpret_render_buffer(&sysfunc, &target); + interpret_render_buffer(&target); osx_end_render(); // NOTE(allen): Toggle Full Screen @@ -649,7 +649,12 @@ osx_init(){ // DBG_POINT(); - system_font_init(&sysfunc.font, 0, 0, plat_settings.font_size, plat_settings.use_hinting); + + 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); + end_temp_memory(temp); // // App Init @@ -680,9 +685,7 @@ osx_init(){ DBG_POINT(); } -#include "4ed_shared_fonts.cpp" #include "mac_4ed_file_track.cpp" -#include "4ed_font_static_functions.cpp" // BOTTOM diff --git a/platform_win32/win32_4ed.cpp b/platform_win32/win32_4ed.cpp index 1cae7cc6..f910776c 100644 --- a/platform_win32/win32_4ed.cpp +++ b/platform_win32/win32_4ed.cpp @@ -46,6 +46,7 @@ #include "4ed_math.h" +#include "4ed_font.h" #include "4ed_system.h" #include "4ed_log.h" #include "4ed_render_format.h" @@ -62,7 +63,6 @@ #include "win32_utf8.h" #include "4ed_file_track.h" -#include "4ed_font_interface_to_os.h" #include "4ed_system_shared.h" #include "4ed_shared_thread_constants.h" @@ -113,9 +113,10 @@ struct Win32_Input_Chunk{ global System_Functions sysfunc; #include "4ed_shared_library_constants.h" #include "win32_library_wrapper.h" -#include "4ed_standard_libraries.cpp" +#include "4ed_standard_libraries.cpp" #include "4ed_coroutine.cpp" +#include "4ed_font.cpp" //////////////////////////////// @@ -281,7 +282,6 @@ Sys_Send_Exit_Signal_Sig(system_send_exit_signal){ #include "4ed_coroutine_functions.cpp" -#include "4ed_font_data.h" #include "4ed_system_shared.cpp" // @@ -503,7 +503,8 @@ Sys_CLI_End_Update_Sig(system_cli_end_update){ return(close_me); } -#include "4ed_font_system_functions.cpp" +#include "4ed_font_provider_freetype.h" +#include "4ed_font_provider_freetype.cpp" #include #include "opengl/4ed_opengl_render.cpp" @@ -1115,7 +1116,11 @@ WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdS // LOG("Initializing fonts\n"); - system_font_init(&sysfunc.font, 0, 0, plat_settings.font_size, plat_settings.use_hinting); + 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); + end_temp_memory(temp); // // Misc System Initializations @@ -1425,7 +1430,7 @@ WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdS // NOTE(allen): Render HDC hdc = GetDC(win32vars.window_handle); - interpret_render_buffer(&sysfunc, &target); + interpret_render_buffer(&target); SwapBuffers(hdc); ReleaseDC(win32vars.window_handle, hdc); @@ -1462,9 +1467,7 @@ WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdS return(0); } -#include "4ed_shared_fonts.cpp" #include "win32_4ed_file_track.cpp" -#include "4ed_font_static_functions.cpp" #include "win32_utf8.cpp" #if 0