From 95104afd378f3dc9ef3c24a519563c6c9f52cabc Mon Sep 17 00:00:00 2001 From: Allen Webster Date: Fri, 13 Nov 2015 23:42:06 -0500 Subject: [PATCH] app platform split --- 4coder_custom.h | 7 +- 4ed.cpp | 293 ++-- 4ed.h | 290 +--- 4ed_app_target.cpp | 93 ++ 4ed_color_view.cpp | 57 +- 4ed_command.cpp | 3 +- 4ed_debug_view.cpp | 185 +-- 4ed_file_view.cpp | 267 ++-- 4ed_interactive_view.cpp | 17 +- 4ed_internal.h | 190 +-- 4ed_layout.cpp | 51 +- 4ed_mem.cpp | 253 ++++ 4ed_meta.h | 1 + 4ed_rendering.cpp | 7 +- 4ed_style.cpp | 15 +- 4ed_system.h | 230 +-- buffer/4coder_test_main.cpp | 13 +- buffer/stb_truetype.h | 2663 ----------------------------------- win32_4ed.cpp | 391 +++-- 19 files changed, 1143 insertions(+), 3883 deletions(-) create mode 100644 4ed_app_target.cpp create mode 100644 4ed_mem.cpp delete mode 100644 buffer/stb_truetype.h diff --git a/4coder_custom.h b/4coder_custom.h index bf56a768..a6e801fb 100644 --- a/4coder_custom.h +++ b/4coder_custom.h @@ -223,9 +223,7 @@ struct Buffer_Summary{ const char *buffer_name; int file_cursor_pos; - int is_lexed; - int map_id; }; @@ -263,6 +261,11 @@ struct Application_Links{ Get_Active_Buffer_Function *get_active_buffer; }; +struct Config_API{ + Get_Binding_Data_Function *get_bindings; + Set_Extra_Font_Function *set_extra_font; +}; + // NOTE(allen): definitions for the buffer that communicates to 4ed.exe enum Binding_Unit_Type{ diff --git a/4ed.cpp b/4ed.cpp index 5334ca95..a42a82e8 100644 --- a/4ed.cpp +++ b/4ed.cpp @@ -75,6 +75,8 @@ struct App_Vars{ App_State state; App_State_Resizing resizing; Panel *prev_mouse_panel; + + Config_API config_api; }; internal i32 @@ -141,8 +143,8 @@ globalvar Application_Links app_links; #define REQ_COLOR_VIEW(n) Color_View *n = view_to_color_view(command->view); if (!n) return #define REQ_DBG_VIEW(n) Debug_View *n = view_to_debug_view(command->view); if (!n) return -#define COMMAND_DECL(n) internal void command_##n(Command_Data *command, Command_Binding binding) -#define COMPOSE_DECL(n) internal void n(Command_Data *command, Command_Binding binding) +#define COMMAND_DECL(n) internal void command_##n(System_Functions *system, Command_Data *command, Command_Binding binding) +#define COMPOSE_DECL(n) internal void n(System_Functions *system, Command_Data *command, Command_Binding binding) struct Command_Data{ Mem_Options *mem; @@ -159,6 +161,7 @@ struct Command_Data{ Key_Single key; Partition part; + System_Functions *system; }; struct Command_Parameter{ @@ -222,7 +225,7 @@ COMMAND_DECL(write_character){ i32 pos; pos = view->cursor.pos; i32 next_cursor_pos = view->cursor.pos + string.size; - view_replace_range(mem, view, layout, pos, pos, (u8*)string.str, string.size, next_cursor_pos); + view_replace_range(system, mem, view, layout, pos, pos, (u8*)string.str, string.size, next_cursor_pos); view_cursor_move(view, next_cursor_pos); if (view->mark >= pos) view->mark += string.size; file->cursor_pos = view->cursor.pos; @@ -454,7 +457,7 @@ COMMAND_DECL(copy){ Range range = get_range(view->cursor.pos, view->mark); if (range.start < range.end){ - clipboard_copy(&mem->general, working_set, range, file); + clipboard_copy(system, &mem->general, working_set, range, file); } } @@ -470,11 +473,11 @@ COMMAND_DECL(cut){ if (range.start < range.end){ i32 next_cursor_pos = range.start; - clipboard_copy(&mem->general, working_set, range, file); - view_replace_range(mem, view, layout, range.start, range.end, 0, 0, next_cursor_pos); + clipboard_copy(system, &mem->general, working_set, range, file); + view_replace_range(system, mem, view, layout, range.start, range.end, 0, 0, next_cursor_pos); view->mark = range.start; - view_measure_wraps(&mem->general, view); + view_measure_wraps(system, &mem->general, view); view_cursor_move(view, next_cursor_pos); } } @@ -494,7 +497,7 @@ COMMAND_DECL(paste){ i32 pos_left = view->cursor.pos; i32 next_cursor_pos = pos_left+src->size; - view_replace_range(mem, view, layout, pos_left, pos_left, (u8*)src->str, src->size, next_cursor_pos); + view_replace_range(system, mem, view, layout, pos_left, pos_left, (u8*)src->str, src->size, next_cursor_pos); view_cursor_move(view, next_cursor_pos); view->mark = pos_left; @@ -528,7 +531,8 @@ COMMAND_DECL(paste_next){ Range range = get_range(view->mark, view->cursor.pos); String *src = working_set_clipboard_roll_down(working_set); i32 next_cursor_pos = range.start+src->size; - view_replace_range(mem, view, layout, range.start, range.end, + view_replace_range(system, + mem, view, layout, range.start, range.end, (u8*)src->str, src->size, next_cursor_pos); view_cursor_move(view, next_cursor_pos); @@ -548,7 +552,7 @@ COMMAND_DECL(paste_next){ } } else{ - command_paste(command, binding); + command_paste(system, command, binding); } } @@ -562,8 +566,8 @@ COMMAND_DECL(delete_range){ Range range = get_range(view->cursor.pos, view->mark); if (range.start < range.end){ i32 next_cursor_pos = range.start; - view_replace_range(mem, view, layout, range.start, range.end, 0, 0, next_cursor_pos); - view_measure_wraps(&mem->general, view); + view_replace_range(system, mem, view, layout, range.start, range.end, 0, 0, next_cursor_pos); + view_measure_wraps(system, &mem->general, view); view_cursor_move(view, next_cursor_pos); view->mark = range.start; } @@ -586,7 +590,7 @@ COMMAND_DECL(undo){ USE_LAYOUT(layout); USE_MEM(mem); - view_undo(mem, layout, view); + view_undo(system, mem, layout, view); } COMMAND_DECL(redo){ @@ -596,7 +600,7 @@ COMMAND_DECL(redo){ USE_LAYOUT(layout); USE_MEM(mem); - view_redo(mem, layout, view); + view_redo(system, mem, layout, view); } COMMAND_DECL(increase_rewind_speed){ @@ -642,7 +646,7 @@ COMMAND_DECL(history_backward){ USE_LAYOUT(layout); USE_MEM(mem); - view_history_step(mem, layout, view, hist_backward); + view_history_step(system, mem, layout, view, hist_backward); } COMMAND_DECL(history_forward){ @@ -652,7 +656,7 @@ COMMAND_DECL(history_forward){ USE_LAYOUT(layout); USE_MEM(mem); - view_history_step(mem, layout, view, hist_forward); + view_history_step(system, mem, layout, view, hist_forward); } COMMAND_DECL(save_history){ @@ -661,7 +665,7 @@ COMMAND_DECL(save_history){ REQ_FILE(file, view); USE_MEM(mem); - file_dump_history(mem, file, "history_data.hst"); + file_dump_history(system, mem, file, "history_data.hst"); } COMMAND_DECL(interactive_new){ @@ -675,11 +679,12 @@ COMMAND_DECL(interactive_new){ USE_DELAY(delay); View *new_view = live_set_alloc_view(live_set, mem); - view_replace_minor(new_view, panel, live_set); + view_replace_minor(system, new_view, panel, live_set); new_view->map = &vars->map_ui; Interactive_View *int_view = - interactive_view_init(new_view, &vars->hot_directory, style, + interactive_view_init(system, + new_view, &vars->hot_directory, style, working_set, delay); int_view->interaction = INTV_SYS_FILE_LIST; int_view->action = INTV_NEW; @@ -687,7 +692,8 @@ COMMAND_DECL(interactive_new){ } internal File_View* -app_open_file(App_Vars *vars, Mem_Options *mem, Panel *panel, +app_open_file(System_Functions *system, + App_Vars *vars, Mem_Options *mem, Panel *panel, Working_Set *working_set, String *string, Style *style, Live_Views *live_set, Command_Data *command_data){ File_View *result = 0; @@ -699,7 +705,7 @@ app_open_file(App_Vars *vars, Mem_Options *mem, Panel *panel, Get_File_Result file = working_set_get_available_file(working_set); if (file.file){ file_get_dummy(file.file); - created_file = file_create(mem, file.file, (u8*)string->str, style->font); + created_file = file_create(system, mem, file.file, string->str, style->font); table_add(&working_set->table, file.file->source_path, file.index); if (created_file){ target_file = file.file; @@ -710,7 +716,7 @@ app_open_file(App_Vars *vars, Mem_Options *mem, Panel *panel, if (target_file){ View *new_view = live_set_alloc_view(live_set, &vars->mem); - view_replace_major(new_view, panel, live_set); + view_replace_major(system, new_view, panel, live_set); File_View *file_view = file_view_init(new_view, &vars->layout); result = file_view; @@ -722,7 +728,8 @@ app_open_file(App_Vars *vars, Mem_Options *mem, Panel *panel, Temp_Memory temp = begin_temp_memory(&vars->mem.part); command_data->part = partition_sub_part(&vars->mem.part, 16 << 10); - view_set_file(file_view, target_file, style, + view_set_file(system, + file_view, target_file, style, vars->hooks[hook_open_file], command_data, app_links); command_data->part = old_part; @@ -734,7 +741,7 @@ app_open_file(App_Vars *vars, Mem_Options *mem, Panel *panel, #if BUFFER_EXPERIMENT_SCALPEL <= 0 if (created_file && target_file->tokens_exist) - file_first_lex_parallel(&mem->general, target_file); + file_first_lex_parallel(system, &mem->general, target_file); #endif } @@ -771,17 +778,19 @@ COMMAND_DECL(interactive_open){ if (filename){ String string = make_string(filename, filename_len); - if (app_open_file(vars, mem, panel, working_set, + if (app_open_file(system, + vars, mem, panel, working_set, &string, style, live_set, command)) made_file = 1; } if (!made_file){ View *new_view = live_set_alloc_view(live_set, mem); - view_replace_minor(new_view, panel, live_set); + view_replace_minor(system, new_view, panel, live_set); new_view->map = &vars->map_ui; Interactive_View *int_view = - interactive_view_init(new_view, &vars->hot_directory, style, + interactive_view_init(system, + new_view, &vars->hot_directory, style, working_set, delay); int_view->interaction = INTV_SYS_FILE_LIST; int_view->action = INTV_OPEN; @@ -803,21 +812,23 @@ COMMAND_DECL(reopen){ USE_VARS(vars); Editing_File temp_file; - if (file_create(mem, &temp_file, (u8*)make_c_str(file->source_path), style->font)){ - file_close(&mem->general, file); + if (file_create(system, + mem, &temp_file, make_c_str(file->source_path), style->font)){ + file_close(system, &mem->general, file); *file = temp_file; file->source_path.str = file->source_path_; file->live_name.str = file->live_name_; #if BUFFER_EXPERIMENT_SCALPEL <= 0 if (file->tokens_exist) - file_first_lex_parallel(&mem->general, file); + file_first_lex_parallel(system, &mem->general, file); #endif Partition old_part = command->part; Temp_Memory temp = begin_temp_memory(&vars->mem.part); command->part = partition_sub_part(&vars->mem.part, 16 << 10); - view_set_file(view, file, style, + view_set_file(system, + view, file, style, vars->hooks[hook_open_file], command, app_links); command->part = old_part; @@ -830,7 +841,7 @@ COMMAND_DECL(reopen){ View *current_view_ = current_panel->view; File_View *current_view = view_to_file_view(current_view_); if (current_view && current_view != view && current_view->file == file){ - view_set_file(current_view, current_view->file, style, 0, command, app_links); + view_set_file(system, current_view, current_view->file, style, 0, command, app_links); } } } @@ -844,7 +855,7 @@ COMMAND_DECL(save){ String *file_path = &file->source_path; if (file_path->size > 0){ - file_save(&mem->part, file, file_path->str); + file_save(system, &mem->part, file, file_path->str); } } @@ -859,11 +870,12 @@ COMMAND_DECL(interactive_save_as){ USE_DELAY(delay); View *new_view = live_set_alloc_view(live_set, mem); - view_replace_minor(new_view, panel, live_set); + view_replace_minor(system, new_view, panel, live_set); new_view->map = &vars->map_ui; Interactive_View *int_view = - interactive_view_init(new_view, &vars->hot_directory, style, + interactive_view_init(system, + new_view, &vars->hot_directory, style, working_set, delay); int_view->interaction = INTV_SYS_FILE_LIST; int_view->action = INTV_SAVE_AS; @@ -892,11 +904,12 @@ COMMAND_DECL(interactive_switch_buffer){ USE_DELAY(delay); View *new_view = live_set_alloc_view(live_set, mem); - view_replace_minor(new_view, panel, live_set); + view_replace_minor(system, new_view, panel, live_set); new_view->map = &vars->map_ui; Interactive_View *int_view = - interactive_view_init(new_view, &vars->hot_directory, style, + interactive_view_init(system, + new_view, &vars->hot_directory, style, working_set, delay); int_view->interaction = INTV_LIVE_FILE_LIST; int_view->action = INTV_SWITCH; @@ -914,11 +927,12 @@ COMMAND_DECL(interactive_kill_buffer){ USE_DELAY(delay); View *new_view = live_set_alloc_view(live_set, mem); - view_replace_minor(new_view, panel, live_set); + view_replace_minor(system, new_view, panel, live_set); new_view->map = &vars->map_ui; Interactive_View *int_view = - interactive_view_init(new_view, &vars->hot_directory, style, + interactive_view_init(system, + new_view, &vars->hot_directory, style, working_set, delay); int_view->interaction = INTV_LIVE_FILE_LIST; int_view->action = INTV_KILL; @@ -969,16 +983,17 @@ COMMAND_DECL(toggle_tokens){ USE_MEM(mem); if (file->tokens_exist){ - file_kill_tokens(&mem->general, file); + file_kill_tokens(system, &mem->general, file); } else{ - file_first_lex_parallel(&mem->general, file); + file_first_lex_parallel(system, &mem->general, file); } #endif } internal void -case_change_range(Mem_Options *mem, File_View *view, Editing_File *file, +case_change_range(System_Functions *system, + Mem_Options *mem, File_View *view, Editing_File *file, u8 a, u8 z, u8 char_delta){ #if BUFFER_EXPERIMENT_SCALPEL <= 0 Range range = get_range(view->cursor.pos, view->mark); @@ -990,7 +1005,7 @@ case_change_range(Mem_Options *mem, File_View *view, Editing_File *file, step.edit.len = range.end - range.start; if (file->still_lexing) - system_cancel_job(BACKGROUND_THREADS, file->lex_job); + system->cancel_job(BACKGROUND_THREADS, file->lex_job); file_update_history_before_edit(mem, file, step, 0, hist_normal); @@ -1002,7 +1017,7 @@ case_change_range(Mem_Options *mem, File_View *view, Editing_File *file, } if (file->token_stack.tokens) - file_relex_parallel(mem, file, range.start, range.end, 0); + file_relex_parallel(system, mem, file, range.start, range.end, 0); } #endif } @@ -1012,7 +1027,7 @@ COMMAND_DECL(to_uppercase){ REQ_FILE_VIEW(view); REQ_FILE(file, view); USE_MEM(mem); - case_change_range(mem, view, file, 'a', 'z', (u8)('A' - 'a')); + case_change_range(system, mem, view, file, 'a', 'z', (u8)('A' - 'a')); } COMMAND_DECL(to_lowercase){ @@ -1020,7 +1035,7 @@ COMMAND_DECL(to_lowercase){ REQ_FILE_VIEW(view); REQ_FILE(file, view); USE_MEM(mem); - case_change_range(mem, view, file, 'A', 'Z', (u8)('a' - 'A')); + case_change_range(system, mem, view, file, 'A', 'Z', (u8)('a' - 'A')); } COMMAND_DECL(clean_all_lines){ @@ -1030,7 +1045,7 @@ COMMAND_DECL(clean_all_lines){ USE_LAYOUT(layout); USE_MEM(mem); - view_clean_whitespace(mem, view, layout); + view_clean_whitespace(system, mem, view, layout); } COMMAND_DECL(eol_dosify){ @@ -1039,7 +1054,7 @@ COMMAND_DECL(eol_dosify){ REQ_FILE(file, view); file->dos_write_mode = 1; - file->last_4ed_edit_time = system_get_now(); + file->last_4ed_edit_time = system->time_stamp_now(); } COMMAND_DECL(eol_nixify){ @@ -1048,7 +1063,7 @@ COMMAND_DECL(eol_nixify){ REQ_FILE(file, view); file->dos_write_mode = 0; - file->last_4ed_edit_time = system_get_now(); + file->last_4ed_edit_time = system->time_stamp_now(); } COMMAND_DECL(auto_tab){ @@ -1075,7 +1090,7 @@ COMMAND_DECL(auto_tab_range){ if (file->token_stack.tokens && file->tokens_complete){ Range range = get_range(view->cursor.pos, view->mark); - view_auto_tab_tokens(mem, view, layout, range.start, range.end, 1); + view_auto_tab_tokens(system, mem, view, layout, range.start, range.end, 1); } } @@ -1088,7 +1103,7 @@ COMMAND_DECL(auto_tab_line_at_cursor){ if (file->token_stack.tokens && file->tokens_complete){ i32 pos = view->cursor.pos; - view_auto_tab_tokens(mem, view, layout, pos, pos, 0); + view_auto_tab_tokens(system, mem, view, layout, pos, pos, 0); } } @@ -1100,7 +1115,7 @@ COMMAND_DECL(auto_tab_whole_file){ USE_MEM(mem); if (file->token_stack.tokens && file->tokens_complete){ - view_auto_tab_tokens(mem, view, layout, 0, buffer_size(&file->buffer), 1); + view_auto_tab_tokens(system, mem, view, layout, 0, buffer_size(&file->buffer), 1); } } @@ -1164,7 +1179,7 @@ COMMAND_DECL(close_panel){ if (layout->panel_count > 1){ if (view){ - live_set_free_view(command->live_set, view); + live_set_free_view(system, command->live_set, view); panel->view = 0; } @@ -1265,7 +1280,7 @@ COMMAND_DECL(delete){ Assert(shift > 0); i32 next_cursor_pos = start; - view_replace_range(mem, view, layout, start, end, 0, 0, next_cursor_pos); + view_replace_range(system, mem, view, layout, start, end, 0, 0, next_cursor_pos); view_cursor_move(view, next_cursor_pos); if (view->mark >= end) view->mark -= shift; } @@ -1289,7 +1304,7 @@ COMMAND_DECL(backspace){ Assert(shift > 0); i32 next_cursor_pos = view->cursor.pos - shift; - view_replace_range(mem, view, layout, start, end, 0, 0, next_cursor_pos); + view_replace_range(system, mem, view, layout, start, end, 0, 0, next_cursor_pos); view_cursor_move(view, next_cursor_pos); if (view->mark >= end) view->mark -= shift; } @@ -1371,9 +1386,10 @@ COMMAND_DECL(page_up){ } inline void -open_theme_options(App_Vars *vars, Live_Views *live_set, Mem_Options *mem, Panel *panel){ +open_theme_options(System_Functions *system, + App_Vars *vars, Live_Views *live_set, Mem_Options *mem, Panel *panel){ View *new_view = live_set_alloc_view(live_set, mem); - view_replace_minor(new_view, panel, live_set); + view_replace_minor(system, new_view, panel, live_set); new_view->map = &vars->map_ui; Color_View *color_view = color_view_init(new_view, &vars->working_set); @@ -1392,7 +1408,7 @@ COMMAND_DECL(open_color_tweaker){ USE_MEM(mem); USE_PANEL(panel); - open_theme_options(vars, live_set, mem, panel); + open_theme_options(system, vars, live_set, mem, panel); } COMMAND_DECL(open_menu){ @@ -1405,7 +1421,7 @@ COMMAND_DECL(open_menu){ USE_STYLE(style); View *new_view = live_set_alloc_view(live_set, mem); - view_replace_minor(new_view, panel, live_set); + view_replace_minor(system, new_view, panel, live_set); new_view->map = &vars->map_ui; Menu_View *menu_view = menu_view_init(new_view, style, working_set, &vars->delay); @@ -1422,7 +1438,7 @@ COMMAND_DECL(open_debug_view){ USE_MEM(mem); View *new_view = live_set_alloc_view(live_set, mem); - view_replace_major(new_view, panel, live_set); + view_replace_major(system, new_view, panel, live_set); new_view->map = &vars->map_debug; Debug_View *debug_view = debug_view_init(new_view); @@ -1442,16 +1458,6 @@ COMMAND_DECL(debug_os_events){ view->mode = DBG_OS_EVENTS; } -COMMAND_DECL(debug_profile){ - ProfileMomentFunction(); - REQ_DBG_VIEW(view); - view->mode = DBG_PROFILE; -} - -COMMAND_DECL(pause_unpause_profile){ - ProfileMomentFunction(); - INTERNAL_updating_profile = !INTERNAL_updating_profile; -} #endif COMMAND_DECL(close_minor_view){ @@ -1460,7 +1466,7 @@ COMMAND_DECL(close_minor_view){ USE_PANEL(panel); USE_LIVE_SET(live_set); - view_remove_minor(panel, live_set); + view_remove_minor(system, panel, live_set); } COMMAND_DECL(cursor_mark_swap){ @@ -1495,10 +1501,10 @@ COMMAND_DECL(set_settings){ #if BUFFER_EXPERIMENT_SCALPEL <= 0 int v = dynamic_to_bool(¶m->param.value); if (file->tokens_exist){ - if (!v) file_kill_tokens(&mem->general, file); + if (!v) file_kill_tokens(system, &mem->general, file); } else{ - if (v) file_first_lex_parallel(&mem->general, file); + if (v) file_first_lex_parallel(system, &mem->general, file); } #endif }break; @@ -1575,20 +1581,21 @@ COMMAND_DECL(build){ } if (file){ - file_create_super_locked(mem, file, (u8*)buffer_name, style->font); + file_create_super_locked(system, mem, file, buffer_name, style->font); table_add(&working_set->table, file->live_name, index); View *new_view = live_set_alloc_view(live_set, mem); - view_replace_major(new_view, panel, live_set); + view_replace_major(system, new_view, panel, live_set); File_View *file_view = file_view_init(new_view, &vars->layout); - view_set_file(file_view, file, style, + view_set_file(system, + file_view, file, style, vars->hooks[hook_open_file], command, app_links); new_view->map = app_get_map(vars, file->base_map_id); i32 i = vars->cli_processes.count++; CLI_Process *proc = vars->cli_processes.procs + i; - if (!system_cli_call(path, script, &proc->cli)){ + if (!system->cli_call(path, script, &proc->cli)){ --vars->cli_processes.count; } proc->out_file = file; @@ -1618,15 +1625,15 @@ update_command_data(App_Vars *vars, Command_Data *cmd){ command_data.screen_height = cmd->screen_height; command_data.key = cmd->key; command_data.part = cmd->part; + command_data.system = cmd->system; *cmd = command_data; } - COMPOSE_DECL(compose_write_auto_tab_line){ - command_write_character(command, binding); + command_write_character(system, command, binding); update_command_data(command->vars, command); - command_auto_tab_line_at_cursor(command, binding); + command_auto_tab_line_at_cursor(system, command, binding); update_command_data(command->vars, command); } @@ -1638,7 +1645,7 @@ extern "C"{ Command_Function function = command_table[command_id]; Command_Binding binding; binding.function = function; - if (function) function(cmd, binding); + if (function) function(cmd->system, cmd, binding); update_command_data(cmd->vars, cmd); } @@ -1715,7 +1722,6 @@ setup_debug_commands(Command_Map *commands, Partition *part, Key_Codes *codes, C map_add(commands, 'm', MDFR_NONE, command_debug_memory); map_add(commands, 'o', MDFR_NONE, command_debug_os_events); - map_add(commands, 'p', MDFR_NONE, command_debug_profile); } #endif @@ -1804,7 +1810,6 @@ setup_top_commands(Command_Map *commands, Partition *part, Key_Codes *codes, Com #if FRED_INTERNAL map_add(commands, 'd', MDFR_ALT, command_open_debug_view); - map_add(commands, 'p', MDFR_CTRL | MDFR_ALT, command_pause_unpause_profile); #endif map_add(commands, 'p', MDFR_CTRL, command_open_panel_vsplit); @@ -2201,9 +2206,10 @@ app_hardcode_styles(App_Vars *vars){ } internal bool32 -app_load_font(Font *font, char *filename, i32 size, void *memory, +app_load_font(System_Functions *system, + Font *font, char *filename, i32 size, void *memory, i32 *used, i32 tab_width, String name){ - if (font_load(font, filename, size, memory, font_predict_size(size), used, tab_width)){ + if (font_load(system, font, filename, size, memory, font_predict_size(size), used, tab_width)){ font->loaded = 1; font->name_[ArrayCount(font->name_)-1] = 0; font->name = make_string(font->name_, 0, ArrayCount(font->name_)-1); @@ -2256,15 +2262,14 @@ HOOK_SIG(default_open_file_hook){ app.clear_parameters(cmd_context); } -internal bool32 -app_init(Thread_Context *thread, Application_Memory *memory, - Key_Codes *loose_codes, Clipboard_Contents clipboard){ +external App_Init_Sig(app_init){ app_links_init(); Partition _partition = partition_open(memory->vars_memory, memory->vars_memory_size); App_Vars *vars = push_struct(&_partition, App_Vars); Assert(vars); *vars = {}; + vars->config_api = api; vars->mem.part = _partition; Partition *partition = &vars->mem.part; general_memory_open(&vars->mem.general, memory->target_memory, memory->target_memory_size); @@ -2319,14 +2324,14 @@ app_init(Thread_Context *thread, Application_Memory *memory, setup_command_table(); Command_Map *global = &vars->map_top; - if (TEMP.get_bindings){ + if (vars->config_api.get_bindings){ i32 size = partition_remaining(partition); void *data = partition_current(partition); // TODO(allen): Use a giant bubble of general memory for this. // So that it doesn't interfere with the command maps as they allocate // their own memory. - i32 wanted_size = TEMP.get_bindings(data, size, loose_codes); + i32 wanted_size = vars->config_api.get_bindings(data, size, loose_codes); bool32 did_top = 0; bool32 did_file = 0; @@ -2458,41 +2463,47 @@ app_init(Thread_Context *thread, Application_Memory *memory, i32 memory_used; memory_used = 0; - app_load_font(vars->fonts.fonts + font_count++, "liberation-mono.ttf", 17, + app_load_font(system, + vars->fonts.fonts + font_count++, "liberation-mono.ttf", 17, partition_current(partition), &memory_used, 4, make_lit_string("liberation mono")); push_block(partition, memory_used); memory_used = 0; - app_load_font(vars->fonts.fonts + font_count++, "LiberationSans-Regular.ttf", 17, + app_load_font(system, + vars->fonts.fonts + font_count++, "LiberationSans-Regular.ttf", 17, partition_current(partition), &memory_used, 4, make_lit_string("liberation sans")); push_block(partition, memory_used); memory_used = 0; - app_load_font(vars->fonts.fonts + font_count++, "Hack-Regular.ttf", 17, + app_load_font(system, + vars->fonts.fonts + font_count++, "Hack-Regular.ttf", 17, partition_current(partition), &memory_used, 4, make_lit_string("hack")); push_block(partition, memory_used); memory_used = 0; - app_load_font(vars->fonts.fonts + font_count++, "CutiveMono-Regular.ttf", 17, + app_load_font(system, + vars->fonts.fonts + font_count++, "CutiveMono-Regular.ttf", 17, partition_current(partition), &memory_used, 4, make_lit_string("cutive mono")); push_block(partition, memory_used); memory_used = 0; - app_load_font(vars->fonts.fonts + font_count++, "Inconsolata-Regular.ttf", 17, + app_load_font(system, + vars->fonts.fonts + font_count++, "Inconsolata-Regular.ttf", 17, partition_current(partition), &memory_used, 4, make_lit_string("inconsolata")); push_block(partition, memory_used); - if (TEMP.set_extra_font){ + if (vars->config_api.set_extra_font){ Extra_Font extra; extra.size = 17; - TEMP.set_extra_font(&extra); + vars->config_api.set_extra_font(&extra); memory_used = 0; - if (app_load_font(vars->fonts.fonts + font_count, extra.file_name, extra.size, + if (app_load_font(system, + vars->fonts.fonts + font_count, extra.file_name, extra.size, partition_current(partition), &memory_used, 4, make_string_slowly(extra.font_name))){ ++font_count; @@ -2545,7 +2556,7 @@ app_init(Thread_Context *thread, Application_Memory *memory, panel_init(&panels[0]); vars->hot_dir_base = make_fixed_width_string(vars->hot_dir_base_); - hot_directory_init(&vars->hot_directory, vars->hot_dir_base); + hot_directory_init(system, &vars->hot_directory, vars->hot_dir_base); vars->mini_str = make_string((char*)vars->mini_buffer, 0, 512); @@ -2559,14 +2570,7 @@ app_init(Thread_Context *thread, Application_Memory *memory, return 1; } -internal Application_Step_Result -app_step(Thread_Context *thread, Key_Codes *codes, - Key_Input_Data *input, Mouse_State *mouse, - bool32 time_step, Render_Target *target, - Application_Memory *memory, - Clipboard_Contents clipboard, - bool32 first_step, bool32 force_redraw){ - +external App_Step_Sig(app_step){ ProfileStart(OS_syncing); Application_Step_Result app_result = {}; app_result.redraw = force_redraw; @@ -2592,7 +2596,7 @@ app_step(Thread_Context *thread, Key_Codes *codes, if (!file->is_dummy){ Time_Stamp time_stamp; - time_stamp = system_file_time_stamp((u8*)make_c_str(file->source_path)); + time_stamp = system->file_time_stamp(make_c_str(file->source_path)); if (time_stamp.success){ file->last_sys_write_time = time_stamp.time; @@ -2616,8 +2620,8 @@ app_step(Thread_Context *thread, Key_Codes *codes, Editing_File *out_file = proc->out_file; i32 new_cursor = out_file->cursor_pos; - for (system_cli_begin_update(&proc->cli); - system_cli_update_step(&proc->cli, dest, max, &amount);){ + for (system->cli_begin_update(&proc->cli); + system->cli_update_step(&proc->cli, dest, max, &amount);){ if (out_file){ amount = eol_in_place_convert_in(dest, amount); Edit_Spec spec = {}; @@ -2628,14 +2632,14 @@ app_step(Thread_Context *thread, Key_Codes *codes, spec.step.pre_pos = new_cursor; spec.step.post_pos = spec.step.edit.start + amount; spec.str = (u8*)dest; - file_do_single_edit(&vars->mem, out_file, + file_do_single_edit(system, &vars->mem, out_file, &vars->layout, spec, hist_normal); app_result.redraw = 1; new_cursor = spec.step.post_pos; } } - if (system_cli_end_update(&proc->cli)){ + if (system->cli_end_update(&proc->cli)){ *proc = vars->cli_processes.procs[--count]; --i; } @@ -2676,7 +2680,7 @@ app_step(Thread_Context *thread, Key_Codes *codes, if (!view_->is_active) continue; File_View *view = view_to_file_view(view_); if (!view) continue; - view_measure_wraps(&vars->mem.general, view); + view_measure_wraps(system, &vars->mem.general, view); view->cursor = view_compute_cursor_from_pos(view, view->cursor.pos); } app_result.redraw = 1; @@ -2926,6 +2930,7 @@ app_step(Thread_Context *thread, Key_Codes *codes, command_data.vars = vars; command_data.screen_width = target->width; command_data.screen_height = target->height; + command_data.system = system; Temp_Memory param_stack_temp = begin_temp_memory(&vars->mem.part); command_data.part = partition_sub_part(&vars->mem.part, 16 << 10); @@ -2973,12 +2978,12 @@ app_step(Thread_Context *thread, Key_Codes *codes, Handle_Command_Function *handle_command = 0; if (view) handle_command = view->handle_command; if (handle_command){ - handle_command(view, &command_data, cmd, key, codes); + handle_command(system, view, &command_data, cmd, key, codes); app_result.redraw = 1; } else{ if (cmd.function){ - cmd.function(&command_data, cmd); + cmd.function(system, &command_data, cmd); app_result.redraw = 1; } } @@ -3025,7 +3030,7 @@ app_step(Thread_Context *thread, Key_Codes *codes, if (panel == mouse_panel){ input.mouse = mouse_data; } - if (view_->do_view(thread, view_, panel->inner, active_view, + if (view_->do_view(system, thread, view_, panel->inner, active_view, VMSG_STEP, 0, &input, &active_input)){ app_result.redraw = 1; } @@ -3054,7 +3059,8 @@ app_step(Thread_Context *thread, Key_Codes *codes, case DACT_OPEN: { command_data.view = (View*) - app_open_file(vars, mem, panel, working_set, string, style, live_set, &command_data); + app_open_file(system, + vars, mem, panel, working_set, string, style, live_set, &command_data); }break; case DACT_SAVE_AS: @@ -3066,7 +3072,7 @@ app_step(Thread_Context *thread, Key_Codes *codes, if (fview){ Editing_File *file = fview->file; if (file && !file->is_dummy){ - file_save_and_set_names(&vars->mem.part, file, string->str); + file_save_and_set_names(system, &vars->mem.part, file, string->str); } } }break; @@ -3075,26 +3081,27 @@ app_step(Thread_Context *thread, Key_Codes *codes, { Editing_File *file = working_set_lookup_file(working_set, *string); if (!file->is_dummy){ - file_save(&vars->mem.part, file, file->source_path.str); + file_save(system, &vars->mem.part, file, file->source_path.str); } }break; case DACT_NEW: { Get_File_Result file = working_set_get_available_file(working_set); - file_create_empty(mem, file.file, (u8*)string->str, style->font); + file_create_empty(system, mem, file.file, string->str, style->font); table_add(&working_set->table, file.file->source_path, file.index); View *new_view = live_set_alloc_view(live_set, mem); - view_replace_major(new_view, panel, live_set); + view_replace_major(system, new_view, panel, live_set); File_View *file_view = file_view_init(new_view, &vars->layout); command_data.view = (View*)file_view; - view_set_file(file_view, file.file, style, + view_set_file(system, + file_view, file.file, style, vars->hooks[hook_open_file], &command_data, app_links); new_view->map = app_get_map(vars, file.file->base_map_id); #if BUFFER_EXPERIMENT_SCALPEL <= 0 - if (file.file->tokens_exist) file_first_lex_parallel(general, file.file); + if (file.file->tokens_exist) file_first_lex_parallel(system, general, file.file); #endif }break; @@ -3103,12 +3110,13 @@ app_step(Thread_Context *thread, Key_Codes *codes, Editing_File *file = working_set_lookup_file(working_set, *string); if (file){ View *new_view = live_set_alloc_view(live_set, mem); - view_replace_major(new_view, panel, live_set); + view_replace_major(system, new_view, panel, live_set); File_View *file_view = file_view_init(new_view, &vars->layout); command_data.view = (View*)file_view; - view_set_file(file_view, file, style, + view_set_file(system, + file_view, file, style, vars->hooks[hook_open_file], &command_data, app_links); new_view->map = app_get_map(vars, file->base_map_id); @@ -3120,7 +3128,7 @@ app_step(Thread_Context *thread, Key_Codes *codes, Editing_File *file = working_set_lookup_file(working_set, *string); if (file){ table_remove(&working_set->table, file->source_path); - kill_file(general, file, live_set, &vars->layout); + kill_file(system, general, file, live_set, &vars->layout); } }break; @@ -3133,18 +3141,19 @@ app_step(Thread_Context *thread, Key_Codes *codes, case SYNC_GOOD: { table_remove(&working_set->table, file->source_path); - kill_file(general, file, live_set, &vars->layout); - view_remove_minor(panel, live_set); + kill_file(system, general, file, live_set, &vars->layout); + view_remove_minor(system, panel, live_set); }break; case SYNC_UNSAVED: { View *new_view = live_set_alloc_view(live_set, mem); - view_replace_minor(new_view, panel, live_set); + view_replace_minor(system, new_view, panel, live_set); new_view->map = &vars->map_ui; Interactive_View *int_view = - interactive_view_init(new_view, &vars->hot_directory, style, + interactive_view_init(system, + new_view, &vars->hot_directory, style, working_set, &vars->delay); int_view->interaction = INTV_SURE_TO_KILL_INTER; int_view->action = INTV_SURE_TO_KILL; @@ -3159,17 +3168,17 @@ app_step(Thread_Context *thread, Key_Codes *codes, case DACT_CLOSE_MINOR: { - view_remove_minor(panel, live_set); + view_remove_minor(system, panel, live_set); }break; case DACT_CLOSE_MAJOR: { - view_remove_major(panel, live_set); + view_remove_major(system, panel, live_set); }break; case DACT_THEME_OPTIONS: { - open_theme_options(vars, live_set, mem, panel); + open_theme_options(system, vars, live_set, mem, panel); }break; } } @@ -3189,11 +3198,13 @@ app_step(Thread_Context *thread, Key_Codes *codes, prev.x1 != inner.x1 || prev.y1 != inner.y1){ View *view = panel->view; if (view){ - view->do_view(thread, view, inner, active_view, + view->do_view(system, + thread, view, inner, active_view, VMSG_RESIZE, 0, &dead_input, &active_input); view = (view->is_minor)?view->major:0; if (view){ - view->do_view(thread, view, inner, active_view, + view->do_view(system, + thread, view, inner, active_view, VMSG_RESIZE, 0, &dead_input, &active_input); } } @@ -3211,7 +3222,8 @@ app_step(Thread_Context *thread, Key_Codes *codes, Editing_File *file = vars->working_set.files; for (i32 i = vars->working_set.file_index_count; i > 0; --i, ++file){ if (buffer_good(&file->buffer) && !file->is_dummy){ - file_measure_starts_widths(&vars->mem.general, &file->buffer, vars->style.font); + file_measure_starts_widths(system, + &vars->mem.general, &file->buffer, vars->style.font); } } @@ -3219,11 +3231,13 @@ app_step(Thread_Context *thread, Key_Codes *codes, for (i32 panel_i = vars->layout.panel_count; panel_i > 0; --panel_i, ++panel){ View *view = panel->view; if (view){ - view->do_view(thread, view, panel->inner, active_view, + view->do_view(system, + thread, view, panel->inner, active_view, VMSG_STYLE_CHANGE, 0, &dead_input, &active_input); view = (view->is_minor)?view->major:0; if (view){ - view->do_view(thread, view, panel->inner, active_view, + view->do_view(system, + thread, view, panel->inner, active_view, VMSG_STYLE_CHANGE, 0, &dead_input, &active_input); } } @@ -3253,7 +3267,8 @@ app_step(Thread_Context *thread, Key_Codes *codes, if (view_){ Assert(view_->do_view); draw_push_clip(target, panel->inner); - view_->do_view(thread, view_, panel->inner, active_view, + view_->do_view(system, + thread, view_, panel->inner, active_view, VMSG_DRAW, target, &dead_input, &active_input); draw_pop_clip(target); } diff --git a/4ed.h b/4ed.h index e0578e6c..b413c7a2 100644 --- a/4ed.h +++ b/4ed.h @@ -3,249 +3,15 @@ * * 12.12.2014 * - * Application Layer for project codename "4ed" + * Application Layer for 4coder * */ +// TOP + #ifndef FRED_H #define FRED_H -struct Partition{ - u8 *base; - i32 pos, max; -}; - -inline Partition -partition_open(void *memory, i32 size){ - Partition partition; - partition.base = (u8*)memory;; - partition.pos = 0; - partition.max = size; - return partition; -} - -inline void* -partition_allocate(Partition *data, i32 size){ - void *ret = 0; - if (size > 0 && data->pos + size <= data->max){ - ret = data->base + data->pos; - data->pos += size; - } - return ret; -} - -inline void -partition_align(Partition *data, u32 boundary){ - data->pos = (data->pos + (boundary - 1)) & (~boundary); -} - -inline void* -partition_current(Partition *data){ - return data->base + data->pos; -} - -inline i32 -partition_remaining(Partition *data){ - return data->max - data->pos; -} - -inline Partition -partition_sub_part(Partition *data, i32 size){ - Partition result = {}; - void *d = partition_allocate(data, size); - if (d) result = partition_open(d, size); - return result; -} - -#define push_struct(part, T) (T*)partition_allocate(part, sizeof(T)) -#define push_array(part, T, size) (T*)partition_allocate(part, sizeof(T)*(size)) -#define push_block(part, size) partition_allocate(part, size) - -enum Memory_Bubble_Flag{ - MEM_BUBBLE_USED = 0x1, - MEM_BUBBLE_DEBUG = 0xD3000000, - MEM_BUBBLE_SYS_DEBUG = 0x5D000000, - MEM_BUBBLE_DEBUG_MASK = 0xFF000000 -}; -struct Bubble{ - Bubble *prev; - Bubble *next; - u32 flags; - i32 size; - u32 type; - u32 _unused_; -}; -struct General_Memory{ - Bubble sentinel; -}; - -inline void -insert_bubble(Bubble *prev, Bubble *bubble){ - bubble->prev = prev; - bubble->next = prev->next; - bubble->prev->next = bubble; - bubble->next->prev = bubble; -} - -inline void -remove_bubble(Bubble *bubble){ - bubble->prev->next = bubble->next; - bubble->next->prev = bubble->prev; -} - -#if FRED_INTERNAL -#define MEM_BUBBLE_FLAG_INIT MEM_BUBBLE_DEBUG -#else -#define MEM_BUBBLE_FLAG_INIT 0 -#endif - -internal void -general_memory_open(General_Memory *general, void *memory, i32 size){ - general->sentinel.prev = &general->sentinel; - general->sentinel.next = &general->sentinel; - general->sentinel.flags = MEM_BUBBLE_USED; - general->sentinel.size = 0; - - Bubble *first = (Bubble*)memory; - first->flags = (u32)MEM_BUBBLE_FLAG_INIT; - first->size = size - sizeof(Bubble); - insert_bubble(&general->sentinel, first); -} - -internal void -general_memory_check(General_Memory *general){ - Bubble *sentinel = &general->sentinel; - for (Bubble *bubble = sentinel->next; - bubble != sentinel; - bubble = bubble->next){ - Assert(bubble); - - Bubble *next = bubble->next; - Assert(bubble == next->prev); - if (next != sentinel){ - Assert(bubble->next > bubble); - Assert(bubble > bubble->prev); - - char *end_ptr = (char*)(bubble + 1) + bubble->size; - char *next_ptr = (char*)next; - Assert(end_ptr == next_ptr); - } - } -} - -#define BUBBLE_MIN_SIZE 1024 - -internal void -general_memory_attempt_split(Bubble *bubble, i32 wanted_size){ - i32 remaining_size = bubble->size - wanted_size; - if (remaining_size >= BUBBLE_MIN_SIZE){ - bubble->size = wanted_size; - Bubble *new_bubble = (Bubble*)((u8*)(bubble + 1) + wanted_size); - new_bubble->flags = (u32)MEM_BUBBLE_FLAG_INIT; - new_bubble->size = remaining_size - sizeof(Bubble); - insert_bubble(bubble, new_bubble); - } -} - -internal void* -general_memory_allocate(General_Memory *general, i32 size, u32 type = 0){ - void *result = 0; - for (Bubble *bubble = general->sentinel.next; - bubble != &general->sentinel; - bubble = bubble->next){ - if (!(bubble->flags & MEM_BUBBLE_USED)){ - if (bubble->size >= size){ - result = bubble + 1; - bubble->flags |= MEM_BUBBLE_USED; - bubble->type = type; - general_memory_attempt_split(bubble, size); - break; - } - } - } - return result; -} - -inline void -general_memory_do_merge(Bubble *left, Bubble *right){ - Assert(left->next == right); - Assert(right->prev == left); - left->size += sizeof(Bubble) + right->size; - remove_bubble(right); -} - -inline void -general_memory_attempt_merge(Bubble *left, Bubble *right){ - if (!(left->flags & MEM_BUBBLE_USED) && - !(right->flags & MEM_BUBBLE_USED)){ - general_memory_do_merge(left, right); - } -} - -internal void -general_memory_free(General_Memory *general, void *memory){ - Bubble *bubble = ((Bubble*)memory) - 1; - Assert((!FRED_INTERNAL) || (bubble->flags & MEM_BUBBLE_DEBUG_MASK) == MEM_BUBBLE_DEBUG); - bubble->flags &= ~MEM_BUBBLE_USED; - bubble->type = 0; - Bubble *prev, *next; - prev = bubble->prev; - next = bubble->next; - general_memory_attempt_merge(bubble, next); - general_memory_attempt_merge(prev, bubble); -} - -internal void* -general_memory_reallocate(General_Memory *general, void *old, i32 old_size, i32 size, u32 type = 0){ - void *result = old; - Bubble *bubble = ((Bubble*)old) - 1; - bubble->type = type; - Assert((!FRED_INTERNAL) || (bubble->flags & MEM_BUBBLE_DEBUG_MASK) == MEM_BUBBLE_DEBUG); - i32 additional_space = size - bubble->size; - if (additional_space > 0){ - Bubble *next = bubble->next; - if (!(next->flags & MEM_BUBBLE_USED) && - next->size + sizeof(Bubble) >= additional_space){ - general_memory_do_merge(bubble, next); - general_memory_attempt_split(bubble, size); - } - else{ - result = general_memory_allocate(general, size, type); - if (old_size) memcpy(result, old, old_size); - general_memory_free(general, old); - } - } - return result; -} - -inline void* -general_memory_reallocate_nocopy(General_Memory *general, void *old, i32 size, u32 type = 0){ - return general_memory_reallocate(general, old, 0, size, type); -} - -struct Temp_Memory{ - Partition *part; - i32 pos; -}; - -internal Temp_Memory -begin_temp_memory(Partition *data){ - Temp_Memory result; - result.part = data; - result.pos = data->pos; - return result; -} - -internal void -end_temp_memory(Temp_Memory temp){ - temp.part->pos = temp.pos; -} - -struct Mem_Options{ - Partition part; - General_Memory general; -}; - #if SOFTWARE_RENDER struct Render_Target{ void *pixel_data; @@ -289,17 +55,13 @@ struct Key_Event_Data{ }; struct Key_Input_Data{ - // NOTE(allen): keycodes here Key_Event_Data press[KEY_INPUT_BUFFER_SIZE]; Key_Event_Data hold[KEY_INPUT_BUFFER_SIZE]; i32 press_count; i32 hold_count; - - // NOTE(allen): - // true when the key is held down - // false when the key is not held down - bool8 control_keys[CONTROL_KEY_COUNT]; - bool8 caps_lock; + + b8 control_keys[CONTROL_KEY_COUNT]; + b8 caps_lock; }; struct Key_Summary{ @@ -310,7 +72,7 @@ struct Key_Summary{ struct Key_Single{ Key_Event_Data key; - bool8 *modifiers; + b8 *modifiers; }; inline Key_Single @@ -354,11 +116,13 @@ struct Clipboard_Contents{ struct Thread_Context; -internal bool32 -app_init(Thread_Context *thread, - Application_Memory *memory, - Key_Codes *lose_codes, - Clipboard_Contents clipboard); +#define App_Init_Sig(name) \ + b32 name(System_Functions *system, \ + Thread_Context *thread, Application_Memory *memory, \ + Key_Codes *loose_codes, Clipboard_Contents clipboard, \ + Config_API api) + +typedef App_Init_Sig(App_Init); enum Application_Mouse_Cursor{ APP_MOUSE_CURSOR_DEFAULT, @@ -375,13 +139,23 @@ struct Application_Step_Result{ bool32 redraw; }; -internal Application_Step_Result -app_step(Thread_Context *thread, - Key_Codes *codes, - Key_Input_Data *input, Mouse_State *state, - bool32 time_step, Render_Target *target, - Application_Memory *memory, - Clipboard_Contents clipboard, - bool32 first_step, bool32 force_redraw); +#define App_Step_Sig(name) Application_Step_Result \ + name(System_Functions *system, \ + Thread_Context *thread, Key_Codes *codes, \ + Key_Input_Data *input, Mouse_State *mouse, \ + b32 time_step, Render_Target *target, \ + Application_Memory *memory, \ + Clipboard_Contents clipboard, \ + b32 first_step, b32 force_redraw) + +typedef App_Step_Sig(App_Step); + +struct App_Functions{ + App_Init *init; + App_Step *step; +}; #endif + +// BOTTOM + diff --git a/4ed_app_target.cpp b/4ed_app_target.cpp new file mode 100644 index 00000000..6833922f --- /dev/null +++ b/4ed_app_target.cpp @@ -0,0 +1,93 @@ +/* + * Mr. 4th Dimention - Allen Webster + * + * 13.11.2014 + * + * Application layer build target + * + */ + +// TOP + +#ifdef FRED_NOT_PACKAGE + +#define FRED_INTERNAL 1 +#define FRED_SLOW 1 + +#define FRED_PRINT_DEBUG 1 +#define FRED_PRINT_DEBUG_FILE_LINE 0 +#define FRED_PROFILING 1 +#define FRED_PROFILING_OS 0 +#define FRED_FULL_ERRORS 0 + +#else + +#define FRED_SLOW 0 +#define FRED_INTERNAL 0 + +#define FRED_PRINT_DEBUG 0 +#define FRED_PRINT_DEBUG_FILE_LINE 0 +#define FRED_PROFILING 0 +#define FRED_PROFILING_OS 0 +#define FRED_FULL_ERRORS 0 + +#endif + +#define SOFTWARE_RENDER 0 + +#if FRED_INTERNAL == 0 +#undef FRED_PRINT_DEBUG +#define FRED_PRINT_DEBUG 0 +#undef FRED_PROFILING +#define FRED_PROFILING 0 +#undef FRED_PROFILING_OS +#define FRED_PROFILING_OS 0 +#endif + +#if FRED_PRINT_DEBUG == 0 +#undef FRED_PRINT_DEBUG_FILE_LINE +#define FRED_PRINT_DEBUG_FILE_LINE 0 +#undef FRED_PRINT_DEBUG_FILE_LINE +#define FRED_PROFILING_OS 0 +#endif + +#define FPS 30 +#define FRAME_TIME (1000000 / FPS) + +#define BUFFER_EXPERIMENT_SCALPEL 0 + +#include "4ed_meta.h" + +#include "4cpp_types.h" +#define FCPP_STRING_IMPLEMENTATION +#include "4cpp_string.h" + +#include "4ed_mem.cpp" + +#include "4ed_math.cpp" +#include "4coder_custom.h" +#include "4ed_system.h" +#include "4ed.h" +#include "4ed_rendering.h" + +#include +#include + +#include "4ed_internal.h" + +#define FCPP_LEXER_IMPLEMENTATION +#include "4cpp_lexer.h" + +#include "4ed_rendering.cpp" +#include "4ed_command.cpp" +#include "4ed_layout.cpp" +#include "4ed_style.cpp" +#include "4ed_file_view.cpp" +#include "4ed_color_view.cpp" +#include "4ed_interactive_view.cpp" +#include "4ed_menu_view.cpp" +#include "4ed_debug_view.cpp" +#include "4ed.cpp" + +// BOTTOM + diff --git a/4ed_color_view.cpp b/4ed_color_view.cpp index fcd46532..5f046d2e 100644 --- a/4ed_color_view.cpp +++ b/4ed_color_view.cpp @@ -1272,7 +1272,7 @@ do_style_preview(Library_UI *ui, Style *style, i32 toggle = -1){ } internal bool32 -do_main_file_box(UI_State *state, UI_Layout *layout, Hot_Directory *hot_directory, char *end = 0){ +do_main_file_box(System_Functions *system, UI_State *state, UI_Layout *layout, Hot_Directory *hot_directory, char *end = 0){ bool32 result = 0; Style *style = state->style; Font *font = style->font; @@ -1280,7 +1280,7 @@ do_main_file_box(UI_State *state, UI_Layout *layout, Hot_Directory *hot_director String *string = &hot_directory->string; if (state->input_stage){ - if (ui_do_file_field_input(state, hot_directory)){ + if (ui_do_file_field_input(system, state, hot_directory)){ result = 1; } } @@ -1300,14 +1300,14 @@ do_main_file_box(UI_State *state, UI_Layout *layout, Hot_Directory *hot_director } internal bool32 -do_main_string_box(UI_State *state, UI_Layout *layout, String *string){ +do_main_string_box(System_Functions *system, UI_State *state, UI_Layout *layout, String *string){ bool32 result = 0; Style *style = state->style; Font *font = style->font; i32_Rect box = layout_rect(layout, font->height + 2); if (state->input_stage){ - if (ui_do_line_field_input(state, string)){ + if (ui_do_line_field_input(system, state, string)){ result = 1; } } @@ -1398,13 +1398,14 @@ do_file_option(i32 id, UI_State *state, UI_Layout *layout, String filename, bool return result; } -internal bool32 -do_file_list_box(UI_State *state, UI_Layout *layout, Hot_Directory *hot_dir, bool32 has_filter, +internal b32 +do_file_list_box(System_Functions *system, + UI_State *state, UI_Layout *layout, Hot_Directory *hot_dir, bool32 has_filter, bool32 *new_dir, bool32 *selected, char *end){ bool32 result = 0; File_List *files = &hot_dir->file_list; - if (do_main_file_box(state, layout, hot_dir, end)){ + if (do_main_file_box(system, state, layout, hot_dir, end)){ *selected = 1; terminate_with_null(&hot_dir->string); } @@ -1473,12 +1474,12 @@ do_file_list_box(UI_State *state, UI_Layout *layout, Hot_Directory *hot_dir, boo return result; } -internal bool32 -do_live_file_list_box(UI_State *state, UI_Layout *layout, Working_Set *working_set, +internal b32 +do_live_file_list_box(System_Functions *system, UI_State *state, UI_Layout *layout, Working_Set *working_set, String *string, bool32 *selected){ bool32 result = 0; - if (do_main_string_box(state, layout, string)){ + if (do_main_string_box(system, state, layout, string)){ *selected = 1; terminate_with_null(string); } @@ -1518,7 +1519,8 @@ do_live_file_list_box(UI_State *state, UI_Layout *layout, Working_Set *working_s } internal i32 -step_draw_library(Color_View *color_view, i32_Rect rect, View_Message message, +step_draw_library(System_Functions *system, + Color_View *color_view, i32_Rect rect, View_Message message, Render_Target *target, Input_Summary *user_input){ i32 result = 0; @@ -1565,12 +1567,12 @@ step_draw_library(Color_View *color_view, i32_Rect rect, View_Message message, if (do_button(-3, &ui.state, &ui.layout, "Import", 2)){ color_view->mode = CV_MODE_IMPORT_FILE; hot_directory_clean_end(color_view->hot_directory); - hot_directory_reload(color_view->hot_directory, color_view->working_set); + hot_directory_reload(system, color_view->hot_directory, color_view->working_set); } if (do_button(-4, &ui.state, &ui.layout, "Export", 2)){ color_view->mode = CV_MODE_EXPORT; hot_directory_clean_end(color_view->hot_directory); - hot_directory_reload(color_view->hot_directory, color_view->working_set); + hot_directory_reload(system, color_view->hot_directory, color_view->working_set); memset(color_view->import_export_check, 0, sizeof(color_view->import_export_check)); } @@ -1603,13 +1605,14 @@ step_draw_library(Color_View *color_view, i32_Rect rect, View_Message message, } bool32 new_dir = 0; - if (do_file_list_box(&ui.state, &ui.layout, ui.hot_directory, color_view->p4c_only, + if (do_file_list_box(system, + &ui.state, &ui.layout, ui.hot_directory, color_view->p4c_only, &new_dir, &file_selected, 0)){ result = 1; } if (new_dir){ - hot_directory_reload(ui.hot_directory, ui.state.working_set); + hot_directory_reload(system, ui.hot_directory, ui.state.working_set); } if (file_selected){ memset(&color_view->inspecting_styles, 0, sizeof(Style_Library)); @@ -1617,7 +1620,8 @@ step_draw_library(Color_View *color_view, i32_Rect rect, View_Message message, Style *styles = color_view->inspecting_styles.styles; i32 count, max; max = ArrayCount(color_view->inspecting_styles.styles); - if (style_library_import((u8*)color_view->hot_directory->string.str, + if (style_library_import(system, + color_view->hot_directory->string.str, ui.fonts, styles, max, &count)){ color_view->mode = CV_MODE_IMPORT; } @@ -1645,19 +1649,20 @@ step_draw_library(Color_View *color_view, i32_Rect rect, View_Message message, } bool32 new_dir = 0; - if (do_file_list_box(&ui.state, &ui.layout, ui.hot_directory, 1, + if (do_file_list_box(system, + &ui.state, &ui.layout, ui.hot_directory, 1, &new_dir, &file_selected, ".p4c")){ result = 1; } if (new_dir){ - hot_directory_reload(ui.hot_directory, ui.state.working_set); + hot_directory_reload(system, + ui.hot_directory, ui.state.working_set); } if (file_selected){ i32 count = ui.styles->count; // TODO(allen): pass the transient memory in here - Style **styles = (Style**) - system_get_memory(sizeof(Style*)*count); + Style **styles = (Style**)system->get_memory(sizeof(Style*)*count); Style *style = ui.styles->styles; bool8 *export_check = color_view->import_export_check; i32 export_count = 0; @@ -1666,13 +1671,13 @@ step_draw_library(Color_View *color_view, i32_Rect rect, View_Message message, styles[export_count++] = style; } } - char *mem = (char*)system_get_memory(ui.hot_directory->string.size + 5); + char *mem = (char*)system->get_memory(ui.hot_directory->string.size + 5); String str = make_string(mem, 0, ui.hot_directory->string.size + 5); copy(&str, ui.hot_directory->string); append(&str, make_lit_string(".p4c")); - style_library_export((u8*)str.str, styles, export_count); - system_free_memory(mem); - system_free_memory(styles); + style_library_export(system, str.str, styles, export_count); + system->free_memory(mem); + system->free_memory(styles); color_view->mode = CV_MODE_LIBRARY; } }break; @@ -1757,11 +1762,11 @@ DO_VIEW_SIG(do_color_view){ switch (message){ case VMSG_STEP: { - result = step_draw_library(color_view, rect, message, target, user_input); + result = step_draw_library(system, color_view, rect, message, target, user_input); }break; case VMSG_DRAW: { - step_draw_library(color_view, rect, message, target, user_input); + step_draw_library(system, color_view, rect, message, target, user_input); }break; }break; diff --git a/4ed_command.cpp b/4ed_command.cpp index 1084f9ed..3c454f87 100644 --- a/4ed_command.cpp +++ b/4ed_command.cpp @@ -9,7 +9,8 @@ // TOP -typedef void (*Command_Function)(struct Command_Data *command, struct Command_Binding binding); +typedef void (*Command_Function)(System_Functions *system, + struct Command_Data *command, struct Command_Binding binding); struct Command_Binding{ Command_Function function; diff --git a/4ed_debug_view.cpp b/4ed_debug_view.cpp index c9ef5f26..4d30d2d0 100644 --- a/4ed_debug_view.cpp +++ b/4ed_debug_view.cpp @@ -12,8 +12,7 @@ enum Debug_Mode{ DBG_MEMORY, - DBG_OS_EVENTS, - DBG_PROFILE + DBG_OS_EVENTS }; struct Dbg_Past_Key{ @@ -94,10 +93,10 @@ draw_general_memory(Debug_View *view, i32_Rect rect, Render_Target *target, i32 } internal i32 -draw_system_memory(Debug_View *view, i32_Rect rect, Render_Target *target, i32 y){ +draw_system_memory(System_Functions *system, Debug_View *view, i32_Rect rect, Render_Target *target, i32 y){ Font *font = view->font; i32 y_advance = font->height; - Bubble *sentinel = INTERNAL_system_sentinel(); + Bubble *sentinel = system->internal_sentinel(); for (Bubble *bubble = sentinel->next; bubble != sentinel; @@ -124,10 +123,11 @@ draw_system_memory(Debug_View *view, i32_Rect rect, Render_Target *target, i32 y } internal void -draw_background_threads(Debug_View *view, i32_Rect rect, Render_Target *target){ +draw_background_threads(System_Functions *system, + Debug_View *view, i32_Rect rect, Render_Target *target){ i32 pending; bool8 running[4]; - INTERNAL_get_thread_states(BACKGROUND_THREADS, running, &pending); + system->internal_get_thread_states(BACKGROUND_THREADS, running, &pending); i32 box_size = 30; @@ -292,152 +292,8 @@ draw_os_events(Debug_View *view, i32_Rect rect, Render_Target *target, } internal i32 -draw_profile_frame(Render_Target *target, Profile_Frame *frame, - i32 x, i32 top, i32 bottom, i32 goal, Input_Summary *active_input){ - i32 result = -1; - - persist u32 colors[] = { - 0x80C06000, - 0x8000C060, - 0x806000C0, - 0x8060C000, - 0x800060C0, - 0x80C00060, - }; - - persist i32 color_max = ArrayCount(colors); - Mouse_Summary *mouse = &active_input->mouse; - - i32 count = frame->events.count; - Debug_Event *events = frame->events.e; - - i32 i; - for (i = 0; i < count && events[i].type == DBGEV_START; ++i){ - i64 start = events[i++].time; - i64 end = events[i].time; - - real32 rtop = unlerp(0, (real32)end, FRAME_TIME); - real32 rbot = unlerp(0, (real32)start, FRAME_TIME); - - rtop = lerp((real32)bottom, rtop, (real32)goal); - rbot = lerp((real32)bottom, rbot, (real32)goal); - - i32_Rect r = i32R(x, (i32)rtop, x+5, (i32)rbot); - draw_rectangle(target, r, colors[events[i].event_index % color_max]); - if (hit_check(mouse->mx, mouse->my, r)) result = (i - 1); - } - - { - real32 rtop = unlerp(0, (real32)frame->dbg_procing_end, FRAME_TIME); - real32 rbot = unlerp(0, (real32)frame->dbg_procing_start, FRAME_TIME); - - rtop = lerp((real32)bottom, rtop, (real32)goal); - rbot = lerp((real32)bottom, rbot, (real32)goal); - - i32_Rect r = i32R(x, (i32)rtop, x+5, (i32)rbot); - draw_rectangle(target, r, 0xFF808080); - } - - for (; i < count; ++i){ - - Assert(events[i].type == DBGEV_MOMENT); - - real32 ry = unlerp(0, (real32)events[i].time, FRAME_TIME); - ry = lerp((real32)bottom, ry, (real32)goal); - - i32_Rect r = i32R(x-1, (i32)ry, x+6, (i32)ry+1); - draw_rectangle(target, r, 0xFFFFFFFF); - if (hit_check(mouse->mx, mouse->my, r)) result = i; - } - - return result; -} - -internal void -draw_profile(Debug_View *view, i32_Rect rect, Render_Target *target, Input_Summary *active_input){ - i32 j = (INTERNAL_frame_index % 30); - - i32 event_index = -1; - i32 frame_index = -1; - - i32 target_time = (rect.y0 + rect.y1)/2; - - i32 x = rect.x0; - for (i32 i = 0; i < PAST_PROFILE_COUNT; ++i){ - Profile_Frame *frame = past_frames + j; - i32 s = draw_profile_frame(target, frame, x, rect.y0, rect.y1, target_time, active_input); - if (s != -1){ - event_index = s; - frame_index = j; - } - x += 10; - j = ((j+1) % PAST_PROFILE_COUNT); - } - - draw_rectangle(target, i32R(rect.x0, target_time, rect.x1, target_time + 1), 0xFFFFFFFF); - - char c[200]; - - if (frame_index != -1){ - Profile_Frame *frame = past_frames + frame_index; - Debug_Event *events = frame->events.e; - Debug_Event *event = events + event_index; - - Font *font = view->font; - - u32 color = 0xFFFFFFFF; - - i32 x, y; - x = rect.x0; - y = rect.y0; - - String s = make_fixed_width_string(c); - append(&s, event->name); - append(&s, ": "); - - Assert(event->type == DBGEV_START || event->type == DBGEV_MOMENT); - if (event->type == DBGEV_START){ - Debug_Event *next_event = event + 1; - Assert(next_event->type == DBGEV_END); - append_int_to_str((i32)(next_event->time - event->time), &s); - } - else{ - append_int_to_str((i32)event->time, &s); - } - terminate_with_null(&s); - draw_string(target, font, c, x, y, color); - y += font->height; - - if (frame->first_key != -1){ - Dbg_Past_Key *key = view->past_keys + frame->first_key; - Dbg_Past_Key *end_key = view->past_keys + ArrayCount(view->past_keys); - while (key->frame_index == frame->index){ - draw_key_event(view, target, key, - x, y, 0xFFFFFFFF, 0xFF808080); - y += font->height; - ++key; - if (key == end_key) key = view->past_keys; - } - } - - i32 count = frame->events.count; - for (i32 i = 0; i < count; ++i){ - if (events[i].type == DBGEV_START) ++i; - else{ - s = make_fixed_width_string(c); - append(&s, events[i].name); - append(&s, ": "); - append_int_to_str((i32)events[i].time, &s); - terminate_with_null(&s); - draw_string(target, font, c, x, y, color); - y += font->height; - } - } - } -} - -internal i32 -draw_debug_view(Debug_View *view, i32_Rect rect, Render_Target *target, +draw_debug_view(System_Functions *system, + Debug_View *view, i32_Rect rect, Render_Target *target, Input_Summary *active_input){ i32 result = 0; @@ -450,17 +306,12 @@ draw_debug_view(Debug_View *view, i32_Rect rect, Render_Target *target, y = draw_general_memory(view, rect, target, y); draw_rectangle(target, i32R(rect.x0, y, rect.x1, y+2), 0xFF222222); y += 2; - y = draw_system_memory(view, rect, target, y); + y = draw_system_memory(system, view, rect, target, y); }break; case DBG_OS_EVENTS: { draw_os_events(view, rect, target, active_input); }break; - case DBG_PROFILE: - { - draw_background_threads(view, rect, target); - draw_profile(view, rect, target, active_input); - }break; } return result; } @@ -472,7 +323,6 @@ step_debug_view(Debug_View *view, i32_Rect rect, Render_Target *target, bool8 *modifiers = active_input->keys.modifiers; for (i32 i = 0; i < active_input->keys.count; ++i){ - i32 this_index = view->past_key_pos; Dbg_Past_Key *past_key = view->past_keys + view->past_key_pos; ++view->past_key_pos; view->past_key_pos = view->past_key_pos % max_past; @@ -482,15 +332,14 @@ step_debug_view(Debug_View *view, i32_Rect rect, Render_Target *target, past_key->modifiers[1] = modifiers[1]; past_key->modifiers[2] = modifiers[2]; - if (INTERNAL_updating_profile){ - past_key->frame_index = INTERNAL_frame_index; - if (profile_frame.first_key == -1){ - profile_frame.first_key = this_index; - } - } - else{ - past_key->frame_index = -1; +#if 0 + i32 this_index = view->past_key_pos; + past_key->frame_index = INTERNAL_frame_index; + if (profile_frame.first_key == -1){ + profile_frame.first_key = this_index; } +#endif + past_key->frame_index = -1; if (view->past_key_count < max_past) ++view->past_key_count; } @@ -509,7 +358,7 @@ DO_VIEW_SIG(do_debug_view){ case VMSG_RESIZE: break; case VMSG_STYLE_CHANGE: break; case VMSG_STEP: step_debug_view(debug_view, rect, target, active_input); result = 1; break; - case VMSG_DRAW: draw_debug_view(debug_view, rect, target, active_input); break; + case VMSG_DRAW: draw_debug_view(system, debug_view, rect, target, active_input); break; case VMSG_FREE: break; } diff --git a/4ed_file_view.cpp b/4ed_file_view.cpp index 6672029e..bb06a979 100644 --- a/4ed_file_view.cpp +++ b/4ed_file_view.cpp @@ -270,13 +270,13 @@ struct Hot_Directory{ }; internal void -hot_directory_init(Hot_Directory *hot_directory, String base){ +hot_directory_init(System_Functions *system, Hot_Directory *hot_directory, String base){ hot_directory->string = base; hot_directory->string.str[255] = 0; - i32 dir_size = system_get_working_directory((u8*)hot_directory->string.str, - hot_directory->string.memory_size); + i32 dir_size = system->get_current_directory(hot_directory->string.str, + hot_directory->string.memory_size); if (dir_size <= 0){ - dir_size = system_get_easy_directory((u8*)hot_directory->string.str); + dir_size = system->get_easy_directory(hot_directory->string.str); } hot_directory->string.size = dir_size; append(&hot_directory->string, "\\"); @@ -323,22 +323,23 @@ hot_directory_fixup(Hot_Directory *hot_directory, Working_Set *working_set){ } inline void -hot_directory_set(Hot_Directory *hot_directory, String str, Working_Set *working_set){ +hot_directory_set(System_Functions *system, + Hot_Directory *hot_directory, String str, Working_Set *working_set){ bool32 success = copy_checked(&hot_directory->string, str); terminate_with_null(&hot_directory->string); if (success){ - system_free_file_list(hot_directory->file_list); - hot_directory->file_list = system_get_files(str); + system->free_file_list(hot_directory->file_list); + hot_directory->file_list = system->get_file_list(str); } hot_directory_fixup(hot_directory, working_set); } inline void -hot_directory_reload(Hot_Directory *hot_directory, Working_Set *working_set){ +hot_directory_reload(System_Functions *system, Hot_Directory *hot_directory, Working_Set *working_set){ if (hot_directory->file_list.block){ - system_free_file_list(hot_directory->file_list); + system->free_file_list(hot_directory->file_list); } - hot_directory->file_list = system_get_files(hot_directory->string); + hot_directory->file_list = system->get_file_list(hot_directory->string); hot_directory_fixup(hot_directory, working_set); } @@ -412,7 +413,8 @@ struct Single_Line_Mode{ }; internal Single_Line_Input_Step -app_single_line_input_core(Key_Codes *codes, Working_Set *working_set, +app_single_line_input_core(System_Functions *system, + Key_Codes *codes, Working_Set *working_set, Key_Single key, Single_Line_Mode mode){ Single_Line_Input_Step result = {}; @@ -431,7 +433,7 @@ app_single_line_input_core(Key_Codes *codes, Working_Set *working_set, if (char_is_slash(end_character)){ mode.string->size = reverse_seek_slash(*mode.string) + 1; mode.string->str[mode.string->size] = 0; - hot_directory_set(mode.hot_directory, *mode.string, working_set); + hot_directory_set(system, mode.hot_directory, *mode.string, working_set); } else{ mode.string->str[mode.string->size] = 0; @@ -462,7 +464,7 @@ app_single_line_input_core(Key_Codes *codes, Working_Set *working_set, if (match.filename.str){ if (match.is_folder){ set_last_folder(mode.string, match.filename); - hot_directory_set(mode.hot_directory, *mode.string, working_set); + hot_directory_set(system, mode.hot_directory, *mode.string, working_set); result.hit_newline = 0; } else{ @@ -490,7 +492,7 @@ app_single_line_input_core(Key_Codes *codes, Working_Set *working_set, mode.string->size++; mode.string->str[mode.string->size] = 0; if (mode.type == SINGLE_LINE_FILE && char_is_slash(new_character)){ - hot_directory_set(mode.hot_directory, *mode.string, working_set); + hot_directory_set(system, mode.hot_directory, *mode.string, working_set); } result.made_a_change = 1; } @@ -505,15 +507,17 @@ app_single_line_input_core(Key_Codes *codes, Working_Set *working_set, } inline Single_Line_Input_Step -app_single_line_input_step(Key_Codes *codes, Key_Single key, String *string){ +app_single_line_input_step(System_Functions *system, + Key_Codes *codes, Key_Single key, String *string){ Single_Line_Mode mode = {}; mode.type = SINGLE_LINE_STRING; mode.string = string; - return app_single_line_input_core(codes, 0, key, mode); + return app_single_line_input_core(system, codes, 0, key, mode); } inline Single_Line_Input_Step -app_single_file_input_step(Key_Codes *codes, Working_Set *working_set, Key_Single key, +app_single_file_input_step(System_Functions *system, + Key_Codes *codes, Working_Set *working_set, Key_Single key, String *string, Hot_Directory *hot_directory, bool32 fast_folder_select){ Single_Line_Mode mode = {}; @@ -521,11 +525,12 @@ app_single_file_input_step(Key_Codes *codes, Working_Set *working_set, Key_Singl mode.string = string; mode.hot_directory = hot_directory; mode.fast_folder_select = fast_folder_select; - return app_single_line_input_core(codes, working_set, key, mode); + return app_single_line_input_core(system, codes, working_set, key, mode); } inline Single_Line_Input_Step -app_single_number_input_step(Key_Codes *codes, Key_Single key, String *string){ +app_single_number_input_step(System_Functions *system, + Key_Codes *codes, Key_Single key, String *string){ Single_Line_Input_Step result = {}; Single_Line_Mode mode = {}; mode.type = SINGLE_LINE_STRING; @@ -533,7 +538,7 @@ app_single_number_input_step(Key_Codes *codes, Key_Single key, String *string){ char c = (char)key.key.character; if (c == 0 || c == '\n' || char_is_numeric(c)) - result = app_single_line_input_core(codes, 0, key, mode); + result = app_single_line_input_core(system, codes, 0, key, mode); return result; } @@ -930,7 +935,8 @@ ui_do_text_field_input(UI_State *state, String *str){ } internal bool32 -ui_do_file_field_input(UI_State *state, Hot_Directory *hot_dir){ +ui_do_file_field_input(System_Functions *system, + UI_State *state, Hot_Directory *hot_dir){ bool32 result = 0; Key_Summary *keys = state->keys; for (i32 key_i = 0; key_i < keys->count; ++key_i){ @@ -938,21 +944,22 @@ ui_do_file_field_input(UI_State *state, Hot_Directory *hot_dir){ String *str = &hot_dir->string; terminate_with_null(str); Single_Line_Input_Step step = - app_single_file_input_step(state->codes, state->working_set, key, str, hot_dir, 1); + app_single_file_input_step(system, state->codes, state->working_set, key, str, hot_dir, 1); if (step.hit_newline || step.hit_ctrl_newline) result = 1; } return result; } internal bool32 -ui_do_line_field_input(UI_State *state, String *string){ +ui_do_line_field_input(System_Functions *system, + UI_State *state, String *string){ bool32 result = 0; Key_Summary *keys = state->keys; for (i32 key_i = 0; key_i < keys->count; ++key_i){ Key_Single key = get_single_key(keys, key_i); terminate_with_null(string); Single_Line_Input_Step step = - app_single_line_input_step(state->codes, key, string); + app_single_line_input_step(system, state->codes, key, string); if (step.hit_newline || step.hit_ctrl_newline) result = 1; } return result; @@ -1136,8 +1143,8 @@ file_set_name(Editing_File *file, char *filename){ } inline void -file_synchronize_times(Editing_File *file, u8 *filename){ - Time_Stamp stamp = system_file_time_stamp(filename); +file_synchronize_times(System_Functions *system, Editing_File *file, char *filename){ + Time_Stamp stamp = system->file_time_stamp(filename); if (stamp.success){ file->last_4ed_write_time = stamp.time; file->last_4ed_edit_time = stamp.time; @@ -1146,7 +1153,7 @@ file_synchronize_times(Editing_File *file, u8 *filename){ } internal b32 -file_save(Partition *part, Editing_File *file, char *filename){ +file_save(System_Functions *system, Partition *part, Editing_File *file, char *filename){ b32 result = 0; #if BUFFER_EXPERIMENT_SCALPEL <= 3 Temp_Memory temp = begin_temp_memory(part); @@ -1154,25 +1161,26 @@ file_save(Partition *part, Editing_File *file, char *filename){ if (file->dos_write_mode){ char *data = push_array(part, char, max); i32 size = buffer_convert_out(&file->buffer, data, max); - result = system_save_file((u8*)filename, data, size); + result = system->save_file(filename, data, size); } else{ char *data = push_array(part, char, max); i32 size = buffer_size(&file->buffer); Assert(size <= max); buffer_stringify(&file->buffer, 0, size, data); - result = system_save_file((u8*)filename, data, size); + result = system->save_file(filename, data, size); } end_temp_memory(temp); - file_synchronize_times(file, (u8*)filename); + file_synchronize_times(system, file, filename); #endif return result; } -inline bool32 -file_save_and_set_names(Partition *part, Editing_File *file, char *filename){ - bool32 result = 0; - if (file_save(part, file, filename)){ +inline b32 +file_save_and_set_names(System_Functions *system, + Partition *part, Editing_File *file, char *filename){ + b32 result = 0; + if (file_save(system, part, file, filename)){ result = 1; file_set_name(file, filename); } @@ -1222,7 +1230,8 @@ file_grow_starts_as_needed(General_Memory *general, Buffer_Type *buffer, i32 add } internal void -file_measure_starts_widths(General_Memory *general, Buffer_Type *buffer, Font *font){ +file_measure_starts_widths(System_Functions *system, + General_Memory *general, Buffer_Type *buffer, Font *font){ ProfileMomentFunction(); if (!buffer->line_starts){ i32 max = buffer->line_max = Kbytes(1); @@ -1304,7 +1313,8 @@ file_measure_starts(General_Memory *general, Buffer_Type *buffer){ #endif internal void -file_remeasure_starts(General_Memory *general, Buffer_Type *buffer, +file_remeasure_starts(System_Functions *system, + General_Memory *general, Buffer_Type *buffer, i32 line_start, i32 line_end, i32 line_shift, i32 character_shift){ #if BUFFER_EXPERIMENT_SCALPEL <= 3 @@ -1362,7 +1372,8 @@ file_measure_widths(General_Memory *general, Buffer_Type *buffer, Font *font){ #endif internal void -file_remeasure_widths(General_Memory *general, Buffer_Type *buffer, Font *font, +file_remeasure_widths(System_Functions *system, + General_Memory *general, Buffer_Type *buffer, Font *font, i32 line_start, i32 line_end, i32 line_shift){ #if BUFFER_EXPERIMENT_SCALPEL <= 3 ProfileMomentFunction(); @@ -1406,7 +1417,8 @@ view_compute_lowest_line(File_View *view){ } internal void -view_measure_wraps(General_Memory *general, File_View *view){ +view_measure_wraps(System_Functions *system, + General_Memory *general, File_View *view){ #if BUFFER_EXPERIMENT_SCALPEL <= 3 ProfileMomentFunction(); Buffer_Type *buffer; @@ -1443,7 +1455,8 @@ alloc_for_buffer(void *context, int *size){ } internal void -file_create_from_string(Mem_Options *mem, Editing_File *file, u8 *filename, Font *font, String val, b32 super_locked = 0){ +file_create_from_string(System_Functions *system, + Mem_Options *mem, Editing_File *file, char *filename, Font *font, String val, b32 super_locked = 0){ *file = {}; General_Memory *general = &mem->general; #if BUFFER_EXPERIMENT_SCALPEL <= 3 @@ -1460,6 +1473,7 @@ file_create_from_string(Mem_Options *mem, Editing_File *file, u8 *filename, Font i32 scratch_size = partition_remaining(part); Assert(scratch_size > 0); i32 init_success = buffer_end_init(&init, part->base + part->pos, scratch_size); + AllowLocal(init_success); Assert(init_success); #endif @@ -1469,9 +1483,9 @@ file_create_from_string(Mem_Options *mem, Editing_File *file, u8 *filename, Font file->base_map_id = mapid_file; file->font = font; - file_synchronize_times(file, filename); + file_synchronize_times(system, file, filename); - file_measure_starts_widths(general, &file->buffer, font); + file_measure_starts_widths(system, general, &file->buffer, font); file->super_locked = super_locked; if (!super_locked){ @@ -1503,33 +1517,33 @@ file_create_from_string(Mem_Options *mem, Editing_File *file, u8 *filename, Font } internal bool32 -file_create(Mem_Options *mem, Editing_File *file, u8 *filename, Font *font){ +file_create(System_Functions *system, Mem_Options *mem, Editing_File *file, char *filename, Font *font){ bool32 result = 0; - File_Data raw_file = system_load_file(filename); + File_Data raw_file = system->load_file(filename); if (raw_file.data){ result = 1; String val = make_string((char*)raw_file.data, raw_file.size); - file_create_from_string(mem, file, filename, font, val); - system_free_file(raw_file); + file_create_from_string(system, mem, file, filename, font, val); + system->free_file(raw_file); } return result; } internal b32 -file_create_empty(Mem_Options *mem, Editing_File *file, u8 *filename, Font *font){ +file_create_empty(System_Functions *system, Mem_Options *mem, Editing_File *file, char *filename, Font *font){ b32 result = 1; String empty_str = {}; - file_create_from_string(mem, file, filename, font, empty_str); + file_create_from_string(system, mem, file, filename, font, empty_str); return result; } internal b32 -file_create_super_locked(Mem_Options *mem, Editing_File *file, u8 *filename, Font *font){ +file_create_super_locked(System_Functions *system, Mem_Options *mem, Editing_File *file, char *filename, Font *font){ b32 result = 1; String empty_str = {}; - file_create_from_string(mem, file, filename, font, empty_str, 1); + file_create_from_string(system, mem, file, filename, font, empty_str, 1); return result; } @@ -1559,9 +1573,9 @@ working_set_get_available_file(Working_Set *working_set){ } internal void -file_close(General_Memory *general, Editing_File *file){ +file_close(System_Functions *system, General_Memory *general, Editing_File *file){ if (file->still_lexing){ - system_cancel_job(BACKGROUND_THREADS, file->lex_job); + system->cancel_job(BACKGROUND_THREADS, file->lex_job); } if (file->token_stack.tokens){ general_memory_free(general, file->token_stack.tokens); @@ -1605,7 +1619,7 @@ struct Shift_Information{ #if BUFFER_EXPERIMENT_SCALPEL <= 0 internal -JOB_CALLBACK(job_full_lex){ +Job_Callback(job_full_lex){ Editing_File *file = (Editing_File*)data[0]; General_Memory *general = (General_Memory*)data[1]; @@ -1621,14 +1635,14 @@ JOB_CALLBACK(job_full_lex){ Cpp_Lex_Data status; status = cpp_lex_file_nonalloc(cpp_file, &tokens); while (!status.complete){ - system_grow_thread_memory(memory); + system->grow_thread_memory(memory); tokens.tokens = (Cpp_Token*)memory->data; tokens.max_count = memory->size / sizeof(Cpp_Token); status = cpp_lex_file_nonalloc(cpp_file, &tokens, status); } i32 new_max = LargeRoundUp(tokens.count, Kbytes(1)); - system_aquire_lock(FRAME_LOCK); + system->acquire_lock(FRAME_LOCK); if (file->token_stack.tokens){ file->token_stack.tokens = (Cpp_Token*) general_memory_reallocate_nocopy(general, file->token_stack.tokens, new_max*sizeof(Cpp_Token), BUBBLE_TOKENS); @@ -1637,7 +1651,7 @@ JOB_CALLBACK(job_full_lex){ file->token_stack.tokens = (Cpp_Token*) general_memory_allocate(general, new_max*sizeof(Cpp_Token), BUBBLE_TOKENS); } - system_release_lock(FRAME_LOCK); + system->release_lock(FRAME_LOCK); i32 copy_amount = Kbytes(8); i32 uncoppied = tokens.count*sizeof(Cpp_Token); @@ -1647,9 +1661,9 @@ JOB_CALLBACK(job_full_lex){ u8 *src = (u8*)tokens.tokens; while (uncoppied > 0){ - system_aquire_lock(FRAME_LOCK); + system->acquire_lock(FRAME_LOCK); memcpy(dest, src, copy_amount); - system_release_lock(FRAME_LOCK); + system->release_lock(FRAME_LOCK); dest += copy_amount; src += copy_amount; uncoppied -= copy_amount; @@ -1658,7 +1672,7 @@ JOB_CALLBACK(job_full_lex){ file->token_stack.count = tokens.count; file->token_stack.max_count = new_max; - system_force_redraw(); + system->force_redraw(); // NOTE(allen): These are outside the locked section because I don't // think getting these out of order will cause critical bugs, and I @@ -1669,9 +1683,10 @@ JOB_CALLBACK(job_full_lex){ #endif internal void -file_kill_tokens(General_Memory *general, Editing_File *file){ +file_kill_tokens(System_Functions *system, + General_Memory *general, Editing_File *file){ if (file->still_lexing){ - system_cancel_job(BACKGROUND_THREADS, file->lex_job); + system->cancel_job(BACKGROUND_THREADS, file->lex_job); } if (file->token_stack.tokens){ general_memory_free(general, file->token_stack.tokens); @@ -1683,7 +1698,8 @@ file_kill_tokens(General_Memory *general, Editing_File *file){ #if BUFFER_EXPERIMENT_SCALPEL <= 0 internal void -file_first_lex_parallel(General_Memory *general, Editing_File *file){ +file_first_lex_parallel(System_Functions *system, + General_Memory *general, Editing_File *file){ Assert(file->token_stack.tokens == 0); file->tokens_complete = 0; @@ -1695,20 +1711,21 @@ file_first_lex_parallel(General_Memory *general, Editing_File *file){ job.data[0] = file; job.data[1] = general; job.memory_request = Kbytes(64); - file->lex_job = system_post_job(BACKGROUND_THREADS, job); + file->lex_job = system->post_job(BACKGROUND_THREADS, job); } internal void -file_relex_parallel(Mem_Options *mem, Editing_File *file, +file_relex_parallel(System_Functions *system, + Mem_Options *mem, Editing_File *file, i32 start_i, i32 end_i, i32 amount){ General_Memory *general = &mem->general; Partition *part = &mem->part; if (file->token_stack.tokens == 0){ - file_first_lex_parallel(general, file); + file_first_lex_parallel(system, general, file); return; } - bool32 inline_lex = !file->still_lexing; + b32 inline_lex = !file->still_lexing; if (inline_lex){ Cpp_File cpp_file; cpp_file.data = file->buffer.data; @@ -1779,7 +1796,7 @@ file_relex_parallel(Mem_Options *mem, Editing_File *file, job.data[0] = file; job.data[1] = general; job.memory_request = Kbytes(64); - file->lex_job = system_post_job(BACKGROUND_THREADS, job); + file->lex_job = system->post_job(BACKGROUND_THREADS, job); } } #endif @@ -2182,7 +2199,8 @@ view_get_cursor_y(File_View *view){ } internal void -view_set_file(File_View *view, Editing_File *file, Style *style, +view_set_file(System_Functions *system, + File_View *view, Editing_File *file, Style *style, Custom_Command_Function *open_hook, void *cmd_context, Application_Links app){ Panel *panel = view->view_base.panel; view->file = file; @@ -2194,7 +2212,7 @@ view_set_file(File_View *view, Editing_File *file, Style *style, view->font_advance = font->advance; view->font_height = font->height; - view_measure_wraps(general, view); + view_measure_wraps(system, general, view); view->cursor = {}; view->cursor = view_compute_cursor_from_pos(view, file->cursor_pos); @@ -2526,20 +2544,22 @@ debug_step_match(Edit_Step a, Edit_Step b){ } inline void -file_pre_edit_maintenance(Editing_File *file){ +file_pre_edit_maintenance(System_Functions *system, + Editing_File *file){ if (file->still_lexing) - system_cancel_job(BACKGROUND_THREADS, file->lex_job); - file->last_4ed_edit_time = system_get_now(); + system->cancel_job(BACKGROUND_THREADS, file->lex_job); + file->last_4ed_edit_time = system->time_stamp_now(); } internal void -file_do_single_edit(Mem_Options *mem, Editing_File *file, +file_do_single_edit(System_Functions *system, + Mem_Options *mem, Editing_File *file, Editing_Layout *layout, Edit_Spec spec, History_Mode history_mode){ ProfileMomentFunction(); // NOTE(allen): fixing stuff beforewards???? file_update_history_before_edit(mem, file, spec.step, spec.str, history_mode); - file_pre_edit_maintenance(file); + file_pre_edit_maintenance(system, file); // NOTE(allen): actual text replacement #if BUFFER_EXPERIMENT_SCALPEL <= 3 @@ -2580,15 +2600,15 @@ file_do_single_edit(Mem_Options *mem, Editing_File *file, i32 new_line_count = buffer_count_newlines(&file->buffer, start, start+str_len); i32 line_shift = new_line_count - replaced_line_count; - file_remeasure_starts(general, &file->buffer, line_start, line_end, line_shift, shift_amount); - file_remeasure_widths(general, &file->buffer, file->font, line_start, line_end, line_shift); + file_remeasure_starts(system, general, &file->buffer, line_start, line_end, line_shift, shift_amount); + file_remeasure_widths(system, general, &file->buffer, file->font, line_start, line_end, line_shift); i32 panel_count = layout->panel_count; Panel *current_panel = layout->panels; for (i32 i = 0; i < panel_count; ++i, ++current_panel){ File_View *current_view = view_to_file_view(current_panel->view); if (current_view && current_view->file == file){ - view_measure_wraps(general, current_view); + view_measure_wraps(system, general, current_view); } } #endif @@ -2596,7 +2616,7 @@ file_do_single_edit(Mem_Options *mem, Editing_File *file, #if BUFFER_EXPERIMENT_SCALPEL <= 0 // NOTE(allen): fixing stuff afterwards if (file->tokens_exist) - file_relex_parallel(mem, file, start, end, shift_amount); + file_relex_parallel(system, mem, file, start, end, shift_amount); #endif #if BUFFER_EXPERIMENT_SCALPEL <= 3 @@ -2609,7 +2629,7 @@ file_do_single_edit(Mem_Options *mem, Editing_File *file, for (i32 i = 0; i < panel_count; ++i, ++current_panel){ File_View *current_view = view_to_file_view(current_panel->view); if (current_view && current_view->file == file){ - view_measure_wraps(general, current_view); + view_measure_wraps(system, general, current_view); write_cursor_with_index(cursors, &cursor_count, current_view->cursor.pos); write_cursor_with_index(cursors, &cursor_count, current_view->mark); } @@ -2638,7 +2658,8 @@ file_do_single_edit(Mem_Options *mem, Editing_File *file, } internal void -view_do_white_batch_edit(Mem_Options *mem, File_View *view, Editing_File *file, +view_do_white_batch_edit(System_Functions *system, + Mem_Options *mem, File_View *view, Editing_File *file, Editing_Layout *layout, Edit_Spec spec, History_Mode history_mode){ if (view->locked) return; #if BUFFER_EXPERIMENT_SCALPEL <= 3 @@ -2648,7 +2669,7 @@ view_do_white_batch_edit(Mem_Options *mem, File_View *view, Editing_File *file, // NOTE(allen): fixing stuff beforewards???? Assert(spec.str == 0); file_update_history_before_edit(mem, file, spec.step, 0, history_mode); - file_pre_edit_maintenance(file); + file_pre_edit_maintenance(system, file); // NOTE(allen): actual text replacement General_Memory *general = &mem->general; @@ -2720,7 +2741,7 @@ view_do_white_batch_edit(Mem_Options *mem, File_View *view, Editing_File *file, for (i32 i = 0; i < panel_count; ++i, ++current_panel){ File_View *current_view = view_to_file_view(current_panel->view); if (current_view && current_view->file == file){ - view_measure_wraps(general, current_view); + view_measure_wraps(system, general, current_view); write_cursor_with_index(cursors, &cursor_count, current_view->cursor.pos); write_cursor_with_index(cursors, &cursor_count, current_view->mark); } @@ -2748,7 +2769,8 @@ view_do_white_batch_edit(Mem_Options *mem, File_View *view, Editing_File *file, } inline void -view_replace_range(Mem_Options *mem, File_View *view, Editing_Layout *layout, +view_replace_range(System_Functions *system, + Mem_Options *mem, File_View *view, Editing_Layout *layout, i32 start, i32 end, u8 *str, i32 len, i32 next_cursor){ if (view->locked) return; Edit_Spec spec = {}; @@ -2759,7 +2781,7 @@ view_replace_range(Mem_Options *mem, File_View *view, Editing_Layout *layout, spec.step.pre_pos = view->cursor.pos; spec.step.post_pos = next_cursor; spec.str = str; - file_do_single_edit(mem, view->file, layout, spec, hist_normal); + file_do_single_edit(system, mem, view->file, layout, spec, hist_normal); } inline void @@ -2772,7 +2794,8 @@ view_post_paste_effect(File_View *view, i32 ticks, i32 start, i32 size, u32 colo } internal void -view_undo_redo(Mem_Options *mem, Editing_Layout *layout, File_View *view, Editing_File *file, +view_undo_redo(System_Functions *system, + Mem_Options *mem, Editing_Layout *layout, File_View *view, Editing_File *file, Edit_Stack *stack, Edit_Type expected_type){ if (view->locked) return; if (file && stack->edit_count > 0){ @@ -2787,7 +2810,7 @@ view_undo_redo(Mem_Options *mem, Editing_Layout *layout, File_View *view, Editin spec.step.edit.str_start = 0; spec.str = stack->strings + step.edit.str_start; - file_do_single_edit(mem, file, layout, spec, hist_normal); + file_do_single_edit(system, mem, file, layout, spec, hist_normal); if (expected_type == ED_UNDO) view_cursor_move(view, step.pre_pos); else view_cursor_move(view, step.post_pos); @@ -2798,21 +2821,21 @@ view_undo_redo(Mem_Options *mem, Editing_Layout *layout, File_View *view, Editin } else{ TentativeAssert(spec.step.special_type == 1); - view_do_white_batch_edit(mem, view, file, layout, spec, hist_normal); + view_do_white_batch_edit(system, mem, view, file, layout, spec, hist_normal); } } } inline void -view_undo(Mem_Options *mem, Editing_Layout *layout, File_View *view){ +view_undo(System_Functions *system, Mem_Options *mem, Editing_Layout *layout, File_View *view){ Editing_File *file = view->file; - view_undo_redo(mem, layout, view, file, &file->undo.undo, ED_UNDO); + view_undo_redo(system, mem, layout, view, file, &file->undo.undo, ED_UNDO); } inline void -view_redo(Mem_Options *mem, Editing_Layout *layout, File_View *view){ +view_redo(System_Functions *system, Mem_Options *mem, Editing_Layout *layout, File_View *view){ Editing_File *file = view->file; - view_undo_redo(mem, layout, view, file, &file->undo.redo, ED_REDO); + view_undo_redo(system, mem, layout, view, file, &file->undo.redo, ED_REDO); } inline u8* @@ -2822,7 +2845,7 @@ write_data(u8 *ptr, void *x, i32 size){ } internal void -file_dump_history(Mem_Options *mem, Editing_File *file, char *filename){ +file_dump_history(System_Functions *system, Mem_Options *mem, Editing_File *file, char *filename){ if (!file->undo.undo.edits) return; i32 size = 0; @@ -2871,18 +2894,18 @@ file_dump_history(Mem_Options *mem, Editing_File *file, char *filename){ curs = write_data(curs, file->undo.children.strings, file->undo.children.size); Assert((i32)(curs - data) == size); - system_save_file((u8*)filename, data, size); + system->save_file(filename, data, size); } } internal void -view_history_step(Mem_Options *mem, Editing_Layout *layout, File_View *view, History_Mode history_mode){ +view_history_step(System_Functions *system, Mem_Options *mem, Editing_Layout *layout, File_View *view, History_Mode history_mode){ if (view->locked) return; Assert(history_mode != hist_normal); Editing_File *file = view->file; - bool32 do_history_step = 0; + b32 do_history_step = 0; Edit_Step step = {}; if (history_mode == hist_backward){ if (file->undo.edit_history_cursor > 0){ @@ -2908,7 +2931,7 @@ view_history_step(Mem_Options *mem, Editing_Layout *layout, File_View *view, His spec.step.edit.str_start = 0; spec.str = file->undo.history.strings + step.edit.str_start; - file_do_single_edit(mem, file, layout, spec, history_mode); + file_do_single_edit(system, mem, file, layout, spec, history_mode); switch (spec.step.type){ case ED_NORMAL: @@ -2925,7 +2948,7 @@ view_history_step(Mem_Options *mem, Editing_Layout *layout, File_View *view, His } else{ TentativeAssert(spec.step.special_type == 1); - view_do_white_batch_edit(mem, view, file, layout, spec, history_mode); + view_do_white_batch_edit(system, mem, view, file, layout, spec, history_mode); } } } @@ -3063,13 +3086,13 @@ working_set_lookup_file(Working_Set *working_set, String string){ } internal void -clipboard_copy(General_Memory *general, Working_Set *working, Range range, Editing_File *file){ +clipboard_copy(System_Functions *system, General_Memory *general, Working_Set *working, Range range, Editing_File *file){ #if BUFFER_EXPERIMENT_SCALPEL <= 3 i32 size = range.end - range.start; String *dest = working_set_next_clipboard_string(general, working, size); buffer_stringify(&file->buffer, range.start, range.end, dest->str); dest->size = size; - system_post_clipboard(*dest); + system->post_clipboard(*dest); #endif } @@ -3111,7 +3134,7 @@ file_compute_whitespace_edit(Mem_Options *mem, Editing_File *file, i32 cursor_po } internal void -view_clean_whitespace(Mem_Options *mem, File_View *view, Editing_Layout *layout){ +view_clean_whitespace(System_Functions *system, Mem_Options *mem, File_View *view, Editing_Layout *layout){ #if BUFFER_EXPERIMENT_SCALPEL <= 3 Editing_File *file = view->file; Assert(file && !file->is_dummy); @@ -3162,7 +3185,7 @@ view_clean_whitespace(Mem_Options *mem, File_View *view, Editing_Layout *layout) file_compute_whitespace_edit(mem, file, view->cursor.pos, edits, str_base, str_size, inverse_array, inv_str, part->max - part->pos, edit_count); - view_do_white_batch_edit(mem, view, file, layout, spec, hist_normal); + view_do_white_batch_edit(system, mem, view, file, layout, spec, hist_normal); } end_temp_memory(temp); @@ -3170,7 +3193,8 @@ view_clean_whitespace(Mem_Options *mem, File_View *view, Editing_Layout *layout) } internal void -view_auto_tab_tokens(Mem_Options *mem, File_View *view, Editing_Layout *layout, +view_auto_tab_tokens(System_Functions *system, + Mem_Options *mem, File_View *view, Editing_Layout *layout, i32 start, i32 end, b32 empty_blank_lines){ #if BUFFER_EXPERIMENT_SCALPEL <= 0 Editing_File *file = view->file; @@ -3351,7 +3375,7 @@ view_auto_tab_tokens(Mem_Options *mem, File_View *view, Editing_Layout *layout, file_compute_whitespace_edit(mem, file, view->cursor.pos, edits, str_base, str_size, inverse_array, inv_str, part->max - part->pos, edit_count); - view_do_white_batch_edit(mem, view, file, layout, spec, hist_normal); + view_do_white_batch_edit(system, mem, view, file, layout, spec, hist_normal); } end_temp_memory(temp); @@ -3493,10 +3517,10 @@ view_compute_max_target_y(File_View *view){ } internal void -remeasure_file_view(View *view_, i32_Rect rect){ +remeasure_file_view(System_Functions *system, View *view_, i32_Rect rect){ File_View *view = (File_View*)view_; Relative_Scrolling relative = view_get_relative_scrolling(view); - view_measure_wraps(&view->view_base.mem->general, view); + view_measure_wraps(system, &view->view_base.mem->general, view); view_cursor_move(view, view->cursor.pos); view->preferred_x = view_get_cursor_x(view); view_set_relative_scrolling(view, relative); @@ -3696,7 +3720,7 @@ do_undo_slider(Widget_ID wid, UI_State *state, UI_Layout *layout, i32 max, i32 v } internal i32 -step_file_view(Thread_Context *thread, View *view_, i32_Rect rect, +step_file_view(System_Functions *system, Thread_Context *thread, View *view_, i32_Rect rect, bool32 is_active, Input_Summary *user_input){ view_->mouse_cursor_type = APP_MOUSE_CURSOR_IBEAM; i32 result = 0; @@ -3829,11 +3853,11 @@ step_file_view(Thread_Context *thread, View *view_, i32_Rect rect, view->rewind_amount = 0; for (i32 i = 0; i < scrub_max && new_count < undo_count; ++i){ - view_undo(view_->mem, view->layout, view); + view_undo(system, view_->mem, view->layout, view); --undo_count; } for (i32 i = 0; i < scrub_max && new_count > undo_count; ++i){ - view_redo(view_->mem, view->layout, view); + view_redo(system, view_->mem, view->layout, view); ++undo_count; } } @@ -3857,10 +3881,10 @@ step_file_view(Thread_Context *thread, View *view_, i32_Rect rect, i32 count = file->undo.edit_history_cursor; if (do_undo_slider(wid, &state, &layout, mid, count, &file->undo, &new_count)){ for (i32 i = 0; i < scrub_max && new_count < count; ++i){ - view_history_step(view_->mem, view->layout, view, hist_backward); + view_history_step(system, view_->mem, view->layout, view, hist_backward); } for (i32 i = 0; i < scrub_max && new_count > count; ++i){ - view_history_step(view_->mem, view->layout, view, hist_forward); + view_history_step(system, view_->mem, view->layout, view, hist_forward); } } } @@ -3882,11 +3906,11 @@ step_file_view(Thread_Context *thread, View *view_, i32_Rect rect, i32 rewind_max = view->rewind_max; view->rewind_amount += view->rewind_speed; for (i32 i = 0; view->rewind_amount <= -1.f; ++i, view->rewind_amount += 1.f){ - if (i < rewind_max) view_undo(view_->mem, view->layout, view); + if (i < rewind_max) view_undo(system, view_->mem, view->layout, view); } for (i32 i = 0; view->rewind_amount >= 1.f; ++i, view->rewind_amount -= 1.f){ - if (i < rewind_max) view_redo(view_->mem, view->layout, view); + if (i < rewind_max) view_redo(system, view_->mem, view->layout, view); } if (view->rewind_speed < 0.f && undo_count == 0){ @@ -4177,7 +4201,8 @@ draw_file_view(Thread_Context *thread, View *view_, i32_Rect rect, bool32 is_act } internal void -kill_file(General_Memory *general, Editing_File *file, Live_Views *live_set, Editing_Layout *layout){ +kill_file(System_Functions *system, + General_Memory *general, Editing_File *file, Live_Views *live_set, Editing_Layout *layout){ i32 panel_count = layout->panel_count; Panel *panels = layout->panels, *panel; panel = panels; @@ -4189,21 +4214,21 @@ kill_file(General_Memory *general, Editing_File *file, Live_Views *live_set, Edi if (view->is_minor) to_kill = view->major; File_View *fview = view_to_file_view(to_kill); if (fview && fview->file == file){ - live_set_free_view(live_set, &fview->view_base); + live_set_free_view(system, live_set, &fview->view_base); if (to_kill == view) panel->view = 0; else view->major = 0; } } ++panel; } - file_close(general, file); + file_close(system, general, file); file_get_dummy(file); } internal void -command_search(Command_Data*,Command_Binding); +command_search(System_Functions*,Command_Data*,Command_Binding); internal void -command_rsearch(Command_Data*,Command_Binding); +command_rsearch(System_Functions*,Command_Data*,Command_Binding); internal HANDLE_COMMAND_SIG(handle_command_file_view){ @@ -4216,7 +4241,7 @@ HANDLE_COMMAND_SIG(handle_command_file_view){ case FWIDG_TIMELINES: { file_view->next_mode = {}; - if (binding.function) binding.function(command, binding); + if (binding.function) binding.function(system, command, binding); file_view->mode = file_view->next_mode; if (key.key.keycode == codes->esc) @@ -4228,7 +4253,7 @@ HANDLE_COMMAND_SIG(handle_command_file_view){ #if BUFFER_EXPERIMENT_SCALPEL <= 3 String *string = &file_view->isearch.str; Single_Line_Input_Step result = - app_single_line_input_step(codes, key, string); + app_single_line_input_step(system, codes, key, string); if (result.made_a_change || binding.function == command_search || @@ -4309,7 +4334,7 @@ HANDLE_COMMAND_SIG(handle_command_file_view){ { String *string = &file_view->gotoline.str; Single_Line_Input_Step result = - app_single_number_input_step(codes, key, string); + app_single_number_input_step(system, codes, key, string); if (result.hit_newline || result.hit_ctrl_newline){ i32 line_number = str_to_int(*string); @@ -4344,7 +4369,7 @@ DO_VIEW_SIG(do_file_view){ case VMSG_RESIZE: case VMSG_STYLE_CHANGE: { - remeasure_file_view(view, rect); + remeasure_file_view(system, view, rect); }break; case VMSG_DRAW: { @@ -4352,7 +4377,7 @@ DO_VIEW_SIG(do_file_view){ }break; case VMSG_STEP: { - result = step_file_view(thread, view, rect, (view == active), user_input); + result = step_file_view(system, thread, view, rect, (view == active), user_input); }break; case VMSG_FREE: { diff --git a/4ed_interactive_view.cpp b/4ed_interactive_view.cpp index cb1068ec..e15d0a58 100644 --- a/4ed_interactive_view.cpp +++ b/4ed_interactive_view.cpp @@ -97,7 +97,8 @@ interactive_view_complete(Interactive_View *view){ } internal i32 -step_draw_int_view(Interactive_View *view, Render_Target *target, i32_Rect rect, +step_draw_int_view(System_Functions *system, + Interactive_View *view, Render_Target *target, i32_Rect rect, Input_Summary *user_input, bool32 input_stage){ i32 result = 0; @@ -115,17 +116,19 @@ step_draw_int_view(Interactive_View *view, Render_Target *target, i32_Rect rect, switch (view->interaction){ case INTV_SYS_FILE_LIST: - if (do_file_list_box(&state, &layout, view->hot_directory, 0, + if (do_file_list_box(system, + &state, &layout, view->hot_directory, 0, &new_dir, &complete, 0)){ result = 1; } if (new_dir){ - hot_directory_reload(view->hot_directory, view->working_set); + hot_directory_reload(system, + view->hot_directory, view->working_set); } break; case INTV_LIVE_FILE_LIST: - if (do_live_file_list_box(&state, &layout, view->working_set, &view->dest, &complete)){ + if (do_live_file_list_box(system, &state, &layout, view->working_set, &view->dest, &complete)){ result = 1; } break; @@ -191,7 +194,7 @@ DO_VIEW_SIG(do_interactive_view){ Interactive_View *int_view = (Interactive_View*)view; switch (message){ case VMSG_STEP: case VMSG_DRAW: - result = step_draw_int_view(int_view, target, rect, user_input, (message == VMSG_STEP)); + result = step_draw_int_view(system, int_view, target, rect, user_input, (message == VMSG_STEP)); break; } @@ -199,14 +202,14 @@ DO_VIEW_SIG(do_interactive_view){ } internal Interactive_View* -interactive_view_init(View *view, Hot_Directory *hot_dir, Style *style, +interactive_view_init(System_Functions *system, View *view, Hot_Directory *hot_dir, Style *style, Working_Set *working_set, Delay *delay){ Interactive_View *result = (Interactive_View*)view; view->type = VIEW_TYPE_INTERACTIVE; view->do_view = do_interactive_view; result->hot_directory = hot_dir; hot_directory_clean_end(hot_dir); - hot_directory_reload(hot_dir, working_set); + hot_directory_reload(system, hot_dir, working_set); result->query = make_fixed_width_string(result->query_); result->dest = make_fixed_width_string(result->dest_); result->style = style; diff --git a/4ed_internal.h b/4ed_internal.h index 537d5804..0cd490bc 100644 --- a/4ed_internal.h +++ b/4ed_internal.h @@ -7,178 +7,32 @@ * */ -/* - * Profiling - */ +// TOP #if FRED_INTERNAL == 1 -enum Debug_Event_Type{ - DBGEV_START, - DBGEV_END, - DBGEV_MOMENT, - // never below this - DBGEV_COUNT -}; +#define ProfileStart_(name, start, counter, hit, thread, n, c) -struct Debug_Event{ - i64 time; - char *name; - Debug_Event_Type type; - i32 which_hit; - i32 event_index; - i32 thread_index; -}; +#define ProfileEnd_(name, start, counter, hit, thread) -struct Debug_Event_Array{ - volatile u32 count; - Debug_Event e[4096]; -}; +#define ProfileMoment_(name, counter, thread) -struct Profile_Frame{ - Debug_Event_Array events; - i32 dbg_procing_start; - i32 dbg_procing_end; - i32 index; - i32 first_key; -}; +#if 0 -Profile_Frame profile_frame; +#define ProfileStart(name) char *_pname_##name; i64 _pstart_##name; \ + i32 _pcounter_##name; u32 _phit_##name; \ + ProfileStart_(_pname_##name, _pstart_##name, _pcounter_##name, \ + _phit_##name, system->thread_get_id(thread), \ + #name, __COUNTER__) -#define PAST_PROFILE_COUNT 30 -Profile_Frame past_frames[PAST_PROFILE_COUNT]; - -extern const i32 INTERNAL_event_index_count; -extern u32 INTERNAL_event_hits[]; -i64 INTERNAL_frame_start_time; - -bool32 INTERNAL_collecting_events; - -inline u32 -post_debug_event(char *name, Debug_Event_Type type, i32 event_index, i32 thread_index, u32 which_hit){ - u32 result = 0; - if (INTERNAL_collecting_events){ - u32 index = - InterlockedIncrement(&profile_frame.events.count); - --index; - - Assert(index < ArrayCount(profile_frame.events.e)); - - Debug_Event ev; - ev.time = system_time() - INTERNAL_frame_start_time; - ev.name = name; - ev.type = type; - ev.event_index = event_index; - ev.thread_index = thread_index; - - if (type == DBGEV_END){ - ev.which_hit = which_hit; - } - else{ - ev.which_hit = InterlockedIncrement(INTERNAL_event_hits + event_index) - 1; - } - - profile_frame.events.e[index] = ev; - result = ev.which_hit; - } - - return result; -} - -internal u32 -quick_partition(Debug_Event *es, u32 start, u32 pivot){ - Debug_Event *p = es + pivot; - - i32 m = (start + pivot) >> 1; - Swap(*p, es[m]); - - i32 pn = p->thread_index; - i32 pe = p->event_index; - i32 ph = p->which_hit; - i32 pt = p->type; - - for (u32 i = start; i < pivot; ++i){ - Debug_Event *e = es + i; - - bool32 smaller = 0; - - if (e->thread_index < pn) smaller = 1; - else if (e->thread_index == pn){ - if (e->type != DBGEV_MOMENT && pt == DBGEV_MOMENT) smaller = 1; - else if (e->type != DBGEV_MOMENT){ - if (e->event_index < pe) smaller = 1; - else if (e->event_index == pe){ - if (e->which_hit < ph) smaller = 1; - else if (e->which_hit == ph){ - if (e->type < pt) smaller = 1; - } - } - } - else if (pt == DBGEV_MOMENT){ - if (e->time < p->time) smaller = 1; - } - } - - if (smaller){ - Swap(*e, es[start]); - ++start; - } - } - Swap(*p, es[start]); - - return start; -} - -internal void -quick_sort(Debug_Event *e, u32 start, u32 pivot){ - u32 mid = quick_partition(e, start, pivot); - if (start + 1 < mid) quick_sort(e, start, mid - 1); - if (mid + 1 < pivot) quick_sort(e, mid + 1, pivot); -} - -inline void -sort(Debug_Event_Array *events){ - quick_sort(events->e, 0, events->count - 1); -} - -globalvar i32 INTERNAL_frame_index; -globalvar bool32 INTERNAL_updating_profile; - -#define ProfileStart_(name, start, counter, hit, thread, n, c)\ - name = n; counter = c; start = system_time(); hit = post_debug_event(n, DBGEV_START, counter, thread, 0) -#define ProfileEnd_(name, start, counter, hit, thread) post_debug_event(name, DBGEV_END, counter, thread, hit) -#define ProfileMoment_(name, counter, thread) post_debug_event(name, DBGEV_MOMENT, counter, thread, 0) - -struct INTERNAL_Profile_Block{ - char *name; - i64 start; - i32 counter; - i32 thread; - i32 hit; - - INTERNAL_Profile_Block(char *n, i32 c, i32 t){ - ProfileStart_(name, start, counter, hit, t, n, c); - thread = t; - } - - ~INTERNAL_Profile_Block(){ - ProfileEnd_(name, start, counter, hit, thread); - } -}; - -#define ProfileBlock(name, thread) INTERNAL_Profile_Block name(#name, __COUNTER__, thread) -#define ProfileBlockFunction() INTERNAL_Profile_Block name(__FUNCTION__, __COUNTER__, 0) - -#define ProfileStart(name) char *_pname_##name; i64 _pstart_##name; i32 _pcounter_##name; u32 _phit_##name; \ - ProfileStart_(_pname_##name, _pstart_##name, _pcounter_##name, _phit_##name, system_thread_get_id(thread), #name, __COUNTER__) - -#define ProfileEnd(name) ProfileEnd_(_pname_##name, _pstart_##name, _pcounter_##name, _phit_##name, system_thread_get_id(thread)) +#define ProfileEnd(name) ProfileEnd_(_pname_##name, _pstart_##name, \ + _pcounter_##name, _phit_##name, \ + system->thread_get_id(thread)) #define ProfileMoment(name, thread) ProfileMoment_(#name, __COUNTER__, thread) #define ProfileMomentFunction() ProfileMoment_(__FUNCTION__, __COUNTER__, 0) #else -#define ProfileBlock(name) #define ProfileStart(name) #define ProfileEnd(name) #define ProfileMoment(name) @@ -186,3 +40,21 @@ struct INTERNAL_Profile_Block{ #endif + + +struct Sys_Bubble : public Bubble{ + i32 line_number; + char *file_name; +}; + +#else + +#define ProfileStart(name) +#define ProfileEnd(name) +#define ProfileMoment(name) +#define ProfileMomentFunction() + +#endif + +// BOTTOM + diff --git a/4ed_layout.cpp b/4ed_layout.cpp index 834c44ef..6750102c 100644 --- a/4ed_layout.cpp +++ b/4ed_layout.cpp @@ -38,14 +38,19 @@ enum View_Message{ }; struct View; -#define DO_VIEW_SIG(name)\ - i32 (name)(Thread_Context *thread, View *view, i32_Rect rect, View *active,\ - View_Message message, Render_Target *target, Input_Summary *user_input, Input_Summary *active_input) +#define DO_VIEW_SIG(name) \ + i32 (name)(System_Functions *system, Thread_Context *thread, \ + View *view, i32_Rect rect, View *active, \ + View_Message message, Render_Target *target, \ + Input_Summary *user_input, Input_Summary *active_input) + typedef DO_VIEW_SIG(Do_View_Function); -#define HANDLE_COMMAND_SIG(name)\ - void (name)(View *view, Command_Data *command, Command_Binding binding,\ +#define HANDLE_COMMAND_SIG(name) \ + void (name)(System_Functions *system, View *view, \ + Command_Data *command, Command_Binding binding, \ Key_Single key, Key_Codes *codes) + typedef HANDLE_COMMAND_SIG(Handle_Command_Function); // TODO(allen): this shouldn't exist @@ -186,9 +191,9 @@ live_set_alloc_view(Live_Views *live_set, Mem_Options *mem){ } inline void -live_set_free_view(Live_Views *live_set, View *view){ +live_set_free_view(System_Functions *system, Live_Views *live_set, View *view){ Assert(live_set->count > 0); - view->do_view(0, view, {}, 0, VMSG_FREE, 0, {}, 0); + view->do_view(system, 0, view, {}, 0, VMSG_FREE, 0, {}, 0); view->next_free = live_set->free_view; live_set->free_view = view; --live_set->count; @@ -196,13 +201,13 @@ live_set_free_view(Live_Views *live_set, View *view){ } inline void -view_replace_major(View *new_view, Panel *panel, Live_Views *live_set){ +view_replace_major(System_Functions *system, View *new_view, Panel *panel, Live_Views *live_set){ View *view = panel->view; if (view){ if (view->is_minor && view->major){ - live_set_free_view(live_set, view->major); + live_set_free_view(system, live_set, view->major); } - live_set_free_view(live_set, view); + live_set_free_view(system, live_set, view); } new_view->panel = panel; new_view->minor = 0; @@ -210,13 +215,13 @@ view_replace_major(View *new_view, Panel *panel, Live_Views *live_set){ } inline void -view_replace_minor(View *new_view, Panel *panel, Live_Views *live_set){ +view_replace_minor(System_Functions *system, View *new_view, Panel *panel, Live_Views *live_set){ View *view = panel->view; new_view->is_minor = 1; if (view){ if (view->is_minor){ new_view->major = view->major; - live_set_free_view(live_set, view); + live_set_free_view(system, live_set, view); } else{ new_view->major = view; @@ -231,40 +236,40 @@ view_replace_minor(View *new_view, Panel *panel, Live_Views *live_set){ } inline void -view_remove_major(Panel *panel, Live_Views *live_set){ +view_remove_major(System_Functions *system, Panel *panel, Live_Views *live_set){ View *view = panel->view; if (view){ if (view->is_minor && view->major){ - live_set_free_view(live_set, view->major); + live_set_free_view(system, live_set, view->major); } - live_set_free_view(live_set, view); + live_set_free_view(system, live_set, view); } panel->view = 0; } inline void -view_remove_major_leave_minor(Panel *panel, Live_Views *live_set){ +view_remove_major_leave_minor(System_Functions *system, Panel *panel, Live_Views *live_set){ View *view = panel->view; if (view){ if (view->is_minor && view->major){ - live_set_free_view(live_set, view->major); + live_set_free_view(system, live_set, view->major); view->major = 0; } else{ - live_set_free_view(live_set, view); + live_set_free_view(system, live_set, view); panel->view = 0; } } } inline void -view_remove_minor(Panel *panel, Live_Views *live_set){ +view_remove_minor(System_Functions *system, Panel *panel, Live_Views *live_set){ View *view = panel->view; View *major = 0; if (view){ if (view->is_minor){ major = view->major; - live_set_free_view(live_set, view); + live_set_free_view(system, live_set, view); } } panel->view = major; @@ -272,10 +277,10 @@ view_remove_minor(Panel *panel, Live_Views *live_set){ } inline void -view_remove(Panel *panel, Live_Views *live_set){ +view_remove(System_Functions *system, Panel *panel, Live_Views *live_set){ View *view = panel->view; - if (view->is_minor) view_remove_minor(panel, live_set); - else view_remove_major(panel, live_set); + if (view->is_minor) view_remove_minor(system, panel, live_set); + else view_remove_major(system, panel, live_set); } struct Divider_And_ID{ diff --git a/4ed_mem.cpp b/4ed_mem.cpp new file mode 100644 index 00000000..0b9f3ad7 --- /dev/null +++ b/4ed_mem.cpp @@ -0,0 +1,253 @@ +/* + * Mr. 4th Dimention - Allen Webster + * + * 13.11.2015 + * + * Memory utils for 4coder + * + */ + +// TOP + +struct Partition{ + u8 *base; + i32 pos, max; +}; + +inline Partition +partition_open(void *memory, i32 size){ + Partition partition; + partition.base = (u8*)memory;; + partition.pos = 0; + partition.max = size; + return partition; +} + +inline void* +partition_allocate(Partition *data, i32 size){ + void *ret = 0; + if (size > 0 && data->pos + size <= data->max){ + ret = data->base + data->pos; + data->pos += size; + } + return ret; +} + +inline void +partition_align(Partition *data, u32 boundary){ + data->pos = (data->pos + (boundary - 1)) & (~boundary); +} + +inline void* +partition_current(Partition *data){ + return data->base + data->pos; +} + +inline i32 +partition_remaining(Partition *data){ + return data->max - data->pos; +} + +inline Partition +partition_sub_part(Partition *data, i32 size){ + Partition result = {}; + void *d = partition_allocate(data, size); + if (d) result = partition_open(d, size); + return result; +} + +#define push_struct(part, T) (T*)partition_allocate(part, sizeof(T)) +#define push_array(part, T, size) (T*)partition_allocate(part, sizeof(T)*(size)) +#define push_block(part, size) partition_allocate(part, size) + +enum Memory_Bubble_Flag{ + MEM_BUBBLE_USED = 0x1, + MEM_BUBBLE_DEBUG = 0xD3000000, + MEM_BUBBLE_SYS_DEBUG = 0x5D000000, + MEM_BUBBLE_DEBUG_MASK = 0xFF000000 +}; + +struct Bubble{ + Bubble *prev; + Bubble *next; + u32 flags; + i32 size; + u32 type; + u32 _unused_; +}; + +struct General_Memory{ + Bubble sentinel; +}; + +inline void +insert_bubble(Bubble *prev, Bubble *bubble){ + bubble->prev = prev; + bubble->next = prev->next; + bubble->prev->next = bubble; + bubble->next->prev = bubble; +} + +inline void +remove_bubble(Bubble *bubble){ + bubble->prev->next = bubble->next; + bubble->next->prev = bubble->prev; +} + +#if FRED_INTERNAL +#define MEM_BUBBLE_FLAG_INIT MEM_BUBBLE_DEBUG +#else +#define MEM_BUBBLE_FLAG_INIT 0 +#endif + +internal void +general_memory_open(General_Memory *general, void *memory, i32 size){ + general->sentinel.prev = &general->sentinel; + general->sentinel.next = &general->sentinel; + general->sentinel.flags = MEM_BUBBLE_USED; + general->sentinel.size = 0; + + Bubble *first = (Bubble*)memory; + first->flags = (u32)MEM_BUBBLE_FLAG_INIT; + first->size = size - sizeof(Bubble); + insert_bubble(&general->sentinel, first); +} + +internal void +general_memory_check(General_Memory *general){ + Bubble *sentinel = &general->sentinel; + for (Bubble *bubble = sentinel->next; + bubble != sentinel; + bubble = bubble->next){ + Assert(bubble); + + Bubble *next = bubble->next; + Assert(bubble == next->prev); + if (next != sentinel){ + Assert(bubble->next > bubble); + Assert(bubble > bubble->prev); + + char *end_ptr = (char*)(bubble + 1) + bubble->size; + char *next_ptr = (char*)next; + AllowLocal(end_ptr); + AllowLocal(next_ptr); + Assert(end_ptr == next_ptr); + } + } +} + +#define BUBBLE_MIN_SIZE 1024 + +internal void +general_memory_attempt_split(Bubble *bubble, i32 wanted_size){ + i32 remaining_size = bubble->size - wanted_size; + if (remaining_size >= BUBBLE_MIN_SIZE){ + bubble->size = wanted_size; + Bubble *new_bubble = (Bubble*)((u8*)(bubble + 1) + wanted_size); + new_bubble->flags = (u32)MEM_BUBBLE_FLAG_INIT; + new_bubble->size = remaining_size - sizeof(Bubble); + insert_bubble(bubble, new_bubble); + } +} + +internal void* +general_memory_allocate(General_Memory *general, i32 size, u32 type = 0){ + void *result = 0; + for (Bubble *bubble = general->sentinel.next; + bubble != &general->sentinel; + bubble = bubble->next){ + if (!(bubble->flags & MEM_BUBBLE_USED)){ + if (bubble->size >= size){ + result = bubble + 1; + bubble->flags |= MEM_BUBBLE_USED; + bubble->type = type; + general_memory_attempt_split(bubble, size); + break; + } + } + } + return result; +} + +inline void +general_memory_do_merge(Bubble *left, Bubble *right){ + Assert(left->next == right); + Assert(right->prev == left); + left->size += sizeof(Bubble) + right->size; + remove_bubble(right); +} + +inline void +general_memory_attempt_merge(Bubble *left, Bubble *right){ + if (!(left->flags & MEM_BUBBLE_USED) && + !(right->flags & MEM_BUBBLE_USED)){ + general_memory_do_merge(left, right); + } +} + +internal void +general_memory_free(General_Memory *general, void *memory){ + Bubble *bubble = ((Bubble*)memory) - 1; + Assert((!FRED_INTERNAL) || (bubble->flags & MEM_BUBBLE_DEBUG_MASK) == MEM_BUBBLE_DEBUG); + bubble->flags &= ~MEM_BUBBLE_USED; + bubble->type = 0; + Bubble *prev, *next; + prev = bubble->prev; + next = bubble->next; + general_memory_attempt_merge(bubble, next); + general_memory_attempt_merge(prev, bubble); +} + +internal void* +general_memory_reallocate(General_Memory *general, void *old, i32 old_size, i32 size, u32 type = 0){ + void *result = old; + Bubble *bubble = ((Bubble*)old) - 1; + bubble->type = type; + Assert((!FRED_INTERNAL) || (bubble->flags & MEM_BUBBLE_DEBUG_MASK) == MEM_BUBBLE_DEBUG); + i32 additional_space = size - bubble->size; + if (additional_space > 0){ + Bubble *next = bubble->next; + if (!(next->flags & MEM_BUBBLE_USED) && + next->size + sizeof(Bubble) >= additional_space){ + general_memory_do_merge(bubble, next); + general_memory_attempt_split(bubble, size); + } + else{ + result = general_memory_allocate(general, size, type); + if (old_size) memcpy(result, old, old_size); + general_memory_free(general, old); + } + } + return result; +} + +inline void* +general_memory_reallocate_nocopy(General_Memory *general, void *old, i32 size, u32 type = 0){ + return general_memory_reallocate(general, old, 0, size, type); +} + +struct Temp_Memory{ + Partition *part; + i32 pos; +}; + +internal Temp_Memory +begin_temp_memory(Partition *data){ + Temp_Memory result; + result.part = data; + result.pos = data->pos; + return result; +} + +internal void +end_temp_memory(Temp_Memory temp){ + temp.part->pos = temp.pos; +} + +struct Mem_Options{ + Partition part; + General_Memory general; +}; + +// BOTTOM + diff --git a/4ed_meta.h b/4ed_meta.h index f852729c..ef2dab80 100644 --- a/4ed_meta.h +++ b/4ed_meta.h @@ -33,6 +33,7 @@ typedef double real64; typedef float f32; typedef double f64; +#define external extern "C" #define internal static #define globalvar static #define persist static diff --git a/4ed_rendering.cpp b/4ed_rendering.cpp index a3c272f6..70fae083 100644 --- a/4ed_rendering.cpp +++ b/4ed_rendering.cpp @@ -669,12 +669,13 @@ font_predict_size(i32 pt_size){ } internal i32 -font_load(Font *font_out, char *filename, i32 pt_size, +font_load(System_Functions *system, + Font *font_out, char *filename, i32 pt_size, void *font_block, i32 font_block_size, i32 *memory_used_out, i32 tab_width){ i32 result = 1; File_Data file; - file = system_load_file((u8*)filename); + file = system->load_file(filename); if (!file.data){ result = 0; @@ -749,7 +750,7 @@ font_load(Font *font_out, char *filename, i32 pt_size, } font_out->advance = max_advance - 1; } - system_free_file(file); + system->free_file(file); } return result; diff --git a/4ed_style.cpp b/4ed_style.cpp index 8097f94c..3bc54126 100644 --- a/4ed_style.cpp +++ b/4ed_style.cpp @@ -475,10 +475,11 @@ style_format_for_use(Font_Set *fonts, Style *out, Style_File_Format_v3 *style){ } internal bool32 -style_library_import(u8 *filename, Font_Set *fonts, Style *out, i32 max, +style_library_import(System_Functions *system, + char *filename, Font_Set *fonts, Style *out, i32 max, i32 *count_opt, i32 *total_opt = 0){ bool32 result = 1; - File_Data file = system_load_file(filename); + File_Data file = system->load_file(filename); if (!file.data){ result = 0; } @@ -538,7 +539,7 @@ style_library_import(u8 *filename, Font_Set *fonts, Style *out, i32 max, } early_exit: - system_free_file(file); + system->free_file(file); } return result; @@ -594,10 +595,10 @@ style_format_for_file(Style *style, Style_File_Format *out){ } internal void -style_library_export(u8 *filename, Style **styles, i32 count){ +style_library_export(System_Functions *system, char *filename, Style **styles, i32 count){ i32 size = count*(sizeof(Style_File_Format) + STAG_COUNT*sizeof(Style_Color_Specifier)) + sizeof(P4C_Page_Header) + sizeof(Style_Page_Header); - void *data = system_get_memory(size); + void *data = system->get_memory(size); void *cursor = data; { @@ -619,8 +620,8 @@ style_library_export(u8 *filename, Style **styles, i32 count){ for (i32 i = 0; i < count; ++i){ out = style_format_for_file(*in++, out); } - system_save_file(filename, data, size); - system_free_memory(data); + system->save_file(filename, data, size); + system->free_memory(data); } // BOTTOM diff --git a/4ed_system.h b/4ed_system.h index 5d7e73d8..7f6d5f8b 100644 --- a/4ed_system.h +++ b/4ed_system.h @@ -7,10 +7,14 @@ * */ -struct Plat_Handle{ u64 d[2]; }; +// TOP + +struct System_Functions; + +struct Plat_Handle{ + u32 d[4]; +}; -// TODO(allen): This should either be a String or it should be improved -// to handle 64-bit sized files. Staying in this state, however, is unacceptable. struct File_Data{ void *data; u32 size; @@ -18,65 +22,60 @@ struct File_Data{ struct Time_Stamp{ u64 time; - bool32 success; + b32 success; }; -internal File_Data -system_load_file(u8 *filename); +#define Sys_Load_File_Sig(name) File_Data name(char *filename) +typedef Sys_Load_File_Sig(System_Load_File); -internal bool32 -system_save_file(u8 *filename, void *data, i32 size); +#define Sys_Save_File_Sig(name) i32 name(char *filename, void *data, i32 size) +typedef Sys_Save_File_Sig(System_Save_File); -internal Time_Stamp -system_file_time_stamp(u8 *filename); +#define Sys_File_Time_Stamp_Sig(name) Time_Stamp name(char *filename) +typedef Sys_File_Time_Stamp_Sig(System_File_Time_Stamp); -internal u64 -system_get_now(); +#define Sys_Time_Stamp_Now_Sig(name) u64 name() +typedef Sys_Time_Stamp_Now_Sig(System_Time_Stamp_Now); -internal void -system_free_file(File_Data data); +#define Sys_Free_File_Sig(name) void name(File_Data file) +typedef Sys_Free_File_Sig(System_Free_File); -internal void -system_fatal_error(u8 *message); +#define Sys_Get_Current_Directory_Sig(name) i32 name(char *out, i32 max) +typedef Sys_Get_Current_Directory_Sig(System_Get_Current_Directory); -internal i32 -system_get_working_directory(u8 *destination, i32 max_size); - -internal i32 -system_get_easy_directory(u8 *destination); +#define Sys_Get_Easy_Directory_Sig(name) i32 name(char *destination) +typedef Sys_Get_Easy_Directory_Sig(System_Get_Easy_Directory); struct File_Info{ String filename; - bool32 folder; - //bool32 loaded; + b32 folder; }; struct File_List{ File_Info *infos; - i32 count; - void *block; + i32 count; }; -internal File_List -system_get_files(String directory); +#define Sys_Get_File_List_Sig(name) File_List name(String directory) +typedef Sys_Get_File_List_Sig(System_Get_File_List); -internal void -system_free_file_list(File_List list); +#define Sys_Free_File_List_Sig(name) void name(File_List list) +typedef Sys_Free_File_List_Sig(System_Free_File_List); -internal void* -system_get_memory_(i32 size, i32 line_number, char *file_name); +#define Sys_Get_Memory_Sig(name) void* name(i32 size, i32 line_number, char *filename) +typedef Sys_Get_Memory_Sig(System_Get_Memory); -#define system_get_memory(size) system_get_memory_(size, __LINE__, __FILE__) +#define get_memory(size) get_memory_full(size, __LINE__, __FILE__) -internal void -system_free_memory(void *block); +#define Sys_Free_Memory_Sig(name) void name(void *block); +typedef Sys_Free_Memory_Sig(System_Free_Memory); -internal void -system_post_clipboard(String str); +#define Sys_Post_Clipboard_Sig(name) void name(String str); +typedef Sys_Post_Clipboard_Sig(System_Post_Clipboard); -internal i64 -system_time(); +#define Sys_Time_Sig(name) i64 name() +typedef Sys_Time_Sig(System_Time); struct CLI_Handles{ Plat_Handle proc; @@ -85,55 +84,20 @@ struct CLI_Handles{ u32 scratch_space[4]; }; -internal b32 -system_cli_call(char *path, char *script_name, CLI_Handles *cli_out); +#define Sys_CLI_Call_Sig(name) b32 name(char *path, char *script, CLI_Handles *cli) +typedef Sys_CLI_Call_Sig(System_CLI_Call); -internal void -system_cli_begin_update(CLI_Handles *cli); +#define Sys_CLI_Begin_Update_Sig(name) void name(CLI_Handles *cli) +typedef Sys_CLI_Begin_Update_Sig(System_CLI_Begin_Update); -internal b32 -system_cli_update_step(CLI_Handles *cli, char *dest, u32 max, u32 *amount); +#define Sys_CLI_Update_Step_Sig(name) b32 name(CLI_Handles *cli, char *dest, u32 max, u32 *amount) +typedef Sys_CLI_Update_Step_Sig(System_CLI_Update_Step); -internal b32 -system_cli_end_update(CLI_Handles *cli); +#define Sys_CLI_End_Update_Sig(name) b32 name(CLI_Handles *cli) +typedef Sys_CLI_End_Update_Sig(System_CLI_End_Update); struct Thread_Context; -struct Thread_Memory{ - void *data; - i32 size; - i32 id; -}; - -internal u32 -system_thread_get_id(Thread_Context *thread); - -internal u32 -system_thread_current_job_id(Thread_Context *thread); - -enum Thread_Group_ID{ - BACKGROUND_THREADS, - THREAD_GROUP_COUNT -}; - -#define JOB_CALLBACK(name) void name(Thread_Context *thread, Thread_Memory *memory, void *data[2]) -typedef JOB_CALLBACK(Job_Callback); - -struct Job_Data{ - Job_Callback *callback; - void *data[2]; - i32 memory_request; -}; - -internal u32 -system_post_job(Thread_Group_ID group_id, Job_Data job); - -internal void -system_cancel_job(Thread_Group_ID group_id, u32 job_id); - -internal bool32 -system_job_is_pending(Thread_Group_ID group_id, u32 job_id); - enum Lock_ID{ FRAME_LOCK, CANCEL_LOCK0, @@ -147,29 +111,97 @@ enum Lock_ID{ LOCK_COUNT }; -internal void -system_aquire_lock(Lock_ID id); +enum Thread_Group_ID{ + BACKGROUND_THREADS, + THREAD_GROUP_COUNT +}; -internal void -system_release_lock(Lock_ID id); +struct Thread_Memory{ + void *data; + i32 size; + i32 id; +}; -internal void -system_aquire_lock(i32 id); +#define Job_Callback(name) void name(System_Functions *system, Thread_Context *thread, Thread_Memory *memory, void *data[2]) +typedef Job_Callback(Job_Callback); -internal void -system_release_lock(i32 id); +struct Job_Data{ + Job_Callback *callback; + void *data[2]; + i32 memory_request; +}; -internal void -system_grow_thread_memory(Thread_Memory *memory); +#define Sys_Thread_Get_ID_Sig(name) u32 name(Thread_Context *thread) +typedef Sys_Thread_Get_ID_Sig(System_Thread_Get_ID); -internal void -system_force_redraw(); +#define Sys_Thread_Current_Job_ID_Sig(name) u32 name(Thread_Context *thread) +typedef Sys_Thread_Current_Job_ID_Sig(System_Thread_Current_Job_ID); -#if FRED_INTERNAL -internal Bubble* -INTERNAL_system_sentinel(); +#define Sys_Post_Job_Sig(name) u32 name(Thread_Group_ID id, Job_Data job) +typedef Sys_Post_Job_Sig(System_Post_Job); -internal void -INTERNAL_get_thread_states(Thread_Group_ID id, bool8 *running, i32 *pending); -#endif +#define Sys_Cancel_Job_Sig(name) void name(Thread_Group_ID id, u32 job_id) +typedef Sys_Cancel_Job_Sig(System_Cancel_Job); + +#define Sys_Job_Is_Pending_Sig(name) b32 name(Thread_Group_ID id, u32 job_id) +typedef Sys_Job_Is_Pending_Sig(System_Job_Is_Pending); + +#define Sys_Grow_Thread_Memory_Sig(name) void name(Thread_Memory *memory) +typedef Sys_Grow_Thread_Memory_Sig(System_Grow_Thread_Memory); + +#define Sys_Acquire_Lock_Sig(name) void name(i32 id) +typedef Sys_Acquire_Lock_Sig(System_Acquire_Lock); + +#define Sys_Release_Lock_Sig(name) void name(i32 id) +typedef Sys_Release_Lock_Sig(System_Release_Lock); + +#define Sys_Force_Redraw_Sig(name) void name() +typedef Sys_Force_Redraw_Sig(System_Force_Redraw); + +#define INTERNAL_Sys_Sentinel_Sig(name) Bubble* name() +typedef INTERNAL_Sys_Sentinel_Sig(INTERNAL_System_Sentinel); + +#define INTERNAL_Sys_Get_Thread_States_Sig(name) void name(Thread_Group_ID id, b8 *running, i32 *pending) +typedef INTERNAL_Sys_Get_Thread_States_Sig(INTERNAL_System_Get_Thread_States); + +struct System_Functions{ + System_Load_File *load_file; + System_Save_File *save_file; + System_File_Time_Stamp *file_time_stamp; + System_Time_Stamp_Now *time_stamp_now; + System_Free_File *free_file; + + System_Get_Current_Directory *get_current_directory; + System_Get_Easy_Directory *get_easy_directory; + + System_Get_File_List *get_file_list; + System_Free_File_List *free_file_list; + + System_Get_Memory *get_memory_full; + System_Free_Memory *free_memory; + + System_Post_Clipboard *post_clipboard; + System_Time *time; + + System_CLI_Call *cli_call; + System_CLI_Begin_Update *cli_begin_update; + System_CLI_Update_Step *cli_update_step; + System_CLI_End_Update *cli_end_update; + + System_Thread_Get_ID *thread_get_id; + System_Thread_Current_Job_ID *thread_current_job_id; + System_Post_Job *post_job; + System_Cancel_Job *cancel_job; + System_Job_Is_Pending *job_is_pending; + System_Grow_Thread_Memory *grow_thread_memory; + System_Acquire_Lock *acquire_lock; + System_Release_Lock *release_lock; + + System_Force_Redraw *force_redraw; + + INTERNAL_System_Sentinel *internal_sentinel; + INTERNAL_System_Get_Thread_States *internal_get_thread_states; +}; + +// BOTTOM diff --git a/buffer/4coder_test_main.cpp b/buffer/4coder_test_main.cpp index 6f9c3ac0..1a384a1d 100644 --- a/buffer/4coder_test_main.cpp +++ b/buffer/4coder_test_main.cpp @@ -1178,8 +1178,8 @@ void batch_edit_test(Stats_Log *log, Buffer_Set *buffers, int test_repitions, fl Sample_Machine machine; machine = begin_machine(test_repitions, &scratch, &scratch_size); - printf("batch size: %d\n", replay->replay.count); - log_data_item(log, litstr("batch-size"), replay->replay.count); + printf("batch size: %d\n", batch_size); + log_data_item(log, litstr("batch-size"), batch_size); int i; for (i = 0; i < test_repitions; ++i){ start(&machine); @@ -1396,20 +1396,13 @@ int main(int argc, char **argv){ { char word[] = "not-going-to-find-this"; int word_len = sizeof(word) - 1; - word_seek_test(&log, &buffers, reps, 0, word, word_len, scratch, scratch_size, &word_seek); - } { char word[] = "return"; int word_len = sizeof(word) - 1; - word_seek_test(&log, &buffers, reps, 1, word, word_len, scratch, scratch_size, &word_seek); - - printf("average normal word seek:\n"); - print_record(word_seek.expected); - printf("\n"); } } log_end_section(&log); @@ -1463,7 +1456,7 @@ int main(int argc, char **argv){ character_stride = 10; } else{ - character_stride = (character_stride / batch_size); + character_stride /= batch_size; } int p, curs; diff --git a/buffer/stb_truetype.h b/buffer/stb_truetype.h deleted file mode 100644 index 52126e81..00000000 --- a/buffer/stb_truetype.h +++ /dev/null @@ -1,2663 +0,0 @@ -// stb_truetype.h - v1.05 - public domain -// authored from 2009-2014 by Sean Barrett / RAD Game Tools -// -// This library processes TrueType files: -// parse files -// extract glyph metrics -// extract glyph shapes -// render glyphs to one-channel bitmaps with antialiasing (box filter) -// -// Todo: -// non-MS cmaps -// crashproof on bad data -// hinting? (no longer patented) -// cleartype-style AA? -// optimize: use simple memory allocator for intermediates -// optimize: build edge-list directly from curves -// optimize: rasterize directly from curves? -// -// CUSTOMIZATIONS -// -// This particular version has been customized by Allen Webster. -// These customizations include: -// stbtt_GetBakedQuadUnrounded -// -// ADDITIONAL CONTRIBUTORS -// -// Mikko Mononen: compound shape support, more cmap formats -// Tor Andersson: kerning, subpixel rendering -// -// Bug/warning reports/fixes: -// "Zer" on mollyrocket (with fix) -// Cass Everitt -// stoiko (Haemimont Games) -// Brian Hook -// Walter van Niftrik -// David Gow -// David Given -// Ivan-Assen Ivanov -// Anthony Pesch -// Johan Duparc -// Hou Qiming -// Fabian "ryg" Giesen -// Martins Mozeiko -// Cap Petschulat -// Omar Cornut -// github:aloucks -// Peter LaValle -// -// Misc other: -// Ryan Gordon -// -// VERSION HISTORY -// -// 1.05 (2015-04-15) fix misplaced definitions for STBTT_STATIC -// 1.04 (2015-04-15) typo in example -// 1.03 (2015-04-12) STBTT_STATIC, fix memory leak in new packing, various fixes -// 1.02 (2014-12-10) fix various warnings & compile issues w/ stb_rect_pack, C++ -// 1.01 (2014-12-08) fix subpixel position when oversampling to exactly match -// non-oversampled; STBTT_POINT_SIZE for packed case only -// 1.00 (2014-12-06) add new PackBegin etc. API, w/ support for oversampling -// 0.99 (2014-09-18) fix multiple bugs with subpixel rendering (ryg) -// 0.9 (2014-08-07) support certain mac/iOS fonts without an MS platformID -// 0.8b (2014-07-07) fix a warning -// 0.8 (2014-05-25) fix a few more warnings -// 0.7 (2013-09-25) bugfix: subpixel glyph bug fixed in 0.5 had come back -// 0.6c (2012-07-24) improve documentation -// 0.6b (2012-07-20) fix a few more warnings -// 0.6 (2012-07-17) fix warnings; added stbtt_ScaleForMappingEmToPixels, -// stbtt_GetFontBoundingBox, stbtt_IsGlyphEmpty -// 0.5 (2011-12-09) bugfixes: -// subpixel glyph renderer computed wrong bounding box -// first vertex of shape can be off-curve (FreeSans) -// 0.4b (2011-12-03) fixed an error in the font baking example -// 0.4 (2011-12-01) kerning, subpixel rendering (tor) -// bugfixes for: -// codepoint-to-glyph conversion using table fmt=12 -// codepoint-to-glyph conversion using table fmt=4 -// stbtt_GetBakedQuad with non-square texture (Zer) -// updated Hello World! sample to use kerning and subpixel -// fixed some warnings -// 0.3 (2009-06-24) cmap fmt=12, compound shapes (MM) -// userdata, malloc-from-userdata, non-zero fill (stb) -// 0.2 (2009-03-11) Fix unsigned/signed char warnings -// 0.1 (2009-03-09) First public release -// -// LICENSE -// -// This software is in the public domain. Where that dedication is not -// recognized, you are granted a perpetual, irrevokable license to copy -// and modify this file as you see fit. -// -// USAGE -// -// Include this file in whatever places neeed to refer to it. In ONE C/C++ -// file, write: -// #define STB_TRUETYPE_IMPLEMENTATION -// before the #include of this file. This expands out the actual -// implementation into that C/C++ file. -// -// To make the implementation private to the file that generates the implementation, -// #define STBTT_STATIC -// -// Simple 3D API (don't ship this, but it's fine for tools and quick start) -// stbtt_BakeFontBitmap() -- bake a font to a bitmap for use as texture -// stbtt_GetBakedQuad() -- compute quad to draw for a given char -// -// Improved 3D API (more shippable): -// #include "stb_rect_pack.h" -- optional, but you really want it -// stbtt_PackBegin() -// stbtt_PackSetOversample() -- for improved quality on small fonts -// stbtt_PackFontRanges() -// stbtt_PackEnd() -// stbtt_GetPackedQuad() -// -// "Load" a font file from a memory buffer (you have to keep the buffer loaded) -// stbtt_InitFont() -// stbtt_GetFontOffsetForIndex() -- use for TTC font collections -// -// Render a unicode codepoint to a bitmap -// stbtt_GetCodepointBitmap() -- allocates and returns a bitmap -// stbtt_MakeCodepointBitmap() -- renders into bitmap you provide -// stbtt_GetCodepointBitmapBox() -- how big the bitmap must be -// -// Character advance/positioning -// stbtt_GetCodepointHMetrics() -// stbtt_GetFontVMetrics() -// stbtt_GetCodepointKernAdvance() -// -// ADDITIONAL DOCUMENTATION -// -// Immediately after this block comment are a series of sample programs. -// -// After the sample programs is the "header file" section. This section -// includes documentation for each API function. -// -// Some important concepts to understand to use this library: -// -// Codepoint -// Characters are defined by unicode codepoints, e.g. 65 is -// uppercase A, 231 is lowercase c with a cedilla, 0x7e30 is -// the hiragana for "ma". -// -// Glyph -// A visual character shape (every codepoint is rendered as -// some glyph) -// -// Glyph index -// A font-specific integer ID representing a glyph -// -// Baseline -// Glyph shapes are defined relative to a baseline, which is the -// bottom of uppercase characters. Characters extend both above -// and below the baseline. -// -// Current Point -// As you draw text to the screen, you keep track of a "current point" -// which is the origin of each character. The current point's vertical -// position is the baseline. Even "baked fonts" use this model. -// -// Vertical Font Metrics -// The vertical qualities of the font, used to vertically position -// and space the characters. See docs for stbtt_GetFontVMetrics. -// -// Font Size in Pixels or Points -// The preferred interface for specifying font sizes in stb_truetype -// is to specify how tall the font's vertical extent should be in pixels. -// If that sounds good enough, skip the next paragraph. -// -// Most font APIs instead use "points", which are a common typographic -// measurement for describing font size, defined as 72 points per inch. -// stb_truetype provides a point API for compatibility. However, true -// "per inch" conventions don't make much sense on computer displays -// since they different monitors have different number of pixels per -// inch. For example, Windows traditionally uses a convention that -// there are 96 pixels per inch, thus making 'inch' measurements have -// nothing to do with inches, and thus effectively defining a point to -// be 1.333 pixels. Additionally, the TrueType font data provides -// an explicit scale factor to scale a given font's glyphs to points, -// but the author has observed that this scale factor is often wrong -// for non-commercial fonts, thus making fonts scaled in points -// according to the TrueType spec incoherently sized in practice. -// -// ADVANCED USAGE -// -// Quality: -// -// - Use the functions with Subpixel at the end to allow your characters -// to have subpixel positioning. Since the font is anti-aliased, not -// hinted, this is very import for quality. (This is not possible with -// baked fonts.) -// -// - Kerning is now supported, and if you're supporting subpixel rendering -// then kerning is worth using to give your text a polished look. -// -// Performance: -// -// - Convert Unicode codepoints to glyph indexes and operate on the glyphs; -// if you don't do this, stb_truetype is forced to do the conversion on -// every call. -// -// - There are a lot of memory allocations. We should modify it to take -// a temp buffer and allocate from the temp buffer (without freeing), -// should help performance a lot. -// -// NOTES -// -// The system uses the raw data found in the .ttf file without changing it -// and without building auxiliary data structures. This is a bit inefficient -// on little-endian systems (the data is big-endian), but assuming you're -// caching the bitmaps or glyph shapes this shouldn't be a big deal. -// -// It appears to be very hard to programmatically determine what font a -// given file is in a general way. I provide an API for this, but I don't -// recommend it. -// -// -// SOURCE STATISTICS (based on v0.6c, 2050 LOC) -// -// Documentation & header file 520 LOC \___ 660 LOC documentation -// Sample code 140 LOC / -// Truetype parsing 620 LOC ---- 620 LOC TrueType -// Software rasterization 240 LOC \ . -// Curve tesselation 120 LOC \__ 550 LOC Bitmap creation -// Bitmap management 100 LOC / -// Baked bitmap interface 70 LOC / -// Font name matching & access 150 LOC ---- 150 -// C runtime library abstraction 60 LOC ---- 60 - - -////////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////////// -//// -//// SAMPLE PROGRAMS -//// -// -// Incomplete text-in-3d-api example, which draws quads properly aligned to be lossless -// -#if 0 -#define STB_TRUETYPE_IMPLEMENTATION // force following include to generate implementation -#include "stb_truetype.h" - -unsigned char ttf_buffer[1<<20]; -unsigned char temp_bitmap[512*512]; - -stbtt_bakedchar cdata[96]; // ASCII 32..126 is 95 glyphs -GLuint ftex; - -void my_stbtt_initfont(void) -{ - fread(ttf_buffer, 1, 1<<20, fopen("c:/windows/fonts/times.ttf", "rb")); - stbtt_BakeFontBitmap(ttf_buffer,0, 32.0, temp_bitmap,512,512, 32,96, cdata); // no guarantee this fits! - // can free ttf_buffer at this point - glGenTextures(1, &ftex); - glBindTexture(GL_TEXTURE_2D, ftex); - glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, 512,512, 0, GL_ALPHA, GL_UNSIGNED_BYTE, temp_bitmap); - // can free temp_bitmap at this point - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); -} - -void my_stbtt_print(float x, float y, char *text) -{ - // assume orthographic projection with units = screen pixels, origin at top left - glEnable(GL_TEXTURE_2D); - glBindTexture(GL_TEXTURE_2D, ftex); - glBegin(GL_QUADS); - while (*text) { - if (*text >= 32 && *text < 128) { - stbtt_aligned_quad q; - stbtt_GetBakedQuad(cdata, 512,512, *text-32, &x,&y,&q,1);//1=opengl & d3d10+,0=d3d9 - glTexCoord2f(q.s0,q.t1); glVertex2f(q.x0,q.y0); - glTexCoord2f(q.s1,q.t1); glVertex2f(q.x1,q.y0); - glTexCoord2f(q.s1,q.t0); glVertex2f(q.x1,q.y1); - glTexCoord2f(q.s0,q.t0); glVertex2f(q.x0,q.y1); - } - ++text; - } - glEnd(); -} -#endif -// -// -////////////////////////////////////////////////////////////////////////////// -// -// Complete program (this compiles): get a single bitmap, print as ASCII art -// -#if 0 -#include -#define STB_TRUETYPE_IMPLEMENTATION // force following include to generate implementation -#include "stb_truetype.h" - -char ttf_buffer[1<<25]; - -int main(int argc, char **argv) -{ - stbtt_fontinfo font; - unsigned char *bitmap; - int w,h,i,j,c = (argc > 1 ? atoi(argv[1]) : 'a'), s = (argc > 2 ? atoi(argv[2]) : 20); - - fread(ttf_buffer, 1, 1<<25, fopen(argc > 3 ? argv[3] : "c:/windows/fonts/arialbd.ttf", "rb")); - - stbtt_InitFont(&font, ttf_buffer, stbtt_GetFontOffsetForIndex(ttf_buffer,0)); - bitmap = stbtt_GetCodepointBitmap(&font, 0,stbtt_ScaleForPixelHeight(&font, s), c, &w, &h, 0,0); - - for (j=0; j < h; ++j) { - for (i=0; i < w; ++i) - putchar(" .:ioVM@"[bitmap[j*w+i]>>5]); - putchar('\n'); - } - return 0; -} -#endif -// -// Output: -// -// .ii. -// @@@@@@. -// V@Mio@@o -// :i. V@V -// :oM@@M -// :@@@MM@M -// @@o o@M -// :@@. M@M -// @@@o@@@@ -// :M@@V:@@. -// -////////////////////////////////////////////////////////////////////////////// -// -// Complete program: print "Hello World!" banner, with bugs -// -#if 0 -char buffer[24<<20]; -unsigned char screen[20][79]; - -int main(int arg, char **argv) -{ - stbtt_fontinfo font; - int i,j,ascent,baseline,ch=0; - float scale, xpos=2; // leave a little padding in case the character extends left - char *text = "Heljo World!"; - - fread(buffer, 1, 1000000, fopen("c:/windows/fonts/arialbd.ttf", "rb")); - stbtt_InitFont(&font, buffer, 0); - - scale = stbtt_ScaleForPixelHeight(&font, 15); - stbtt_GetFontVMetrics(&font, &ascent,0,0); - baseline = (int) (ascent*scale); - - while (text[ch]) { - int advance,lsb,x0,y0,x1,y1; - float x_shift = xpos - (float) floor(xpos); - stbtt_GetCodepointHMetrics(&font, text[ch], &advance, &lsb); - stbtt_GetCodepointBitmapBoxSubpixel(&font, text[ch], scale,scale,x_shift,0, &x0,&y0,&x1,&y1); - stbtt_MakeCodepointBitmapSubpixel(&font, &screen[baseline + y0][(int) xpos + x0], x1-x0,y1-y0, 79, scale,scale,x_shift,0, text[ch]); - // note that this stomps the old data, so where character boxes overlap (e.g. 'lj') it's wrong - // because this API is really for baking character bitmaps into textures. if you want to render - // a sequence of characters, you really need to render each bitmap to a temp buffer, then - // "alpha blend" that into the working buffer - xpos += (advance * scale); - if (text[ch+1]) - xpos += scale*stbtt_GetCodepointKernAdvance(&font, text[ch],text[ch+1]); - ++ch; - } - - for (j=0; j < 20; ++j) { - for (i=0; i < 78; ++i) - putchar(" .:ioVM@"[screen[j][i]>>5]); - putchar('\n'); - } - - return 0; -} -#endif - - -////////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////////// -//// -//// INTEGRATION WITH YOUR CODEBASE -//// -//// The following sections allow you to supply alternate definitions -//// of C library functions used by stb_truetype. - -#ifdef STB_TRUETYPE_IMPLEMENTATION - // #define your own (u)stbtt_int8/16/32 before including to override this - #ifndef stbtt_uint8 - typedef unsigned char stbtt_uint8; - typedef signed char stbtt_int8; - typedef unsigned short stbtt_uint16; - typedef signed short stbtt_int16; - typedef unsigned int stbtt_uint32; - typedef signed int stbtt_int32; - #endif - - typedef char stbtt__check_size32[sizeof(stbtt_int32)==4 ? 1 : -1]; - typedef char stbtt__check_size16[sizeof(stbtt_int16)==2 ? 1 : -1]; - - // #define your own STBTT_sort() to override this to avoid qsort - #ifndef STBTT_sort - #include - #define STBTT_sort(data,num_items,item_size,compare_func) qsort(data,num_items,item_size,compare_func) - #endif - - // #define your own STBTT_ifloor/STBTT_iceil() to avoid math.h - #ifndef STBTT_ifloor - #include - #define STBTT_ifloor(x) ((int) floor(x)) - #define STBTT_iceil(x) ((int) ceil(x)) - #endif - - #ifndef STBTT_sqrt - #include - #define STBTT_sqrt(x) sqrt(x) - #endif - - // #define your own functions "STBTT_malloc" / "STBTT_free" to avoid malloc.h - #ifndef STBTT_malloc - #include - #define STBTT_malloc(x,u) ((void)(u),malloc(x)) - #define STBTT_free(x,u) ((void)(u),free(x)) - #endif - - #ifndef STBTT_assert - #include - #define STBTT_assert(x) assert(x) - #endif - - #ifndef STBTT_strlen - #include - #define STBTT_strlen(x) strlen(x) - #endif - - #ifndef STBTT_memcpy - #include - #define STBTT_memcpy memcpy - #define STBTT_memset memset - #endif -#endif - -/////////////////////////////////////////////////////////////////////////////// -/////////////////////////////////////////////////////////////////////////////// -//// -//// INTERFACE -//// -//// - -#ifndef __STB_INCLUDE_STB_TRUETYPE_H__ -#define __STB_INCLUDE_STB_TRUETYPE_H__ - -#ifdef STBTT_STATIC -#define STBTT_DEF static -#else -#define STBTT_DEF extern -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -////////////////////////////////////////////////////////////////////////////// -// -// TEXTURE BAKING API -// -// If you use this API, you only have to call two functions ever. -// - -typedef struct -{ - unsigned short x0,y0,x1,y1; // coordinates of bbox in bitmap - float xoff,yoff,xadvance; -} stbtt_bakedchar; - -STBTT_DEF int stbtt_BakeFontBitmap(const unsigned char *data, int offset, // font location (use offset=0 for plain .ttf) - float pixel_height, // height of font in pixels - unsigned char *pixels, int pw, int ph, // bitmap to be filled in - int first_char, int num_chars, // characters to bake - stbtt_bakedchar *chardata); // you allocate this, it's num_chars long -// if return is positive, the first unused row of the bitmap -// if return is negative, returns the negative of the number of characters that fit -// if return is 0, no characters fit and no rows were used -// This uses a very crappy packing. - -typedef struct -{ - float x0,y0,s0,t0; // top-left - float x1,y1,s1,t1; // bottom-right -} stbtt_aligned_quad; - -STBTT_DEF void stbtt_GetBakedQuad(stbtt_bakedchar *chardata, int pw, int ph, // same data as above - int char_index, // character to display - float *xpos, float *ypos, // pointers to current position in screen pixel space - stbtt_aligned_quad *q, // output: quad to draw - int opengl_fillrule); // true if opengl fill rule; false if DX9 or earlier -// Call GetBakedQuad with char_index = 'character - first_char', and it -// creates the quad you need to draw and advances the current position. -// -// The coordinate system used assumes y increases downwards. -// -// Characters will extend both above and below the current position; -// see discussion of "BASELINE" above. -// -// It's inefficient; you might want to c&p it and optimize it. - -STBTT_DEF void stbtt_GetBakedQuadUnrounded(stbtt_bakedchar *chardata, int pw, int ph, - int char_index, float *xpos, float *ypos, - stbtt_aligned_quad *q, int opengl_fillrule); -// Works just as stbtt_GetBakedQuad but does not round the x,y coordinates q to the pixels - -////////////////////////////////////////////////////////////////////////////// -// -// NEW TEXTURE BAKING API -// -// This provides options for packing multiple fonts into one atlas, not -// perfectly but better than nothing. - -typedef struct -{ - unsigned short x0,y0,x1,y1; // coordinates of bbox in bitmap - float xoff,yoff,xadvance; - float xoff2,yoff2; -} stbtt_packedchar; - -typedef struct stbtt_pack_context stbtt_pack_context; - -STBTT_DEF int stbtt_PackBegin(stbtt_pack_context *spc, unsigned char *pixels, int width, int height, int stride_in_bytes, int padding, void *alloc_context); -// Initializes a packing context stored in the passed-in stbtt_pack_context. -// Future calls using this context will pack characters into the bitmap passed -// in here: a 1-channel bitmap that is weight x height. stride_in_bytes is -// the distance from one row to the next (or 0 to mean they are packed tightly -// together). "padding" is // the amount of padding to leave between each -// character (normally you want '1' for bitmaps you'll use as textures with -// bilinear filtering). -// -// Returns 0 on failure, 1 on success. - -STBTT_DEF void stbtt_PackEnd (stbtt_pack_context *spc); -// Cleans up the packing context and frees all memory. - -#define STBTT_POINT_SIZE(x) (-(x)) - -STBTT_DEF int stbtt_PackFontRange(stbtt_pack_context *spc, unsigned char *fontdata, int font_index, float font_size, - int first_unicode_char_in_range, int num_chars_in_range, stbtt_packedchar *chardata_for_range); -// Creates character bitmaps from the font_index'th font found in fontdata (use -// font_index=0 if you don't know what that is). It creates num_chars_in_range -// bitmaps for characters with unicode values starting at first_unicode_char_in_range -// and increasing. Data for how to render them is stored in chardata_for_range; -// pass these to stbtt_GetPackedQuad to get back renderable quads. -// -// font_size is the full height of the character from ascender to descender, -// as computed by stbtt_ScaleForPixelHeight. To use a point size as computed -// by stbtt_ScaleForMappingEmToPixels, wrap the point size in STBTT_POINT_SIZE() -// and pass that result as 'font_size': -// ..., 20 , ... // font max minus min y is 20 pixels tall -// ..., STBTT_POINT_SIZE(20), ... // 'M' is 20 pixels tall - -typedef struct -{ - float font_size; - int first_unicode_char_in_range; - int num_chars_in_range; - stbtt_packedchar *chardata_for_range; // output -} stbtt_pack_range; - -STBTT_DEF int stbtt_PackFontRanges(stbtt_pack_context *spc, unsigned char *fontdata, int font_index, stbtt_pack_range *ranges, int num_ranges); -// Creates character bitmaps from multiple ranges of characters stored in -// ranges. This will usually create a better-packed bitmap than multiple -// calls to stbtt_PackFontRange. - - -STBTT_DEF void stbtt_PackSetOversampling(stbtt_pack_context *spc, unsigned int h_oversample, unsigned int v_oversample); -// Oversampling a font increases the quality by allowing higher-quality subpixel -// positioning, and is especially valuable at smaller text sizes. -// -// This function sets the amount of oversampling for all following calls to -// stbtt_PackFontRange(s). The default (no oversampling) is achieved by -// h_oversample=1, v_oversample=1. The total number of pixels required is -// h_oversample*v_oversample larger than the default; for example, 2x2 -// oversampling requires 4x the storage of 1x1. For best results, render -// oversampled textures with bilinear filtering. Look at the readme in -// stb/tests/oversample for information about oversampled fonts - -STBTT_DEF void stbtt_GetPackedQuad(stbtt_packedchar *chardata, int pw, int ph, // same data as above - int char_index, // character to display - float *xpos, float *ypos, // pointers to current position in screen pixel space - stbtt_aligned_quad *q, // output: quad to draw - int align_to_integer); - -// this is an opaque structure that you shouldn't mess with which holds -// all the context needed from PackBegin to PackEnd. -struct stbtt_pack_context { - void *user_allocator_context; - void *pack_info; - int width; - int height; - int stride_in_bytes; - int padding; - unsigned int h_oversample, v_oversample; - unsigned char *pixels; - void *nodes; -}; - -////////////////////////////////////////////////////////////////////////////// -// -// FONT LOADING -// -// - -STBTT_DEF int stbtt_GetFontOffsetForIndex(const unsigned char *data, int index); -// Each .ttf/.ttc file may have more than one font. Each font has a sequential -// index number starting from 0. Call this function to get the font offset for -// a given index; it returns -1 if the index is out of range. A regular .ttf -// file will only define one font and it always be at offset 0, so it will -// return '0' for index 0, and -1 for all other indices. You can just skip -// this step if you know it's that kind of font. - - -// The following structure is defined publically so you can declare one on -// the stack or as a global or etc, but you should treat it as opaque. -typedef struct stbtt_fontinfo -{ - void * userdata; - unsigned char * data; // pointer to .ttf file - int fontstart; // offset of start of font - - int numGlyphs; // number of glyphs, needed for range checking - - int loca,head,glyf,hhea,hmtx,kern; // table locations as offset from start of .ttf - int index_map; // a cmap mapping for our chosen character encoding - int indexToLocFormat; // format needed to map from glyph index to glyph -} stbtt_fontinfo; - -STBTT_DEF int stbtt_InitFont(stbtt_fontinfo *info, const unsigned char *data, int offset); -// Given an offset into the file that defines a font, this function builds -// the necessary cached info for the rest of the system. You must allocate -// the stbtt_fontinfo yourself, and stbtt_InitFont will fill it out. You don't -// need to do anything special to free it, because the contents are pure -// value data with no additional data structures. Returns 0 on failure. - - -////////////////////////////////////////////////////////////////////////////// -// -// CHARACTER TO GLYPH-INDEX CONVERSIOn - -STBTT_DEF int stbtt_FindGlyphIndex(const stbtt_fontinfo *info, int unicode_codepoint); -// If you're going to perform multiple operations on the same character -// and you want a speed-up, call this function with the character you're -// going to process, then use glyph-based functions instead of the -// codepoint-based functions. - - -////////////////////////////////////////////////////////////////////////////// -// -// CHARACTER PROPERTIES -// - -STBTT_DEF float stbtt_ScaleForPixelHeight(const stbtt_fontinfo *info, float pixels); -// computes a scale factor to produce a font whose "height" is 'pixels' tall. -// Height is measured as the distance from the highest ascender to the lowest -// descender; in other words, it's equivalent to calling stbtt_GetFontVMetrics -// and computing: -// scale = pixels / (ascent - descent) -// so if you prefer to measure height by the ascent only, use a similar calculation. - -STBTT_DEF float stbtt_ScaleForMappingEmToPixels(const stbtt_fontinfo *info, float pixels); -// computes a scale factor to produce a font whose EM size is mapped to -// 'pixels' tall. This is probably what traditional APIs compute, but -// I'm not positive. - -STBTT_DEF void stbtt_GetFontVMetrics(const stbtt_fontinfo *info, int *ascent, int *descent, int *lineGap); -// ascent is the coordinate above the baseline the font extends; descent -// is the coordinate below the baseline the font extends (i.e. it is typically negative) -// lineGap is the spacing between one row's descent and the next row's ascent... -// so you should advance the vertical position by "*ascent - *descent + *lineGap" -// these are expressed in unscaled coordinates, so you must multiply by -// the scale factor for a given size - -STBTT_DEF void stbtt_GetFontBoundingBox(const stbtt_fontinfo *info, int *x0, int *y0, int *x1, int *y1); -// the bounding box around all possible characters - -STBTT_DEF void stbtt_GetCodepointHMetrics(const stbtt_fontinfo *info, int codepoint, int *advanceWidth, int *leftSideBearing); -// leftSideBearing is the offset from the current horizontal position to the left edge of the character -// advanceWidth is the offset from the current horizontal position to the next horizontal position -// these are expressed in unscaled coordinates - -STBTT_DEF int stbtt_GetCodepointKernAdvance(const stbtt_fontinfo *info, int ch1, int ch2); -// an additional amount to add to the 'advance' value between ch1 and ch2 - -STBTT_DEF int stbtt_GetCodepointBox(const stbtt_fontinfo *info, int codepoint, int *x0, int *y0, int *x1, int *y1); -// Gets the bounding box of the visible part of the glyph, in unscaled coordinates - -STBTT_DEF void stbtt_GetGlyphHMetrics(const stbtt_fontinfo *info, int glyph_index, int *advanceWidth, int *leftSideBearing); -STBTT_DEF int stbtt_GetGlyphKernAdvance(const stbtt_fontinfo *info, int glyph1, int glyph2); -STBTT_DEF int stbtt_GetGlyphBox(const stbtt_fontinfo *info, int glyph_index, int *x0, int *y0, int *x1, int *y1); -// as above, but takes one or more glyph indices for greater efficiency - - -////////////////////////////////////////////////////////////////////////////// -// -// GLYPH SHAPES (you probably don't need these, but they have to go before -// the bitmaps for C declaration-order reasons) -// - -#ifndef STBTT_vmove // you can predefine these to use different values (but why?) - enum { - STBTT_vmove=1, - STBTT_vline, - STBTT_vcurve - }; -#endif - -#ifndef stbtt_vertex // you can predefine this to use different values - // (we share this with other code at RAD) - #define stbtt_vertex_type short // can't use stbtt_int16 because that's not visible in the header file - typedef struct - { - stbtt_vertex_type x,y,cx,cy; - unsigned char type,padding; - } stbtt_vertex; -#endif - -STBTT_DEF int stbtt_IsGlyphEmpty(const stbtt_fontinfo *info, int glyph_index); -// returns non-zero if nothing is drawn for this glyph - -STBTT_DEF int stbtt_GetCodepointShape(const stbtt_fontinfo *info, int unicode_codepoint, stbtt_vertex **vertices); -STBTT_DEF int stbtt_GetGlyphShape(const stbtt_fontinfo *info, int glyph_index, stbtt_vertex **vertices); -// returns # of vertices and fills *vertices with the pointer to them -// these are expressed in "unscaled" coordinates -// -// The shape is a series of countours. Each one starts with -// a STBTT_moveto, then consists of a series of mixed -// STBTT_lineto and STBTT_curveto segments. A lineto -// draws a line from previous endpoint to its x,y; a curveto -// draws a quadratic bezier from previous endpoint to -// its x,y, using cx,cy as the bezier control point. - -STBTT_DEF void stbtt_FreeShape(const stbtt_fontinfo *info, stbtt_vertex *vertices); -// frees the data allocated above - -////////////////////////////////////////////////////////////////////////////// -// -// BITMAP RENDERING -// - -STBTT_DEF void stbtt_FreeBitmap(unsigned char *bitmap, void *userdata); -// frees the bitmap allocated below - -STBTT_DEF unsigned char *stbtt_GetCodepointBitmap(const stbtt_fontinfo *info, float scale_x, float scale_y, int codepoint, int *width, int *height, int *xoff, int *yoff); -// allocates a large-enough single-channel 8bpp bitmap and renders the -// specified character/glyph at the specified scale into it, with -// antialiasing. 0 is no coverage (transparent), 255 is fully covered (opaque). -// *width & *height are filled out with the width & height of the bitmap, -// which is stored left-to-right, top-to-bottom. -// -// xoff/yoff are the offset it pixel space from the glyph origin to the top-left of the bitmap - -STBTT_DEF unsigned char *stbtt_GetCodepointBitmapSubpixel(const stbtt_fontinfo *info, float scale_x, float scale_y, float shift_x, float shift_y, int codepoint, int *width, int *height, int *xoff, int *yoff); -// the same as stbtt_GetCodepoitnBitmap, but you can specify a subpixel -// shift for the character - -STBTT_DEF void stbtt_MakeCodepointBitmap(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, int codepoint); -// the same as stbtt_GetCodepointBitmap, but you pass in storage for the bitmap -// in the form of 'output', with row spacing of 'out_stride' bytes. the bitmap -// is clipped to out_w/out_h bytes. Call stbtt_GetCodepointBitmapBox to get the -// width and height and positioning info for it first. - -STBTT_DEF void stbtt_MakeCodepointBitmapSubpixel(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int codepoint); -// same as stbtt_MakeCodepointBitmap, but you can specify a subpixel -// shift for the character - -STBTT_DEF void stbtt_GetCodepointBitmapBox(const stbtt_fontinfo *font, int codepoint, float scale_x, float scale_y, int *ix0, int *iy0, int *ix1, int *iy1); -// get the bbox of the bitmap centered around the glyph origin; so the -// bitmap width is ix1-ix0, height is iy1-iy0, and location to place -// the bitmap top left is (leftSideBearing*scale,iy0). -// (Note that the bitmap uses y-increases-down, but the shape uses -// y-increases-up, so CodepointBitmapBox and CodepointBox are inverted.) - -STBTT_DEF void stbtt_GetCodepointBitmapBoxSubpixel(const stbtt_fontinfo *font, int codepoint, float scale_x, float scale_y, float shift_x, float shift_y, int *ix0, int *iy0, int *ix1, int *iy1); -// same as stbtt_GetCodepointBitmapBox, but you can specify a subpixel -// shift for the character - -// the following functions are equivalent to the above functions, but operate -// on glyph indices instead of Unicode codepoints (for efficiency) -STBTT_DEF unsigned char *stbtt_GetGlyphBitmap(const stbtt_fontinfo *info, float scale_x, float scale_y, int glyph, int *width, int *height, int *xoff, int *yoff); -STBTT_DEF unsigned char *stbtt_GetGlyphBitmapSubpixel(const stbtt_fontinfo *info, float scale_x, float scale_y, float shift_x, float shift_y, int glyph, int *width, int *height, int *xoff, int *yoff); -STBTT_DEF void stbtt_MakeGlyphBitmap(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, int glyph); -STBTT_DEF void stbtt_MakeGlyphBitmapSubpixel(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int glyph); -STBTT_DEF void stbtt_GetGlyphBitmapBox(const stbtt_fontinfo *font, int glyph, float scale_x, float scale_y, int *ix0, int *iy0, int *ix1, int *iy1); -STBTT_DEF void stbtt_GetGlyphBitmapBoxSubpixel(const stbtt_fontinfo *font, int glyph, float scale_x, float scale_y,float shift_x, float shift_y, int *ix0, int *iy0, int *ix1, int *iy1); - - -// @TODO: don't expose this structure -typedef struct -{ - int w,h,stride; - unsigned char *pixels; -} stbtt__bitmap; - -STBTT_DEF void stbtt_Rasterize(stbtt__bitmap *result, float flatness_in_pixels, stbtt_vertex *vertices, int num_verts, float scale_x, float scale_y, float shift_x, float shift_y, int x_off, int y_off, int invert, void *userdata); - -////////////////////////////////////////////////////////////////////////////// -// -// Finding the right font... -// -// You should really just solve this offline, keep your own tables -// of what font is what, and don't try to get it out of the .ttf file. -// That's because getting it out of the .ttf file is really hard, because -// the names in the file can appear in many possible encodings, in many -// possible languages, and e.g. if you need a case-insensitive comparison, -// the details of that depend on the encoding & language in a complex way -// (actually underspecified in truetype, but also gigantic). -// -// But you can use the provided functions in two possible ways: -// stbtt_FindMatchingFont() will use *case-sensitive* comparisons on -// unicode-encoded names to try to find the font you want; -// you can run this before calling stbtt_InitFont() -// -// stbtt_GetFontNameString() lets you get any of the various strings -// from the file yourself and do your own comparisons on them. -// You have to have called stbtt_InitFont() first. - - -STBTT_DEF int stbtt_FindMatchingFont(const unsigned char *fontdata, const char *name, int flags); -// returns the offset (not index) of the font that matches, or -1 if none -// if you use STBTT_MACSTYLE_DONTCARE, use a font name like "Arial Bold". -// if you use any other flag, use a font name like "Arial"; this checks -// the 'macStyle' header field; i don't know if fonts set this consistently -#define STBTT_MACSTYLE_DONTCARE 0 -#define STBTT_MACSTYLE_BOLD 1 -#define STBTT_MACSTYLE_ITALIC 2 -#define STBTT_MACSTYLE_UNDERSCORE 4 -#define STBTT_MACSTYLE_NONE 8 // <= not same as 0, this makes us check the bitfield is 0 - -STBTT_DEF int stbtt_CompareUTF8toUTF16_bigendian(const char *s1, int len1, const char *s2, int len2); -// returns 1/0 whether the first string interpreted as utf8 is identical to -// the second string interpreted as big-endian utf16... useful for strings from next func - -STBTT_DEF const char *stbtt_GetFontNameString(const stbtt_fontinfo *font, int *length, int platformID, int encodingID, int languageID, int nameID); -// returns the string (which may be big-endian double byte, e.g. for unicode) -// and puts the length in bytes in *length. -// -// some of the values for the IDs are below; for more see the truetype spec: -// http://developer.apple.com/textfonts/TTRefMan/RM06/Chap6name.html -// http://www.microsoft.com/typography/otspec/name.htm - -enum { // platformID - STBTT_PLATFORM_ID_UNICODE =0, - STBTT_PLATFORM_ID_MAC =1, - STBTT_PLATFORM_ID_ISO =2, - STBTT_PLATFORM_ID_MICROSOFT =3 -}; - -enum { // encodingID for STBTT_PLATFORM_ID_UNICODE - STBTT_UNICODE_EID_UNICODE_1_0 =0, - STBTT_UNICODE_EID_UNICODE_1_1 =1, - STBTT_UNICODE_EID_ISO_10646 =2, - STBTT_UNICODE_EID_UNICODE_2_0_BMP=3, - STBTT_UNICODE_EID_UNICODE_2_0_FULL=4 -}; - -enum { // encodingID for STBTT_PLATFORM_ID_MICROSOFT - STBTT_MS_EID_SYMBOL =0, - STBTT_MS_EID_UNICODE_BMP =1, - STBTT_MS_EID_SHIFTJIS =2, - STBTT_MS_EID_UNICODE_FULL =10 -}; - -enum { // encodingID for STBTT_PLATFORM_ID_MAC; same as Script Manager codes - STBTT_MAC_EID_ROMAN =0, STBTT_MAC_EID_ARABIC =4, - STBTT_MAC_EID_JAPANESE =1, STBTT_MAC_EID_HEBREW =5, - STBTT_MAC_EID_CHINESE_TRAD =2, STBTT_MAC_EID_GREEK =6, - STBTT_MAC_EID_KOREAN =3, STBTT_MAC_EID_RUSSIAN =7 -}; - -enum { // languageID for STBTT_PLATFORM_ID_MICROSOFT; same as LCID... - // problematic because there are e.g. 16 english LCIDs and 16 arabic LCIDs - STBTT_MS_LANG_ENGLISH =0x0409, STBTT_MS_LANG_ITALIAN =0x0410, - STBTT_MS_LANG_CHINESE =0x0804, STBTT_MS_LANG_JAPANESE =0x0411, - STBTT_MS_LANG_DUTCH =0x0413, STBTT_MS_LANG_KOREAN =0x0412, - STBTT_MS_LANG_FRENCH =0x040c, STBTT_MS_LANG_RUSSIAN =0x0419, - STBTT_MS_LANG_GERMAN =0x0407, STBTT_MS_LANG_SPANISH =0x0409, - STBTT_MS_LANG_HEBREW =0x040d, STBTT_MS_LANG_SWEDISH =0x041D -}; - -enum { // languageID for STBTT_PLATFORM_ID_MAC - STBTT_MAC_LANG_ENGLISH =0 , STBTT_MAC_LANG_JAPANESE =11, - STBTT_MAC_LANG_ARABIC =12, STBTT_MAC_LANG_KOREAN =23, - STBTT_MAC_LANG_DUTCH =4 , STBTT_MAC_LANG_RUSSIAN =32, - STBTT_MAC_LANG_FRENCH =1 , STBTT_MAC_LANG_SPANISH =6 , - STBTT_MAC_LANG_GERMAN =2 , STBTT_MAC_LANG_SWEDISH =5 , - STBTT_MAC_LANG_HEBREW =10, STBTT_MAC_LANG_CHINESE_SIMPLIFIED =33, - STBTT_MAC_LANG_ITALIAN =3 , STBTT_MAC_LANG_CHINESE_TRAD =19 -}; - -#ifdef __cplusplus -} -#endif - -#endif // __STB_INCLUDE_STB_TRUETYPE_H__ - -/////////////////////////////////////////////////////////////////////////////// -/////////////////////////////////////////////////////////////////////////////// -//// -//// IMPLEMENTATION -//// -//// - -#ifdef STB_TRUETYPE_IMPLEMENTATION - -#ifndef STBTT_MAX_OVERSAMPLE -#define STBTT_MAX_OVERSAMPLE 8 -#endif - -typedef int stbtt__test_oversample_pow2[(STBTT_MAX_OVERSAMPLE & (STBTT_MAX_OVERSAMPLE-1)) == 0 ? 1 : -1]; - -////////////////////////////////////////////////////////////////////////// -// -// accessors to parse data from file -// - -// on platforms that don't allow misaligned reads, if we want to allow -// truetype fonts that aren't padded to alignment, define ALLOW_UNALIGNED_TRUETYPE - -#define ttBYTE(p) (* (stbtt_uint8 *) (p)) -#define ttCHAR(p) (* (stbtt_int8 *) (p)) -#define ttFixed(p) ttLONG(p) - -#if defined(STB_TRUETYPE_BIGENDIAN) && !defined(ALLOW_UNALIGNED_TRUETYPE) - - #define ttUSHORT(p) (* (stbtt_uint16 *) (p)) - #define ttSHORT(p) (* (stbtt_int16 *) (p)) - #define ttULONG(p) (* (stbtt_uint32 *) (p)) - #define ttLONG(p) (* (stbtt_int32 *) (p)) - -#else - - static stbtt_uint16 ttUSHORT(const stbtt_uint8 *p) { return p[0]*256 + p[1]; } - static stbtt_int16 ttSHORT(const stbtt_uint8 *p) { return p[0]*256 + p[1]; } - static stbtt_uint32 ttULONG(const stbtt_uint8 *p) { return (p[0]<<24) + (p[1]<<16) + (p[2]<<8) + p[3]; } - static stbtt_int32 ttLONG(const stbtt_uint8 *p) { return (p[0]<<24) + (p[1]<<16) + (p[2]<<8) + p[3]; } - -#endif - -#define stbtt_tag4(p,c0,c1,c2,c3) ((p)[0] == (c0) && (p)[1] == (c1) && (p)[2] == (c2) && (p)[3] == (c3)) -#define stbtt_tag(p,str) stbtt_tag4(p,str[0],str[1],str[2],str[3]) - -static int stbtt__isfont(const stbtt_uint8 *font) -{ - // check the version number - if (stbtt_tag4(font, '1',0,0,0)) return 1; // TrueType 1 - if (stbtt_tag(font, "typ1")) return 1; // TrueType with type 1 font -- we don't support this! - if (stbtt_tag(font, "OTTO")) return 1; // OpenType with CFF - if (stbtt_tag4(font, 0,1,0,0)) return 1; // OpenType 1.0 - return 0; -} - -// @OPTIMIZE: binary search -static stbtt_uint32 stbtt__find_table(stbtt_uint8 *data, stbtt_uint32 fontstart, const char *tag) -{ - stbtt_int32 num_tables = ttUSHORT(data+fontstart+4); - stbtt_uint32 tabledir = fontstart + 12; - stbtt_int32 i; - for (i=0; i < num_tables; ++i) { - stbtt_uint32 loc = tabledir + 16*i; - if (stbtt_tag(data+loc+0, tag)) - return ttULONG(data+loc+8); - } - return 0; -} - -STBTT_DEF int stbtt_GetFontOffsetForIndex(const unsigned char *font_collection, int index) -{ - // if it's just a font, there's only one valid index - if (stbtt__isfont(font_collection)) - return index == 0 ? 0 : -1; - - // check if it's a TTC - if (stbtt_tag(font_collection, "ttcf")) { - // version 1? - if (ttULONG(font_collection+4) == 0x00010000 || ttULONG(font_collection+4) == 0x00020000) { - stbtt_int32 n = ttLONG(font_collection+8); - if (index >= n) - return -1; - return ttULONG(font_collection+12+index*14); - } - } - return -1; -} - -STBTT_DEF int stbtt_InitFont(stbtt_fontinfo *info, const unsigned char *data2, int fontstart) -{ - stbtt_uint8 *data = (stbtt_uint8 *) data2; - stbtt_uint32 cmap, t; - stbtt_int32 i,numTables; - - info->data = data; - info->fontstart = fontstart; - - cmap = stbtt__find_table(data, fontstart, "cmap"); // required - info->loca = stbtt__find_table(data, fontstart, "loca"); // required - info->head = stbtt__find_table(data, fontstart, "head"); // required - info->glyf = stbtt__find_table(data, fontstart, "glyf"); // required - info->hhea = stbtt__find_table(data, fontstart, "hhea"); // required - info->hmtx = stbtt__find_table(data, fontstart, "hmtx"); // required - info->kern = stbtt__find_table(data, fontstart, "kern"); // not required - if (!cmap || !info->loca || !info->head || !info->glyf || !info->hhea || !info->hmtx) - return 0; - - t = stbtt__find_table(data, fontstart, "maxp"); - if (t) - info->numGlyphs = ttUSHORT(data+t+4); - else - info->numGlyphs = 0xffff; - - // find a cmap encoding table we understand *now* to avoid searching - // later. (todo: could make this installable) - // the same regardless of glyph. - numTables = ttUSHORT(data + cmap + 2); - info->index_map = 0; - for (i=0; i < numTables; ++i) { - stbtt_uint32 encoding_record = cmap + 4 + 8 * i; - // find an encoding we understand: - switch(ttUSHORT(data+encoding_record)) { - case STBTT_PLATFORM_ID_MICROSOFT: - switch (ttUSHORT(data+encoding_record+2)) { - case STBTT_MS_EID_UNICODE_BMP: - case STBTT_MS_EID_UNICODE_FULL: - // MS/Unicode - info->index_map = cmap + ttULONG(data+encoding_record+4); - break; - } - break; - case STBTT_PLATFORM_ID_UNICODE: - // Mac/iOS has these - // all the encodingIDs are unicode, so we don't bother to check it - info->index_map = cmap + ttULONG(data+encoding_record+4); - break; - } - } - if (info->index_map == 0) - return 0; - - info->indexToLocFormat = ttUSHORT(data+info->head + 50); - return 1; -} - -STBTT_DEF int stbtt_FindGlyphIndex(const stbtt_fontinfo *info, int unicode_codepoint) -{ - stbtt_uint8 *data = info->data; - stbtt_uint32 index_map = info->index_map; - - stbtt_uint16 format = ttUSHORT(data + index_map + 0); - if (format == 0) { // apple byte encoding - stbtt_int32 bytes = ttUSHORT(data + index_map + 2); - if (unicode_codepoint < bytes-6) - return ttBYTE(data + index_map + 6 + unicode_codepoint); - return 0; - } else if (format == 6) { - stbtt_uint32 first = ttUSHORT(data + index_map + 6); - stbtt_uint32 count = ttUSHORT(data + index_map + 8); - if ((stbtt_uint32) unicode_codepoint >= first && (stbtt_uint32) unicode_codepoint < first+count) - return ttUSHORT(data + index_map + 10 + (unicode_codepoint - first)*2); - return 0; - } else if (format == 2) { - STBTT_assert(0); // @TODO: high-byte mapping for japanese/chinese/korean - return 0; - } else if (format == 4) { // standard mapping for windows fonts: binary search collection of ranges - stbtt_uint16 segcount = ttUSHORT(data+index_map+6) >> 1; - stbtt_uint16 searchRange = ttUSHORT(data+index_map+8) >> 1; - stbtt_uint16 entrySelector = ttUSHORT(data+index_map+10); - stbtt_uint16 rangeShift = ttUSHORT(data+index_map+12) >> 1; - - // do a binary search of the segments - stbtt_uint32 endCount = index_map + 14; - stbtt_uint32 search = endCount; - - if (unicode_codepoint > 0xffff) - return 0; - - // they lie from endCount .. endCount + segCount - // but searchRange is the nearest power of two, so... - if (unicode_codepoint >= ttUSHORT(data + search + rangeShift*2)) - search += rangeShift*2; - - // now decrement to bias correctly to find smallest - search -= 2; - while (entrySelector) { - stbtt_uint16 end; - searchRange >>= 1; - end = ttUSHORT(data + search + searchRange*2); - if (unicode_codepoint > end) - search += searchRange*2; - --entrySelector; - } - search += 2; - - { - stbtt_uint16 offset, start; - stbtt_uint16 item = (stbtt_uint16) ((search - endCount) >> 1); - - STBTT_assert(unicode_codepoint <= ttUSHORT(data + endCount + 2*item)); - start = ttUSHORT(data + index_map + 14 + segcount*2 + 2 + 2*item); - if (unicode_codepoint < start) - return 0; - - offset = ttUSHORT(data + index_map + 14 + segcount*6 + 2 + 2*item); - if (offset == 0) - return (stbtt_uint16) (unicode_codepoint + ttSHORT(data + index_map + 14 + segcount*4 + 2 + 2*item)); - - return ttUSHORT(data + offset + (unicode_codepoint-start)*2 + index_map + 14 + segcount*6 + 2 + 2*item); - } - } else if (format == 12 || format == 13) { - stbtt_uint32 ngroups = ttULONG(data+index_map+12); - stbtt_int32 low,high; - low = 0; high = (stbtt_int32)ngroups; - // Binary search the right group. - while (low < high) { - stbtt_int32 mid = low + ((high-low) >> 1); // rounds down, so low <= mid < high - stbtt_uint32 start_char = ttULONG(data+index_map+16+mid*12); - stbtt_uint32 end_char = ttULONG(data+index_map+16+mid*12+4); - if ((stbtt_uint32) unicode_codepoint < start_char) - high = mid; - else if ((stbtt_uint32) unicode_codepoint > end_char) - low = mid+1; - else { - stbtt_uint32 start_glyph = ttULONG(data+index_map+16+mid*12+8); - if (format == 12) - return start_glyph + unicode_codepoint-start_char; - else // format == 13 - return start_glyph; - } - } - return 0; // not found - } - // @TODO - STBTT_assert(0); - return 0; -} - -STBTT_DEF int stbtt_GetCodepointShape(const stbtt_fontinfo *info, int unicode_codepoint, stbtt_vertex **vertices) -{ - return stbtt_GetGlyphShape(info, stbtt_FindGlyphIndex(info, unicode_codepoint), vertices); -} - -static void stbtt_setvertex(stbtt_vertex *v, stbtt_uint8 type, stbtt_int32 x, stbtt_int32 y, stbtt_int32 cx, stbtt_int32 cy) -{ - v->type = type; - v->x = (stbtt_int16) x; - v->y = (stbtt_int16) y; - v->cx = (stbtt_int16) cx; - v->cy = (stbtt_int16) cy; -} - -static int stbtt__GetGlyfOffset(const stbtt_fontinfo *info, int glyph_index) -{ - int g1,g2; - - if (glyph_index >= info->numGlyphs) return -1; // glyph index out of range - if (info->indexToLocFormat >= 2) return -1; // unknown index->glyph map format - - if (info->indexToLocFormat == 0) { - g1 = info->glyf + ttUSHORT(info->data + info->loca + glyph_index * 2) * 2; - g2 = info->glyf + ttUSHORT(info->data + info->loca + glyph_index * 2 + 2) * 2; - } else { - g1 = info->glyf + ttULONG (info->data + info->loca + glyph_index * 4); - g2 = info->glyf + ttULONG (info->data + info->loca + glyph_index * 4 + 4); - } - - return g1==g2 ? -1 : g1; // if length is 0, return -1 -} - -STBTT_DEF int stbtt_GetGlyphBox(const stbtt_fontinfo *info, int glyph_index, int *x0, int *y0, int *x1, int *y1) -{ - int g = stbtt__GetGlyfOffset(info, glyph_index); - if (g < 0) return 0; - - if (x0) *x0 = ttSHORT(info->data + g + 2); - if (y0) *y0 = ttSHORT(info->data + g + 4); - if (x1) *x1 = ttSHORT(info->data + g + 6); - if (y1) *y1 = ttSHORT(info->data + g + 8); - return 1; -} - -STBTT_DEF int stbtt_GetCodepointBox(const stbtt_fontinfo *info, int codepoint, int *x0, int *y0, int *x1, int *y1) -{ - return stbtt_GetGlyphBox(info, stbtt_FindGlyphIndex(info,codepoint), x0,y0,x1,y1); -} - -STBTT_DEF int stbtt_IsGlyphEmpty(const stbtt_fontinfo *info, int glyph_index) -{ - stbtt_int16 numberOfContours; - int g = stbtt__GetGlyfOffset(info, glyph_index); - if (g < 0) return 1; - numberOfContours = ttSHORT(info->data + g); - return numberOfContours == 0; -} - -static int stbtt__close_shape(stbtt_vertex *vertices, int num_vertices, int was_off, int start_off, - stbtt_int32 sx, stbtt_int32 sy, stbtt_int32 scx, stbtt_int32 scy, stbtt_int32 cx, stbtt_int32 cy) -{ - if (start_off) { - if (was_off) - stbtt_setvertex(&vertices[num_vertices++], STBTT_vcurve, (cx+scx)>>1, (cy+scy)>>1, cx,cy); - stbtt_setvertex(&vertices[num_vertices++], STBTT_vcurve, sx,sy,scx,scy); - } else { - if (was_off) - stbtt_setvertex(&vertices[num_vertices++], STBTT_vcurve,sx,sy,cx,cy); - else - stbtt_setvertex(&vertices[num_vertices++], STBTT_vline,sx,sy,0,0); - } - return num_vertices; -} - -STBTT_DEF int stbtt_GetGlyphShape(const stbtt_fontinfo *info, int glyph_index, stbtt_vertex **pvertices) -{ - stbtt_int16 numberOfContours; - stbtt_uint8 *endPtsOfContours; - stbtt_uint8 *data = info->data; - stbtt_vertex *vertices=0; - int num_vertices=0; - int g = stbtt__GetGlyfOffset(info, glyph_index); - - *pvertices = NULL; - - if (g < 0) return 0; - - numberOfContours = ttSHORT(data + g); - - if (numberOfContours > 0) { - stbtt_uint8 flags=0,flagcount; - stbtt_int32 ins, i,j=0,m,n, next_move, was_off=0, off, start_off=0; - stbtt_int32 x,y,cx,cy,sx,sy, scx,scy; - stbtt_uint8 *points; - endPtsOfContours = (data + g + 10); - ins = ttUSHORT(data + g + 10 + numberOfContours * 2); - points = data + g + 10 + numberOfContours * 2 + 2 + ins; - - n = 1+ttUSHORT(endPtsOfContours + numberOfContours*2-2); - - m = n + 2*numberOfContours; // a loose bound on how many vertices we might need - vertices = (stbtt_vertex *) STBTT_malloc(m * sizeof(vertices[0]), info->userdata); - if (vertices == 0) - return 0; - - next_move = 0; - flagcount=0; - - // in first pass, we load uninterpreted data into the allocated array - // above, shifted to the end of the array so we won't overwrite it when - // we create our final data starting from the front - - off = m - n; // starting offset for uninterpreted data, regardless of how m ends up being calculated - - // first load flags - - for (i=0; i < n; ++i) { - if (flagcount == 0) { - flags = *points++; - if (flags & 8) - flagcount = *points++; - } else - --flagcount; - vertices[off+i].type = flags; - } - - // now load x coordinates - x=0; - for (i=0; i < n; ++i) { - flags = vertices[off+i].type; - if (flags & 2) { - stbtt_int16 dx = *points++; - x += (flags & 16) ? dx : -dx; // ??? - } else { - if (!(flags & 16)) { - x = x + (stbtt_int16) (points[0]*256 + points[1]); - points += 2; - } - } - vertices[off+i].x = (stbtt_int16) x; - } - - // now load y coordinates - y=0; - for (i=0; i < n; ++i) { - flags = vertices[off+i].type; - if (flags & 4) { - stbtt_int16 dy = *points++; - y += (flags & 32) ? dy : -dy; // ??? - } else { - if (!(flags & 32)) { - y = y + (stbtt_int16) (points[0]*256 + points[1]); - points += 2; - } - } - vertices[off+i].y = (stbtt_int16) y; - } - - // now convert them to our format - num_vertices=0; - sx = sy = cx = cy = scx = scy = 0; - for (i=0; i < n; ++i) { - flags = vertices[off+i].type; - x = (stbtt_int16) vertices[off+i].x; - y = (stbtt_int16) vertices[off+i].y; - - if (next_move == i) { - if (i != 0) - num_vertices = stbtt__close_shape(vertices, num_vertices, was_off, start_off, sx,sy,scx,scy,cx,cy); - - // now start the new one - start_off = !(flags & 1); - if (start_off) { - // if we start off with an off-curve point, then when we need to find a point on the curve - // where we can start, and we need to save some state for when we wraparound. - scx = x; - scy = y; - if (!(vertices[off+i+1].type & 1)) { - // next point is also a curve point, so interpolate an on-point curve - sx = (x + (stbtt_int32) vertices[off+i+1].x) >> 1; - sy = (y + (stbtt_int32) vertices[off+i+1].y) >> 1; - } else { - // otherwise just use the next point as our start point - sx = (stbtt_int32) vertices[off+i+1].x; - sy = (stbtt_int32) vertices[off+i+1].y; - ++i; // we're using point i+1 as the starting point, so skip it - } - } else { - sx = x; - sy = y; - } - stbtt_setvertex(&vertices[num_vertices++], STBTT_vmove,sx,sy,0,0); - was_off = 0; - next_move = 1 + ttUSHORT(endPtsOfContours+j*2); - ++j; - } else { - if (!(flags & 1)) { // if it's a curve - if (was_off) // two off-curve control points in a row means interpolate an on-curve midpoint - stbtt_setvertex(&vertices[num_vertices++], STBTT_vcurve, (cx+x)>>1, (cy+y)>>1, cx, cy); - cx = x; - cy = y; - was_off = 1; - } else { - if (was_off) - stbtt_setvertex(&vertices[num_vertices++], STBTT_vcurve, x,y, cx, cy); - else - stbtt_setvertex(&vertices[num_vertices++], STBTT_vline, x,y,0,0); - was_off = 0; - } - } - } - num_vertices = stbtt__close_shape(vertices, num_vertices, was_off, start_off, sx,sy,scx,scy,cx,cy); - } else if (numberOfContours == -1) { - // Compound shapes. - int more = 1; - stbtt_uint8 *comp = data + g + 10; - num_vertices = 0; - vertices = 0; - while (more) { - stbtt_uint16 flags, gidx; - int comp_num_verts = 0, i; - stbtt_vertex *comp_verts = 0, *tmp = 0; - float mtx[6] = {1,0,0,1,0,0}, m, n; - - flags = ttSHORT(comp); comp+=2; - gidx = ttSHORT(comp); comp+=2; - - if (flags & 2) { // XY values - if (flags & 1) { // shorts - mtx[4] = ttSHORT(comp); comp+=2; - mtx[5] = ttSHORT(comp); comp+=2; - } else { - mtx[4] = ttCHAR(comp); comp+=1; - mtx[5] = ttCHAR(comp); comp+=1; - } - } - else { - // @TODO handle matching point - STBTT_assert(0); - } - if (flags & (1<<3)) { // WE_HAVE_A_SCALE - mtx[0] = mtx[3] = ttSHORT(comp)/16384.0f; comp+=2; - mtx[1] = mtx[2] = 0; - } else if (flags & (1<<6)) { // WE_HAVE_AN_X_AND_YSCALE - mtx[0] = ttSHORT(comp)/16384.0f; comp+=2; - mtx[1] = mtx[2] = 0; - mtx[3] = ttSHORT(comp)/16384.0f; comp+=2; - } else if (flags & (1<<7)) { // WE_HAVE_A_TWO_BY_TWO - mtx[0] = ttSHORT(comp)/16384.0f; comp+=2; - mtx[1] = ttSHORT(comp)/16384.0f; comp+=2; - mtx[2] = ttSHORT(comp)/16384.0f; comp+=2; - mtx[3] = ttSHORT(comp)/16384.0f; comp+=2; - } - - // Find transformation scales. - m = (float) STBTT_sqrt(mtx[0]*mtx[0] + mtx[1]*mtx[1]); - n = (float) STBTT_sqrt(mtx[2]*mtx[2] + mtx[3]*mtx[3]); - - // Get indexed glyph. - comp_num_verts = stbtt_GetGlyphShape(info, gidx, &comp_verts); - if (comp_num_verts > 0) { - // Transform vertices. - for (i = 0; i < comp_num_verts; ++i) { - stbtt_vertex* v = &comp_verts[i]; - stbtt_vertex_type x,y; - x=v->x; y=v->y; - v->x = (stbtt_vertex_type)(m * (mtx[0]*x + mtx[2]*y + mtx[4])); - v->y = (stbtt_vertex_type)(n * (mtx[1]*x + mtx[3]*y + mtx[5])); - x=v->cx; y=v->cy; - v->cx = (stbtt_vertex_type)(m * (mtx[0]*x + mtx[2]*y + mtx[4])); - v->cy = (stbtt_vertex_type)(n * (mtx[1]*x + mtx[3]*y + mtx[5])); - } - // Append vertices. - tmp = (stbtt_vertex*)STBTT_malloc((num_vertices+comp_num_verts)*sizeof(stbtt_vertex), info->userdata); - if (!tmp) { - if (vertices) STBTT_free(vertices, info->userdata); - if (comp_verts) STBTT_free(comp_verts, info->userdata); - return 0; - } - if (num_vertices > 0) STBTT_memcpy(tmp, vertices, num_vertices*sizeof(stbtt_vertex)); - STBTT_memcpy(tmp+num_vertices, comp_verts, comp_num_verts*sizeof(stbtt_vertex)); - if (vertices) STBTT_free(vertices, info->userdata); - vertices = tmp; - STBTT_free(comp_verts, info->userdata); - num_vertices += comp_num_verts; - } - // More components ? - more = flags & (1<<5); - } - } else if (numberOfContours < 0) { - // @TODO other compound variations? - STBTT_assert(0); - } else { - // numberOfCounters == 0, do nothing - } - - *pvertices = vertices; - return num_vertices; -} - -STBTT_DEF void stbtt_GetGlyphHMetrics(const stbtt_fontinfo *info, int glyph_index, int *advanceWidth, int *leftSideBearing) -{ - stbtt_uint16 numOfLongHorMetrics = ttUSHORT(info->data+info->hhea + 34); - if (glyph_index < numOfLongHorMetrics) { - if (advanceWidth) *advanceWidth = ttSHORT(info->data + info->hmtx + 4*glyph_index); - if (leftSideBearing) *leftSideBearing = ttSHORT(info->data + info->hmtx + 4*glyph_index + 2); - } else { - if (advanceWidth) *advanceWidth = ttSHORT(info->data + info->hmtx + 4*(numOfLongHorMetrics-1)); - if (leftSideBearing) *leftSideBearing = ttSHORT(info->data + info->hmtx + 4*numOfLongHorMetrics + 2*(glyph_index - numOfLongHorMetrics)); - } -} - -STBTT_DEF int stbtt_GetGlyphKernAdvance(const stbtt_fontinfo *info, int glyph1, int glyph2) -{ - stbtt_uint8 *data = info->data + info->kern; - stbtt_uint32 needle, straw; - int l, r, m; - - // we only look at the first table. it must be 'horizontal' and format 0. - if (!info->kern) - return 0; - if (ttUSHORT(data+2) < 1) // number of tables, need at least 1 - return 0; - if (ttUSHORT(data+8) != 1) // horizontal flag must be set in format - return 0; - - l = 0; - r = ttUSHORT(data+10) - 1; - needle = glyph1 << 16 | glyph2; - while (l <= r) { - m = (l + r) >> 1; - straw = ttULONG(data+18+(m*6)); // note: unaligned read - if (needle < straw) - r = m - 1; - else if (needle > straw) - l = m + 1; - else - return ttSHORT(data+22+(m*6)); - } - return 0; -} - -STBTT_DEF int stbtt_GetCodepointKernAdvance(const stbtt_fontinfo *info, int ch1, int ch2) -{ - if (!info->kern) // if no kerning table, don't waste time looking up both codepoint->glyphs - return 0; - return stbtt_GetGlyphKernAdvance(info, stbtt_FindGlyphIndex(info,ch1), stbtt_FindGlyphIndex(info,ch2)); -} - -STBTT_DEF void stbtt_GetCodepointHMetrics(const stbtt_fontinfo *info, int codepoint, int *advanceWidth, int *leftSideBearing) -{ - stbtt_GetGlyphHMetrics(info, stbtt_FindGlyphIndex(info,codepoint), advanceWidth, leftSideBearing); -} - -STBTT_DEF void stbtt_GetFontVMetrics(const stbtt_fontinfo *info, int *ascent, int *descent, int *lineGap) -{ - if (ascent ) *ascent = ttSHORT(info->data+info->hhea + 4); - if (descent) *descent = ttSHORT(info->data+info->hhea + 6); - if (lineGap) *lineGap = ttSHORT(info->data+info->hhea + 8); -} - -STBTT_DEF void stbtt_GetFontBoundingBox(const stbtt_fontinfo *info, int *x0, int *y0, int *x1, int *y1) -{ - *x0 = ttSHORT(info->data + info->head + 36); - *y0 = ttSHORT(info->data + info->head + 38); - *x1 = ttSHORT(info->data + info->head + 40); - *y1 = ttSHORT(info->data + info->head + 42); -} - -STBTT_DEF float stbtt_ScaleForPixelHeight(const stbtt_fontinfo *info, float height) -{ - int fheight = ttSHORT(info->data + info->hhea + 4) - ttSHORT(info->data + info->hhea + 6); - return (float) height / fheight; -} - -STBTT_DEF float stbtt_ScaleForMappingEmToPixels(const stbtt_fontinfo *info, float pixels) -{ - int unitsPerEm = ttUSHORT(info->data + info->head + 18); - return pixels / unitsPerEm; -} - -STBTT_DEF void stbtt_FreeShape(const stbtt_fontinfo *info, stbtt_vertex *v) -{ - STBTT_free(v, info->userdata); -} - -////////////////////////////////////////////////////////////////////////////// -// -// antialiasing software rasterizer -// - -STBTT_DEF void stbtt_GetGlyphBitmapBoxSubpixel(const stbtt_fontinfo *font, int glyph, float scale_x, float scale_y,float shift_x, float shift_y, int *ix0, int *iy0, int *ix1, int *iy1) -{ - int x0,y0,x1,y1; - if (!stbtt_GetGlyphBox(font, glyph, &x0,&y0,&x1,&y1)) { - // e.g. space character - if (ix0) *ix0 = 0; - if (iy0) *iy0 = 0; - if (ix1) *ix1 = 0; - if (iy1) *iy1 = 0; - } else { - // move to integral bboxes (treating pixels as little squares, what pixels get touched)? - if (ix0) *ix0 = STBTT_ifloor( x0 * scale_x + shift_x); - if (iy0) *iy0 = STBTT_ifloor(-y1 * scale_y + shift_y); - if (ix1) *ix1 = STBTT_iceil ( x1 * scale_x + shift_x); - if (iy1) *iy1 = STBTT_iceil (-y0 * scale_y + shift_y); - } -} - -STBTT_DEF void stbtt_GetGlyphBitmapBox(const stbtt_fontinfo *font, int glyph, float scale_x, float scale_y, int *ix0, int *iy0, int *ix1, int *iy1) -{ - stbtt_GetGlyphBitmapBoxSubpixel(font, glyph, scale_x, scale_y,0.0f,0.0f, ix0, iy0, ix1, iy1); -} - -STBTT_DEF void stbtt_GetCodepointBitmapBoxSubpixel(const stbtt_fontinfo *font, int codepoint, float scale_x, float scale_y, float shift_x, float shift_y, int *ix0, int *iy0, int *ix1, int *iy1) -{ - stbtt_GetGlyphBitmapBoxSubpixel(font, stbtt_FindGlyphIndex(font,codepoint), scale_x, scale_y,shift_x,shift_y, ix0,iy0,ix1,iy1); -} - -STBTT_DEF void stbtt_GetCodepointBitmapBox(const stbtt_fontinfo *font, int codepoint, float scale_x, float scale_y, int *ix0, int *iy0, int *ix1, int *iy1) -{ - stbtt_GetCodepointBitmapBoxSubpixel(font, codepoint, scale_x, scale_y,0.0f,0.0f, ix0,iy0,ix1,iy1); -} - -typedef struct stbtt__edge { - float x0,y0, x1,y1; - int invert; -} stbtt__edge; - -typedef struct stbtt__active_edge -{ - int x,dx; - float ey; - struct stbtt__active_edge *next; - int valid; -} stbtt__active_edge; - -#define FIXSHIFT 10 -#define FIX (1 << FIXSHIFT) -#define FIXMASK (FIX-1) - -static stbtt__active_edge *new_active(stbtt__edge *e, int off_x, float start_point, void *userdata) -{ - stbtt__active_edge *z = (stbtt__active_edge *) STBTT_malloc(sizeof(*z), userdata); // @TODO: make a pool of these!!! - float dxdy = (e->x1 - e->x0) / (e->y1 - e->y0); - STBTT_assert(e->y0 <= start_point); - if (!z) return z; - // round dx down to avoid going too far - if (dxdy < 0) - z->dx = -STBTT_ifloor(FIX * -dxdy); - else - z->dx = STBTT_ifloor(FIX * dxdy); - z->x = STBTT_ifloor(FIX * (e->x0 + dxdy * (start_point - e->y0))); - z->x -= off_x * FIX; - z->ey = e->y1; - z->next = 0; - z->valid = e->invert ? 1 : -1; - return z; -} - -// note: this routine clips fills that extend off the edges... ideally this -// wouldn't happen, but it could happen if the truetype glyph bounding boxes -// are wrong, or if the user supplies a too-small bitmap -static void stbtt__fill_active_edges(unsigned char *scanline, int len, stbtt__active_edge *e, int max_weight) -{ - // non-zero winding fill - int x0=0, w=0; - - while (e) { - if (w == 0) { - // if we're currently at zero, we need to record the edge start point - x0 = e->x; w += e->valid; - } else { - int x1 = e->x; w += e->valid; - // if we went to zero, we need to draw - if (w == 0) { - int i = x0 >> FIXSHIFT; - int j = x1 >> FIXSHIFT; - - if (i < len && j >= 0) { - if (i == j) { - // x0,x1 are the same pixel, so compute combined coverage - scanline[i] = scanline[i] + (stbtt_uint8) ((x1 - x0) * max_weight >> FIXSHIFT); - } else { - if (i >= 0) // add antialiasing for x0 - scanline[i] = scanline[i] + (stbtt_uint8) (((FIX - (x0 & FIXMASK)) * max_weight) >> FIXSHIFT); - else - i = -1; // clip - - if (j < len) // add antialiasing for x1 - scanline[j] = scanline[j] + (stbtt_uint8) (((x1 & FIXMASK) * max_weight) >> FIXSHIFT); - else - j = len; // clip - - for (++i; i < j; ++i) // fill pixels between x0 and x1 - scanline[i] = scanline[i] + (stbtt_uint8) max_weight; - } - } - } - } - - e = e->next; - } -} - -static void stbtt__rasterize_sorted_edges(stbtt__bitmap *result, stbtt__edge *e, int n, int vsubsample, int off_x, int off_y, void *userdata) -{ - stbtt__active_edge *active = NULL; - int y,j=0; - int max_weight = (255 / vsubsample); // weight per vertical scanline - int s; // vertical subsample index - unsigned char scanline_data[512], *scanline; - - if (result->w > 512) - scanline = (unsigned char *) STBTT_malloc(result->w, userdata); - else - scanline = scanline_data; - - y = off_y * vsubsample; - e[n].y0 = (off_y + result->h) * (float) vsubsample + 1; - - while (j < result->h) { - STBTT_memset(scanline, 0, result->w); - for (s=0; s < vsubsample; ++s) { - // find center of pixel for this scanline - float scan_y = y + 0.5f; - stbtt__active_edge **step = &active; - - // update all active edges; - // remove all active edges that terminate before the center of this scanline - while (*step) { - stbtt__active_edge * z = *step; - if (z->ey <= scan_y) { - *step = z->next; // delete from list - STBTT_assert(z->valid); - z->valid = 0; - STBTT_free(z, userdata); - } else { - z->x += z->dx; // advance to position for current scanline - step = &((*step)->next); // advance through list - } - } - - // resort the list if needed - for(;;) { - int changed=0; - step = &active; - while (*step && (*step)->next) { - if ((*step)->x > (*step)->next->x) { - stbtt__active_edge *t = *step; - stbtt__active_edge *q = t->next; - - t->next = q->next; - q->next = t; - *step = q; - changed = 1; - } - step = &(*step)->next; - } - if (!changed) break; - } - - // insert all edges that start before the center of this scanline -- omit ones that also end on this scanline - while (e->y0 <= scan_y) { - if (e->y1 > scan_y) { - stbtt__active_edge *z = new_active(e, off_x, scan_y, userdata); - // find insertion point - if (active == NULL) - active = z; - else if (z->x < active->x) { - // insert at front - z->next = active; - active = z; - } else { - // find thing to insert AFTER - stbtt__active_edge *p = active; - while (p->next && p->next->x < z->x) - p = p->next; - // at this point, p->next->x is NOT < z->x - z->next = p->next; - p->next = z; - } - } - ++e; - } - - // now process all active edges in XOR fashion - if (active) - stbtt__fill_active_edges(scanline, result->w, active, max_weight); - - ++y; - } - STBTT_memcpy(result->pixels + j * result->stride, scanline, result->w); - ++j; - } - - while (active) { - stbtt__active_edge *z = active; - active = active->next; - STBTT_free(z, userdata); - } - - if (scanline != scanline_data) - STBTT_free(scanline, userdata); -} - -static int stbtt__edge_compare(const void *p, const void *q) -{ - stbtt__edge *a = (stbtt__edge *) p; - stbtt__edge *b = (stbtt__edge *) q; - - if (a->y0 < b->y0) return -1; - if (a->y0 > b->y0) return 1; - return 0; -} - -typedef struct -{ - float x,y; -} stbtt__point; - -static void stbtt__rasterize(stbtt__bitmap *result, stbtt__point *pts, int *wcount, int windings, float scale_x, float scale_y, float shift_x, float shift_y, int off_x, int off_y, int invert, void *userdata) -{ - float y_scale_inv = invert ? -scale_y : scale_y; - stbtt__edge *e; - int n,i,j,k,m; - int vsubsample = result->h < 8 ? 15 : 5; - // vsubsample should divide 255 evenly; otherwise we won't reach full opacity - - // now we have to blow out the windings into explicit edge lists - n = 0; - for (i=0; i < windings; ++i) - n += wcount[i]; - - e = (stbtt__edge *) STBTT_malloc(sizeof(*e) * (n+1), userdata); // add an extra one as a sentinel - if (e == 0) return; - n = 0; - - m=0; - for (i=0; i < windings; ++i) { - stbtt__point *p = pts + m; - m += wcount[i]; - j = wcount[i]-1; - for (k=0; k < wcount[i]; j=k++) { - int a=k,b=j; - // skip the edge if horizontal - if (p[j].y == p[k].y) - continue; - // add edge from j to k to the list - e[n].invert = 0; - if (invert ? p[j].y > p[k].y : p[j].y < p[k].y) { - e[n].invert = 1; - a=j,b=k; - } - e[n].x0 = p[a].x * scale_x + shift_x; - e[n].y0 = (p[a].y * y_scale_inv + shift_y) * vsubsample; - e[n].x1 = p[b].x * scale_x + shift_x; - e[n].y1 = (p[b].y * y_scale_inv + shift_y) * vsubsample; - ++n; - } - } - - // now sort the edges by their highest point (should snap to integer, and then by x) - STBTT_sort(e, n, sizeof(e[0]), stbtt__edge_compare); - - // now, traverse the scanlines and find the intersections on each scanline, use xor winding rule - stbtt__rasterize_sorted_edges(result, e, n, vsubsample, off_x, off_y, userdata); - - STBTT_free(e, userdata); -} - -static void stbtt__add_point(stbtt__point *points, int n, float x, float y) -{ - if (!points) return; // during first pass, it's unallocated - points[n].x = x; - points[n].y = y; -} - -// tesselate until threshhold p is happy... @TODO warped to compensate for non-linear stretching -static int stbtt__tesselate_curve(stbtt__point *points, int *num_points, float x0, float y0, float x1, float y1, float x2, float y2, float objspace_flatness_squared, int n) -{ - // midpoint - float mx = (x0 + 2*x1 + x2)/4; - float my = (y0 + 2*y1 + y2)/4; - // versus directly drawn line - float dx = (x0+x2)/2 - mx; - float dy = (y0+y2)/2 - my; - if (n > 16) // 65536 segments on one curve better be enough! - return 1; - if (dx*dx+dy*dy > objspace_flatness_squared) { // half-pixel error allowed... need to be smaller if AA - stbtt__tesselate_curve(points, num_points, x0,y0, (x0+x1)/2.0f,(y0+y1)/2.0f, mx,my, objspace_flatness_squared,n+1); - stbtt__tesselate_curve(points, num_points, mx,my, (x1+x2)/2.0f,(y1+y2)/2.0f, x2,y2, objspace_flatness_squared,n+1); - } else { - stbtt__add_point(points, *num_points,x2,y2); - *num_points = *num_points+1; - } - return 1; -} - -// returns number of contours -static stbtt__point *stbtt_FlattenCurves(stbtt_vertex *vertices, int num_verts, float objspace_flatness, int **contour_lengths, int *num_contours, void *userdata) -{ - stbtt__point *points=0; - int num_points=0; - - float objspace_flatness_squared = objspace_flatness * objspace_flatness; - int i,n=0,start=0, pass; - - // count how many "moves" there are to get the contour count - for (i=0; i < num_verts; ++i) - if (vertices[i].type == STBTT_vmove) - ++n; - - *num_contours = n; - if (n == 0) return 0; - - *contour_lengths = (int *) STBTT_malloc(sizeof(**contour_lengths) * n, userdata); - - if (*contour_lengths == 0) { - *num_contours = 0; - return 0; - } - - // make two passes through the points so we don't need to realloc - for (pass=0; pass < 2; ++pass) { - float x=0,y=0; - if (pass == 1) { - points = (stbtt__point *) STBTT_malloc(num_points * sizeof(points[0]), userdata); - if (points == NULL) goto error; - } - num_points = 0; - n= -1; - for (i=0; i < num_verts; ++i) { - switch (vertices[i].type) { - case STBTT_vmove: - // start the next contour - if (n >= 0) - (*contour_lengths)[n] = num_points - start; - ++n; - start = num_points; - - x = vertices[i].x, y = vertices[i].y; - stbtt__add_point(points, num_points++, x,y); - break; - case STBTT_vline: - x = vertices[i].x, y = vertices[i].y; - stbtt__add_point(points, num_points++, x, y); - break; - case STBTT_vcurve: - stbtt__tesselate_curve(points, &num_points, x,y, - vertices[i].cx, vertices[i].cy, - vertices[i].x, vertices[i].y, - objspace_flatness_squared, 0); - x = vertices[i].x, y = vertices[i].y; - break; - } - } - (*contour_lengths)[n] = num_points - start; - } - - return points; -error: - STBTT_free(points, userdata); - STBTT_free(*contour_lengths, userdata); - *contour_lengths = 0; - *num_contours = 0; - return NULL; -} - -STBTT_DEF void stbtt_Rasterize(stbtt__bitmap *result, float flatness_in_pixels, stbtt_vertex *vertices, int num_verts, float scale_x, float scale_y, float shift_x, float shift_y, int x_off, int y_off, int invert, void *userdata) -{ - float scale = scale_x > scale_y ? scale_y : scale_x; - int winding_count, *winding_lengths; - stbtt__point *windings = stbtt_FlattenCurves(vertices, num_verts, flatness_in_pixels / scale, &winding_lengths, &winding_count, userdata); - if (windings) { - stbtt__rasterize(result, windings, winding_lengths, winding_count, scale_x, scale_y, shift_x, shift_y, x_off, y_off, invert, userdata); - STBTT_free(winding_lengths, userdata); - STBTT_free(windings, userdata); - } -} - -STBTT_DEF void stbtt_FreeBitmap(unsigned char *bitmap, void *userdata) -{ - STBTT_free(bitmap, userdata); -} - -STBTT_DEF unsigned char *stbtt_GetGlyphBitmapSubpixel(const stbtt_fontinfo *info, float scale_x, float scale_y, float shift_x, float shift_y, int glyph, int *width, int *height, int *xoff, int *yoff) -{ - int ix0,iy0,ix1,iy1; - stbtt__bitmap gbm; - stbtt_vertex *vertices; - int num_verts = stbtt_GetGlyphShape(info, glyph, &vertices); - - if (scale_x == 0) scale_x = scale_y; - if (scale_y == 0) { - if (scale_x == 0) return NULL; - scale_y = scale_x; - } - - stbtt_GetGlyphBitmapBoxSubpixel(info, glyph, scale_x, scale_y, shift_x, shift_y, &ix0,&iy0,&ix1,&iy1); - - // now we get the size - gbm.w = (ix1 - ix0); - gbm.h = (iy1 - iy0); - gbm.pixels = NULL; // in case we error - - if (width ) *width = gbm.w; - if (height) *height = gbm.h; - if (xoff ) *xoff = ix0; - if (yoff ) *yoff = iy0; - - if (gbm.w && gbm.h) { - gbm.pixels = (unsigned char *) STBTT_malloc(gbm.w * gbm.h, info->userdata); - if (gbm.pixels) { - gbm.stride = gbm.w; - - stbtt_Rasterize(&gbm, 0.35f, vertices, num_verts, scale_x, scale_y, shift_x, shift_y, ix0, iy0, 1, info->userdata); - } - } - STBTT_free(vertices, info->userdata); - return gbm.pixels; -} - -STBTT_DEF unsigned char *stbtt_GetGlyphBitmap(const stbtt_fontinfo *info, float scale_x, float scale_y, int glyph, int *width, int *height, int *xoff, int *yoff) -{ - return stbtt_GetGlyphBitmapSubpixel(info, scale_x, scale_y, 0.0f, 0.0f, glyph, width, height, xoff, yoff); -} - -STBTT_DEF void stbtt_MakeGlyphBitmapSubpixel(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int glyph) -{ - int ix0,iy0; - stbtt_vertex *vertices; - int num_verts = stbtt_GetGlyphShape(info, glyph, &vertices); - stbtt__bitmap gbm; - - stbtt_GetGlyphBitmapBoxSubpixel(info, glyph, scale_x, scale_y, shift_x, shift_y, &ix0,&iy0,0,0); - gbm.pixels = output; - gbm.w = out_w; - gbm.h = out_h; - gbm.stride = out_stride; - - if (gbm.w && gbm.h) - stbtt_Rasterize(&gbm, 0.35f, vertices, num_verts, scale_x, scale_y, shift_x, shift_y, ix0,iy0, 1, info->userdata); - - STBTT_free(vertices, info->userdata); -} - -STBTT_DEF void stbtt_MakeGlyphBitmap(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, int glyph) -{ - stbtt_MakeGlyphBitmapSubpixel(info, output, out_w, out_h, out_stride, scale_x, scale_y, 0.0f,0.0f, glyph); -} - -STBTT_DEF unsigned char *stbtt_GetCodepointBitmapSubpixel(const stbtt_fontinfo *info, float scale_x, float scale_y, float shift_x, float shift_y, int codepoint, int *width, int *height, int *xoff, int *yoff) -{ - return stbtt_GetGlyphBitmapSubpixel(info, scale_x, scale_y,shift_x,shift_y, stbtt_FindGlyphIndex(info,codepoint), width,height,xoff,yoff); -} - -STBTT_DEF void stbtt_MakeCodepointBitmapSubpixel(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int codepoint) -{ - stbtt_MakeGlyphBitmapSubpixel(info, output, out_w, out_h, out_stride, scale_x, scale_y, shift_x, shift_y, stbtt_FindGlyphIndex(info,codepoint)); -} - -STBTT_DEF unsigned char *stbtt_GetCodepointBitmap(const stbtt_fontinfo *info, float scale_x, float scale_y, int codepoint, int *width, int *height, int *xoff, int *yoff) -{ - return stbtt_GetCodepointBitmapSubpixel(info, scale_x, scale_y, 0.0f,0.0f, codepoint, width,height,xoff,yoff); -} - -STBTT_DEF void stbtt_MakeCodepointBitmap(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, int codepoint) -{ - stbtt_MakeCodepointBitmapSubpixel(info, output, out_w, out_h, out_stride, scale_x, scale_y, 0.0f,0.0f, codepoint); -} - -////////////////////////////////////////////////////////////////////////////// -// -// bitmap baking -// -// This is SUPER-CRAPPY packing to keep source code small - -STBTT_DEF int stbtt_BakeFontBitmap(const unsigned char *data, int offset, // font location (use offset=0 for plain .ttf) - float pixel_height, // height of font in pixels - unsigned char *pixels, int pw, int ph, // bitmap to be filled in - int first_char, int num_chars, // characters to bake - stbtt_bakedchar *chardata) -{ - float scale; - int x,y,bottom_y, i; - stbtt_fontinfo f; - if (!stbtt_InitFont(&f, data, offset)) - return -1; - STBTT_memset(pixels, 0, pw*ph); // background of 0 around pixels - x=y=1; - bottom_y = 1; - - scale = stbtt_ScaleForPixelHeight(&f, pixel_height); - - for (i=0; i < num_chars; ++i) { - int advance, lsb, x0,y0,x1,y1,gw,gh; - int g = stbtt_FindGlyphIndex(&f, first_char + i); - stbtt_GetGlyphHMetrics(&f, g, &advance, &lsb); - stbtt_GetGlyphBitmapBox(&f, g, scale,scale, &x0,&y0,&x1,&y1); - gw = x1-x0; - gh = y1-y0; - if (x + gw + 1 >= pw) - y = bottom_y, x = 1; // advance to next row - if (y + gh + 1 >= ph) // check if it fits vertically AFTER potentially moving to next row - return -i; - STBTT_assert(x+gw < pw); - STBTT_assert(y+gh < ph); - stbtt_MakeGlyphBitmap(&f, pixels+x+y*pw, gw,gh,pw, scale,scale, g); - chardata[i].x0 = (stbtt_int16) x; - chardata[i].y0 = (stbtt_int16) y; - chardata[i].x1 = (stbtt_int16) (x + gw); - chardata[i].y1 = (stbtt_int16) (y + gh); - chardata[i].xadvance = scale * advance; - chardata[i].xoff = (float) x0; - chardata[i].yoff = (float) y0; - x = x + gw + 1; - if (y+gh+1 > bottom_y) - bottom_y = y+gh+1; - } - return bottom_y; -} - -STBTT_DEF void stbtt_GetBakedQuad(stbtt_bakedchar *chardata, int pw, int ph, int char_index, float *xpos, float *ypos, stbtt_aligned_quad *q, int opengl_fillrule) -{ - float d3d_bias = opengl_fillrule ? 0 : -0.5f; - float ipw = 1.0f / pw, iph = 1.0f / ph; - stbtt_bakedchar *b = chardata + char_index; - int round_x = STBTT_ifloor((*xpos + b->xoff) + 0.5f); - int round_y = STBTT_ifloor((*ypos + b->yoff) + 0.5f); - - q->x0 = round_x + d3d_bias; - q->y0 = round_y + d3d_bias; - q->x1 = round_x + b->x1 - b->x0 + d3d_bias; - q->y1 = round_y + b->y1 - b->y0 + d3d_bias; - - q->s0 = b->x0 * ipw; - q->t0 = b->y0 * iph; - q->s1 = b->x1 * ipw; - q->t1 = b->y1 * iph; - - //*xpos += b->xadvance; -} - -STBTT_DEF void stbtt_GetBakedQuadUnrounded(stbtt_bakedchar *chardata, int pw, int ph, int char_index, float *xpos, float *ypos, stbtt_aligned_quad *q, int opengl_fillrule) -{ - float d3d_bias = opengl_fillrule ? 0 : -0.5f; - float ipw = 1.0f / pw, iph = 1.0f / ph; - stbtt_bakedchar *b = chardata + char_index; - - float x = *xpos + b->xoff; - float y = *ypos + b->yoff; - - q->x0 = x + d3d_bias; - q->y0 = y + d3d_bias; - q->x1 = x + b->x1 - b->x0 + d3d_bias; - q->y1 = y + b->y1 - b->y0 + d3d_bias; - - q->s0 = b->x0 * ipw; - q->t0 = b->y0 * iph; - q->s1 = b->x1 * ipw; - q->t1 = b->y1 * iph; - - //*xpos += b->xadvance; -} - -////////////////////////////////////////////////////////////////////////////// -// -// rectangle packing replacement routines if you don't have stb_rect_pack.h -// - -#ifndef STB_RECT_PACK_VERSION -#ifdef _MSC_VER -#define STBTT__NOTUSED(v) (void)(v) -#else -#define STBTT__NOTUSED(v) (void)sizeof(v) -#endif - -typedef int stbrp_coord; - -//////////////////////////////////////////////////////////////////////////////////// -// // -// // -// COMPILER WARNING ?!?!? // -// // -// // -// if you get a compile warning due to these symbols being defined more than // -// once, move #include "stb_rect_pack.h" before #include "stb_truetype.h" // -// // -//////////////////////////////////////////////////////////////////////////////////// - -typedef struct -{ - int width,height; - int x,y,bottom_y; -} stbrp_context; - -typedef struct -{ - unsigned char x; -} stbrp_node; - -typedef struct -{ - stbrp_coord x,y; - int id,w,h,was_packed; -} stbrp_rect; - -static void stbrp_init_target(stbrp_context *con, int pw, int ph, stbrp_node *nodes, int num_nodes) -{ - con->width = pw; - con->height = ph; - con->x = 0; - con->y = 0; - con->bottom_y = 0; - STBTT__NOTUSED(nodes); - STBTT__NOTUSED(num_nodes); -} - -static void stbrp_pack_rects(stbrp_context *con, stbrp_rect *rects, int num_rects) -{ - int i; - for (i=0; i < num_rects; ++i) { - if (con->x + rects[i].w > con->width) { - con->x = 0; - con->y = con->bottom_y; - } - if (con->y + rects[i].h > con->height) - break; - rects[i].x = con->x; - rects[i].y = con->y; - rects[i].was_packed = 1; - con->x += rects[i].w; - if (con->y + rects[i].h > con->bottom_y) - con->bottom_y = con->y + rects[i].h; - } - for ( ; i < num_rects; ++i) - rects[i].was_packed = 0; -} -#endif - -////////////////////////////////////////////////////////////////////////////// -// -// bitmap baking -// -// This is SUPER-AWESOME (tm Ryan Gordon) packing using stb_rect_pack.h. If -// stb_rect_pack.h isn't available, it uses the BakeFontBitmap strategy. - -STBTT_DEF int stbtt_PackBegin(stbtt_pack_context *spc, unsigned char *pixels, int pw, int ph, int stride_in_bytes, int padding, void *alloc_context) -{ - stbrp_context *context = (stbrp_context *) STBTT_malloc(sizeof(*context) ,alloc_context); - int num_nodes = pw - padding; - stbrp_node *nodes = (stbrp_node *) STBTT_malloc(sizeof(*nodes ) * num_nodes,alloc_context); - - if (context == NULL || nodes == NULL) { - if (context != NULL) STBTT_free(context, alloc_context); - if (nodes != NULL) STBTT_free(nodes , alloc_context); - return 0; - } - - spc->user_allocator_context = alloc_context; - spc->width = pw; - spc->height = ph; - spc->pixels = pixels; - spc->pack_info = context; - spc->nodes = nodes; - spc->padding = padding; - spc->stride_in_bytes = stride_in_bytes != 0 ? stride_in_bytes : pw; - spc->h_oversample = 1; - spc->v_oversample = 1; - - stbrp_init_target(context, pw-padding, ph-padding, nodes, num_nodes); - - STBTT_memset(pixels, 0, pw*ph); // background of 0 around pixels - - return 1; -} - -STBTT_DEF void stbtt_PackEnd (stbtt_pack_context *spc) -{ - STBTT_free(spc->nodes , spc->user_allocator_context); - STBTT_free(spc->pack_info, spc->user_allocator_context); -} - -STBTT_DEF void stbtt_PackSetOversampling(stbtt_pack_context *spc, unsigned int h_oversample, unsigned int v_oversample) -{ - STBTT_assert(h_oversample <= STBTT_MAX_OVERSAMPLE); - STBTT_assert(v_oversample <= STBTT_MAX_OVERSAMPLE); - if (h_oversample <= STBTT_MAX_OVERSAMPLE) - spc->h_oversample = h_oversample; - if (v_oversample <= STBTT_MAX_OVERSAMPLE) - spc->v_oversample = v_oversample; -} - -#define STBTT__OVER_MASK (STBTT_MAX_OVERSAMPLE-1) - -static void stbtt__h_prefilter(unsigned char *pixels, int w, int h, int stride_in_bytes, unsigned int kernel_width) -{ - unsigned char buffer[STBTT_MAX_OVERSAMPLE]; - int safe_w = w - kernel_width; - int j; - for (j=0; j < h; ++j) { - int i; - unsigned int total; - STBTT_memset(buffer, 0, kernel_width); - - total = 0; - - // make kernel_width a constant in common cases so compiler can optimize out the divide - switch (kernel_width) { - case 2: - for (i=0; i <= safe_w; ++i) { - total += pixels[i] - buffer[i & STBTT__OVER_MASK]; - buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i]; - pixels[i] = (unsigned char) (total / 2); - } - break; - case 3: - for (i=0; i <= safe_w; ++i) { - total += pixels[i] - buffer[i & STBTT__OVER_MASK]; - buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i]; - pixels[i] = (unsigned char) (total / 3); - } - break; - case 4: - for (i=0; i <= safe_w; ++i) { - total += pixels[i] - buffer[i & STBTT__OVER_MASK]; - buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i]; - pixels[i] = (unsigned char) (total / 4); - } - break; - default: - for (i=0; i <= safe_w; ++i) { - total += pixels[i] - buffer[i & STBTT__OVER_MASK]; - buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i]; - pixels[i] = (unsigned char) (total / kernel_width); - } - break; - } - - for (; i < w; ++i) { - STBTT_assert(pixels[i] == 0); - total -= buffer[i & STBTT__OVER_MASK]; - pixels[i] = (unsigned char) (total / kernel_width); - } - - pixels += stride_in_bytes; - } -} - -static void stbtt__v_prefilter(unsigned char *pixels, int w, int h, int stride_in_bytes, unsigned int kernel_width) -{ - unsigned char buffer[STBTT_MAX_OVERSAMPLE]; - int safe_h = h - kernel_width; - int j; - for (j=0; j < w; ++j) { - int i; - unsigned int total; - STBTT_memset(buffer, 0, kernel_width); - - total = 0; - - // make kernel_width a constant in common cases so compiler can optimize out the divide - switch (kernel_width) { - case 2: - for (i=0; i <= safe_h; ++i) { - total += pixels[i*stride_in_bytes] - buffer[i & STBTT__OVER_MASK]; - buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i*stride_in_bytes]; - pixels[i*stride_in_bytes] = (unsigned char) (total / 2); - } - break; - case 3: - for (i=0; i <= safe_h; ++i) { - total += pixels[i*stride_in_bytes] - buffer[i & STBTT__OVER_MASK]; - buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i*stride_in_bytes]; - pixels[i*stride_in_bytes] = (unsigned char) (total / 3); - } - break; - case 4: - for (i=0; i <= safe_h; ++i) { - total += pixels[i*stride_in_bytes] - buffer[i & STBTT__OVER_MASK]; - buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i*stride_in_bytes]; - pixels[i*stride_in_bytes] = (unsigned char) (total / 4); - } - break; - default: - for (i=0; i <= safe_h; ++i) { - total += pixels[i*stride_in_bytes] - buffer[i & STBTT__OVER_MASK]; - buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i*stride_in_bytes]; - pixels[i*stride_in_bytes] = (unsigned char) (total / kernel_width); - } - break; - } - - for (; i < h; ++i) { - STBTT_assert(pixels[i*stride_in_bytes] == 0); - total -= buffer[i & STBTT__OVER_MASK]; - pixels[i*stride_in_bytes] = (unsigned char) (total / kernel_width); - } - - pixels += 1; - } -} - -static float stbtt__oversample_shift(int oversample) -{ - if (!oversample) - return 0.0f; - - // The prefilter is a box filter of width "oversample", - // which shifts phase by (oversample - 1)/2 pixels in - // oversampled space. We want to shift in the opposite - // direction to counter this. - return (float)-(oversample - 1) / (2.0f * (float)oversample); -} - -STBTT_DEF int stbtt_PackFontRanges(stbtt_pack_context *spc, unsigned char *fontdata, int font_index, stbtt_pack_range *ranges, int num_ranges) -{ - stbtt_fontinfo info; - float recip_h = 1.0f / spc->h_oversample; - float recip_v = 1.0f / spc->v_oversample; - float sub_x = stbtt__oversample_shift(spc->h_oversample); - float sub_y = stbtt__oversample_shift(spc->v_oversample); - int i,j,k,n, return_value = 1; - stbrp_context *context = (stbrp_context *) spc->pack_info; - stbrp_rect *rects; - - // flag all characters as NOT packed - for (i=0; i < num_ranges; ++i) - for (j=0; j < ranges[i].num_chars_in_range; ++j) - ranges[i].chardata_for_range[j].x0 = - ranges[i].chardata_for_range[j].y0 = - ranges[i].chardata_for_range[j].x1 = - ranges[i].chardata_for_range[j].y1 = 0; - - n = 0; - for (i=0; i < num_ranges; ++i) - n += ranges[i].num_chars_in_range; - - rects = (stbrp_rect *) STBTT_malloc(sizeof(*rects) * n, spc->user_allocator_context); - if (rects == NULL) - return 0; - - stbtt_InitFont(&info, fontdata, stbtt_GetFontOffsetForIndex(fontdata,font_index)); - k=0; - for (i=0; i < num_ranges; ++i) { - float fh = ranges[i].font_size; - float scale = fh > 0 ? stbtt_ScaleForPixelHeight(&info, fh) : stbtt_ScaleForMappingEmToPixels(&info, -fh); - for (j=0; j < ranges[i].num_chars_in_range; ++j) { - int x0,y0,x1,y1; - stbtt_GetCodepointBitmapBoxSubpixel(&info, ranges[i].first_unicode_char_in_range + j, - scale * spc->h_oversample, - scale * spc->v_oversample, - 0,0, - &x0,&y0,&x1,&y1); - rects[k].w = (stbrp_coord) (x1-x0 + spc->padding + spc->h_oversample-1); - rects[k].h = (stbrp_coord) (y1-y0 + spc->padding + spc->v_oversample-1); - ++k; - } - } - - stbrp_pack_rects(context, rects, k); - - k = 0; - for (i=0; i < num_ranges; ++i) { - float fh = ranges[i].font_size; - float scale = fh > 0 ? stbtt_ScaleForPixelHeight(&info, fh) : stbtt_ScaleForMappingEmToPixels(&info, -fh); - for (j=0; j < ranges[i].num_chars_in_range; ++j) { - stbrp_rect *r = &rects[k]; - if (r->was_packed) { - stbtt_packedchar *bc = &ranges[i].chardata_for_range[j]; - int advance, lsb, x0,y0,x1,y1; - int glyph = stbtt_FindGlyphIndex(&info, ranges[i].first_unicode_char_in_range + j); - stbrp_coord pad = (stbrp_coord) spc->padding; - - // pad on left and top - r->x += pad; - r->y += pad; - r->w -= pad; - r->h -= pad; - stbtt_GetGlyphHMetrics(&info, glyph, &advance, &lsb); - stbtt_GetGlyphBitmapBox(&info, glyph, - scale * spc->h_oversample, - scale * spc->v_oversample, - &x0,&y0,&x1,&y1); - stbtt_MakeGlyphBitmapSubpixel(&info, - spc->pixels + r->x + r->y*spc->stride_in_bytes, - r->w - spc->h_oversample+1, - r->h - spc->v_oversample+1, - spc->stride_in_bytes, - scale * spc->h_oversample, - scale * spc->v_oversample, - 0,0, - glyph); - - if (spc->h_oversample > 1) - stbtt__h_prefilter(spc->pixels + r->x + r->y*spc->stride_in_bytes, - r->w, r->h, spc->stride_in_bytes, - spc->h_oversample); - - if (spc->v_oversample > 1) - stbtt__v_prefilter(spc->pixels + r->x + r->y*spc->stride_in_bytes, - r->w, r->h, spc->stride_in_bytes, - spc->v_oversample); - - bc->x0 = (stbtt_int16) r->x; - bc->y0 = (stbtt_int16) r->y; - bc->x1 = (stbtt_int16) (r->x + r->w); - bc->y1 = (stbtt_int16) (r->y + r->h); - bc->xadvance = scale * advance; - bc->xoff = (float) x0 * recip_h + sub_x; - bc->yoff = (float) y0 * recip_v + sub_y; - bc->xoff2 = (x0 + r->w) * recip_h + sub_x; - bc->yoff2 = (y0 + r->h) * recip_v + sub_y; - } else { - return_value = 0; // if any fail, report failure - } - - ++k; - } - } - - STBTT_free(rects, spc->user_allocator_context); - return return_value; -} - -STBTT_DEF int stbtt_PackFontRange(stbtt_pack_context *spc, unsigned char *fontdata, int font_index, float font_size, - int first_unicode_char_in_range, int num_chars_in_range, stbtt_packedchar *chardata_for_range) -{ - stbtt_pack_range range; - range.first_unicode_char_in_range = first_unicode_char_in_range; - range.num_chars_in_range = num_chars_in_range; - range.chardata_for_range = chardata_for_range; - range.font_size = font_size; - return stbtt_PackFontRanges(spc, fontdata, font_index, &range, 1); -} - -STBTT_DEF void stbtt_GetPackedQuad(stbtt_packedchar *chardata, int pw, int ph, int char_index, float *xpos, float *ypos, stbtt_aligned_quad *q, int align_to_integer) -{ - float ipw = 1.0f / pw, iph = 1.0f / ph; - stbtt_packedchar *b = chardata + char_index; - - if (align_to_integer) { - float x = (float) STBTT_ifloor((*xpos + b->xoff) + 0.5f); - float y = (float) STBTT_ifloor((*ypos + b->yoff) + 0.5f); - q->x0 = x; - q->y0 = y; - q->x1 = x + b->xoff2 - b->xoff; - q->y1 = y + b->yoff2 - b->yoff; - } else { - q->x0 = *xpos + b->xoff; - q->y0 = *ypos + b->yoff; - q->x1 = *xpos + b->xoff2; - q->y1 = *ypos + b->yoff2; - } - - q->s0 = b->x0 * ipw; - q->t0 = b->y0 * iph; - q->s1 = b->x1 * ipw; - q->t1 = b->y1 * iph; - - *xpos += b->xadvance; -} - - -////////////////////////////////////////////////////////////////////////////// -// -// font name matching -- recommended not to use this -// - -// check if a utf8 string contains a prefix which is the utf16 string; if so return length of matching utf8 string -static stbtt_int32 stbtt__CompareUTF8toUTF16_bigendian_prefix(const stbtt_uint8 *s1, stbtt_int32 len1, const stbtt_uint8 *s2, stbtt_int32 len2) -{ - stbtt_int32 i=0; - - // convert utf16 to utf8 and compare the results while converting - while (len2) { - stbtt_uint16 ch = s2[0]*256 + s2[1]; - if (ch < 0x80) { - if (i >= len1) return -1; - if (s1[i++] != ch) return -1; - } else if (ch < 0x800) { - if (i+1 >= len1) return -1; - if (s1[i++] != 0xc0 + (ch >> 6)) return -1; - if (s1[i++] != 0x80 + (ch & 0x3f)) return -1; - } else if (ch >= 0xd800 && ch < 0xdc00) { - stbtt_uint32 c; - stbtt_uint16 ch2 = s2[2]*256 + s2[3]; - if (i+3 >= len1) return -1; - c = ((ch - 0xd800) << 10) + (ch2 - 0xdc00) + 0x10000; - if (s1[i++] != 0xf0 + (c >> 18)) return -1; - if (s1[i++] != 0x80 + ((c >> 12) & 0x3f)) return -1; - if (s1[i++] != 0x80 + ((c >> 6) & 0x3f)) return -1; - if (s1[i++] != 0x80 + ((c ) & 0x3f)) return -1; - s2 += 2; // plus another 2 below - len2 -= 2; - } else if (ch >= 0xdc00 && ch < 0xe000) { - return -1; - } else { - if (i+2 >= len1) return -1; - if (s1[i++] != 0xe0 + (ch >> 12)) return -1; - if (s1[i++] != 0x80 + ((ch >> 6) & 0x3f)) return -1; - if (s1[i++] != 0x80 + ((ch ) & 0x3f)) return -1; - } - s2 += 2; - len2 -= 2; - } - return i; -} - -STBTT_DEF int stbtt_CompareUTF8toUTF16_bigendian(const char *s1, int len1, const char *s2, int len2) -{ - return len1 == stbtt__CompareUTF8toUTF16_bigendian_prefix((const stbtt_uint8*) s1, len1, (const stbtt_uint8*) s2, len2); -} - -// returns results in whatever encoding you request... but note that 2-byte encodings -// will be BIG-ENDIAN... use stbtt_CompareUTF8toUTF16_bigendian() to compare -STBTT_DEF const char *stbtt_GetFontNameString(const stbtt_fontinfo *font, int *length, int platformID, int encodingID, int languageID, int nameID) -{ - stbtt_int32 i,count,stringOffset; - stbtt_uint8 *fc = font->data; - stbtt_uint32 offset = font->fontstart; - stbtt_uint32 nm = stbtt__find_table(fc, offset, "name"); - if (!nm) return NULL; - - count = ttUSHORT(fc+nm+2); - stringOffset = nm + ttUSHORT(fc+nm+4); - for (i=0; i < count; ++i) { - stbtt_uint32 loc = nm + 6 + 12 * i; - if (platformID == ttUSHORT(fc+loc+0) && encodingID == ttUSHORT(fc+loc+2) - && languageID == ttUSHORT(fc+loc+4) && nameID == ttUSHORT(fc+loc+6)) { - *length = ttUSHORT(fc+loc+8); - return (const char *) (fc+stringOffset+ttUSHORT(fc+loc+10)); - } - } - return NULL; -} - -static int stbtt__matchpair(stbtt_uint8 *fc, stbtt_uint32 nm, stbtt_uint8 *name, stbtt_int32 nlen, stbtt_int32 target_id, stbtt_int32 next_id) -{ - stbtt_int32 i; - stbtt_int32 count = ttUSHORT(fc+nm+2); - stbtt_int32 stringOffset = nm + ttUSHORT(fc+nm+4); - - for (i=0; i < count; ++i) { - stbtt_uint32 loc = nm + 6 + 12 * i; - stbtt_int32 id = ttUSHORT(fc+loc+6); - if (id == target_id) { - // find the encoding - stbtt_int32 platform = ttUSHORT(fc+loc+0), encoding = ttUSHORT(fc+loc+2), language = ttUSHORT(fc+loc+4); - - // is this a Unicode encoding? - if (platform == 0 || (platform == 3 && encoding == 1) || (platform == 3 && encoding == 10)) { - stbtt_int32 slen = ttUSHORT(fc+loc+8); - stbtt_int32 off = ttUSHORT(fc+loc+10); - - // check if there's a prefix match - stbtt_int32 matchlen = stbtt__CompareUTF8toUTF16_bigendian_prefix(name, nlen, fc+stringOffset+off,slen); - if (matchlen >= 0) { - // check for target_id+1 immediately following, with same encoding & language - if (i+1 < count && ttUSHORT(fc+loc+12+6) == next_id && ttUSHORT(fc+loc+12) == platform && ttUSHORT(fc+loc+12+2) == encoding && ttUSHORT(fc+loc+12+4) == language) { - slen = ttUSHORT(fc+loc+12+8); - off = ttUSHORT(fc+loc+12+10); - if (slen == 0) { - if (matchlen == nlen) - return 1; - } else if (matchlen < nlen && name[matchlen] == ' ') { - ++matchlen; - if (stbtt_CompareUTF8toUTF16_bigendian((char*) (name+matchlen), nlen-matchlen, (char*)(fc+stringOffset+off),slen)) - return 1; - } - } else { - // if nothing immediately following - if (matchlen == nlen) - return 1; - } - } - } - - // @TODO handle other encodings - } - } - return 0; -} - -static int stbtt__matches(stbtt_uint8 *fc, stbtt_uint32 offset, stbtt_uint8 *name, stbtt_int32 flags) -{ - stbtt_int32 nlen = (stbtt_int32) STBTT_strlen((char *) name); - stbtt_uint32 nm,hd; - if (!stbtt__isfont(fc+offset)) return 0; - - // check italics/bold/underline flags in macStyle... - if (flags) { - hd = stbtt__find_table(fc, offset, "head"); - if ((ttUSHORT(fc+hd+44) & 7) != (flags & 7)) return 0; - } - - nm = stbtt__find_table(fc, offset, "name"); - if (!nm) return 0; - - if (flags) { - // if we checked the macStyle flags, then just check the family and ignore the subfamily - if (stbtt__matchpair(fc, nm, name, nlen, 16, -1)) return 1; - if (stbtt__matchpair(fc, nm, name, nlen, 1, -1)) return 1; - if (stbtt__matchpair(fc, nm, name, nlen, 3, -1)) return 1; - } else { - if (stbtt__matchpair(fc, nm, name, nlen, 16, 17)) return 1; - if (stbtt__matchpair(fc, nm, name, nlen, 1, 2)) return 1; - if (stbtt__matchpair(fc, nm, name, nlen, 3, -1)) return 1; - } - - return 0; -} - -STBTT_DEF int stbtt_FindMatchingFont(const unsigned char *font_collection, const char *name_utf8, stbtt_int32 flags) -{ - stbtt_int32 i; - for (i=0;;++i) { - stbtt_int32 off = stbtt_GetFontOffsetForIndex(font_collection, i); - if (off < 0) return off; - if (stbtt__matches((stbtt_uint8 *) font_collection, off, (stbtt_uint8*) name_utf8, flags)) - return off; - } -} - -#endif // STB_TRUETYPE_IMPLEMENTATION diff --git a/win32_4ed.cpp b/win32_4ed.cpp index 01f488e1..28d8153f 100644 --- a/win32_4ed.cpp +++ b/win32_4ed.cpp @@ -8,10 +8,6 @@ */ // TOP -// TODO(allen): -// -// Fix the OwnDC thing. -// #ifdef FRED_NOT_PACKAGE @@ -58,8 +54,6 @@ #define FPS 30 #define FRAME_TIME (1000000 / FPS) -#define BUFFER_EXPERIMENT_SCALPEL 0 - #include "4ed_meta.h" #define FCPP_FORBID_MALLOC @@ -67,32 +61,25 @@ #include "4cpp_types.h" #define FCPP_STRING_IMPLEMENTATION #include "4cpp_string.h" -#define FCPP_LEXER_IMPLEMENTATION -#include "4cpp_lexer.h" + +#include "4ed_mem.cpp" + #include "4ed_math.cpp" #include "4coder_custom.h" -#include "4ed.h" #include "4ed_system.h" +#include "4ed.h" #include "4ed_rendering.h" -struct TEMP_BACKDOOR{ - Get_Binding_Data_Function *get_bindings; - Set_Extra_Font_Function *set_extra_font; -} TEMP; - -#if FRED_INTERNAL - -struct Sys_Bubble : public Bubble{ - i32 line_number; - char *file_name; -}; - -#endif +Config_API config_api; #include #include #include "4ed_internal.h" + +#if 0 +#define FCPP_LEXER_IMPLEMENTATION +#include "4cpp_lexer.h" #include "4ed_rendering.cpp" #include "4ed_command.cpp" #include "4ed_layout.cpp" @@ -103,6 +90,8 @@ struct Sys_Bubble : public Bubble{ #include "4ed_menu_view.cpp" #include "4ed_debug_view.cpp" #include "4ed.cpp" +#endif + #include "4ed_keyboard.cpp" struct Full_Job_Data{ @@ -179,26 +168,70 @@ struct Win32_Vars{ Thread_Memory *thread_memory; HMODULE custom; + HMODULE app_code; i64 performance_frequency; i64 start_pcount; + + System_Functions *system; + App_Functions app; + +#if FRED_INTERNAL + Sys_Bubble internal_bubble; +#endif }; globalvar Win32_Vars win32vars; globalvar Application_Memory win32memory; -internal void -_OutDbgStr(u8 *msg){ - OutputDebugString((char*)msg); +internal Bubble* +INTERNAL_system_sentinel(){ + return (&win32vars.internal_bubble); } +internal void* +system_get_memory_(i32 size, i32 line_number, char *file_name){ + void *ptr = 0; + +#if FRED_INTERNAL + ptr = VirtualAlloc(0, size + sizeof(Sys_Bubble), MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); + Sys_Bubble *bubble = (Sys_Bubble*)ptr; + bubble->flags = MEM_BUBBLE_SYS_DEBUG; + bubble->line_number = line_number; + bubble->file_name = file_name; + bubble->size = size; + WaitForSingleObject(win32vars.DEBUG_sysmem_lock, INFINITE); + + insert_bubble(&win32vars.internal_bubble, bubble); + ReleaseSemaphore(win32vars.DEBUG_sysmem_lock, 1, 0); + ptr = bubble + 1; +#else + ptr = VirtualAlloc(0, size, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); +#endif + + return ptr; +} + +#define system_get_memory(size) system_get_memory_(size, __LINE__, __FILE__) + internal void -system_fatal_error(u8 *message){ - MessageBox(0, (char*)message, "4ed Error", MB_OK|MB_ICONERROR); +system_free_memory(void *block){ + if (block){ +#if FRED_INTERNAL + Sys_Bubble *bubble = ((Sys_Bubble*)block) - 1; + Assert((bubble->flags & MEM_BUBBLE_DEBUG_MASK) == MEM_BUBBLE_SYS_DEBUG); + WaitForSingleObject(win32vars.DEBUG_sysmem_lock, INFINITE); + remove_bubble(bubble); + ReleaseSemaphore(win32vars.DEBUG_sysmem_lock, 1, 0); + VirtualFree(bubble, 0, MEM_RELEASE); +#else + VirtualFree(block, 0, MEM_RELEASE); +#endif + } } internal File_Data -system_load_file(u8 *filename){ +system_load_file(char *filename){ File_Data result = {}; HANDLE file; file = CreateFile((char*)filename, GENERIC_READ, 0, 0, @@ -238,8 +271,8 @@ system_load_file(u8 *filename){ return result; } -internal bool32 -system_save_file(u8 *filename, void *data, i32 size){ +internal b32 +system_save_file(char *filename, void *data, i32 size){ HANDLE file; file = CreateFile((char*)filename, GENERIC_WRITE, 0, 0, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0); @@ -262,7 +295,7 @@ system_save_file(u8 *filename, void *data, i32 size){ } internal Time_Stamp -system_file_time_stamp(u8 *filename){ +system_file_time_stamp(char *filename){ Time_Stamp result; result = {}; @@ -279,7 +312,7 @@ system_file_time_stamp(u8 *filename){ } internal u64 -system_get_now(){ +system_time_stamp_now(){ u64 result; SYSTEMTIME sys_now; FILETIME file_now; @@ -289,13 +322,23 @@ system_get_now(){ return result; } +internal i64 +system_time(){ + i64 result = 0; + LARGE_INTEGER time; + if (QueryPerformanceCounter(&time)){ + result = (i64)(time.QuadPart - win32vars.start_pcount) * 1000000 / win32vars.performance_frequency; + } + return result; +} + internal void system_free_file(File_Data data){ system_free_memory(data.data); } internal i32 -system_get_working_directory(u8 *destination, i32 max_size){ +system_get_current_directory(char *destination, i32 max_size){ DWORD required = GetCurrentDirectory(0, 0); if ((i32) required > max_size){ // TODO(allen): WHAT NOW? Not enough space in destination for @@ -307,7 +350,7 @@ system_get_working_directory(u8 *destination, i32 max_size){ } internal i32 -system_get_easy_directory(u8 *destination){ +system_get_easy_directory(char *destination){ persist char easydir[] = "C:\\"; for (i32 i = 0; i < ArrayCount(easydir); ++i){ destination[i] = easydir[i]; @@ -316,7 +359,7 @@ system_get_easy_directory(u8 *destination){ } internal File_List -system_get_files(String directory){ +system_get_file_list(String directory){ File_List result = {}; if (directory.size > 0){ @@ -393,63 +436,6 @@ system_free_file_list(File_List list){ system_free_memory(list.block); } -#if FRED_INTERNAL -Sys_Bubble INTERNAL_sentinel; - -internal Bubble* -INTERNAL_system_sentinel(){ - return &INTERNAL_sentinel; -} -#endif - -internal void* -system_get_memory_(i32 size, i32 line_number, char *file_name){ - void *ptr = 0; - -#if FRED_INTERNAL - ptr = VirtualAlloc(0, size + sizeof(Sys_Bubble), MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); - Sys_Bubble *bubble = (Sys_Bubble*)ptr; - bubble->flags = MEM_BUBBLE_SYS_DEBUG; - bubble->line_number = line_number; - bubble->file_name = file_name; - bubble->size = size; - WaitForSingleObject(win32vars.DEBUG_sysmem_lock, INFINITE); - insert_bubble(&INTERNAL_sentinel, bubble); - ReleaseSemaphore(win32vars.DEBUG_sysmem_lock, 1, 0); - ptr = bubble + 1; -#else - ptr = VirtualAlloc(0, size, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); -#endif - - return ptr; -} - -internal void -system_free_memory(void *block){ - if (block){ -#if FRED_INTERNAL - Sys_Bubble *bubble = ((Sys_Bubble*)block) - 1; - Assert((bubble->flags & MEM_BUBBLE_DEBUG_MASK) == MEM_BUBBLE_SYS_DEBUG); - WaitForSingleObject(win32vars.DEBUG_sysmem_lock, INFINITE); - remove_bubble(bubble); - ReleaseSemaphore(win32vars.DEBUG_sysmem_lock, 1, 0); - VirtualFree(bubble, 0, MEM_RELEASE); -#else - VirtualFree(block, 0, MEM_RELEASE); -#endif - } -} - -internal i64 -system_time(){ - i64 result = 0; - LARGE_INTEGER time; - if (QueryPerformanceCounter(&time)){ - result = (i64)(time.QuadPart - win32vars.start_pcount) * 1000000 / win32vars.performance_frequency; - } - return result; -} - // TODO(allen): Probably best to just drop all system functions here again. internal void system_post_clipboard(String str){ @@ -484,7 +470,9 @@ Win32RedrawScreen(HDC hdc){ win32vars.bmp_info.bmiHeader.biHeight = -win32vars.bmp_info.bmiHeader.biHeight; } + #else + internal void Win32RedrawScreen(HDC hdc){ glFlush(); @@ -534,7 +522,6 @@ Win32KeyboardHandle(bool8 current_state, bool8 previous_state, WPARAM wParam){ internal LRESULT Win32Callback(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam){ - LRESULT result = {}; switch (uMsg){ case WM_MENUCHAR: @@ -625,7 +612,6 @@ Win32Callback(HWND hwnd, UINT uMsg, win32vars.true_pixel_size = new_height*new_pitch; if (!win32vars.pixel_data){ - FatalError("Failure allocating new screen memory"); win32vars.keep_playing = 0; } } @@ -652,16 +638,11 @@ Win32Callback(HWND hwnd, UINT uMsg, HDC hdc = BeginPaint(hwnd, &ps); Clipboard_Contents empty_contents = {}; -#if FRED_INTERNAL - INTERNAL_collecting_events = 0; -#endif - app_step(&win32vars.main_thread, - &win32vars.key_codes, - &win32vars.previous_data, &win32vars.mouse, - 0, &win32vars.target, &win32memory, empty_contents, 0, 1); -#if FRED_INTERNAL - INTERNAL_collecting_events = 1; -#endif + win32vars.app.step(win32vars.system, + &win32vars.main_thread, &win32vars.key_codes, + &win32vars.previous_data, &win32vars.mouse, + 0, &win32vars.target, &win32memory, empty_contents, 0, 1); + Win32RedrawScreen(hdc); EndPaint(hwnd, &ps); @@ -726,7 +707,7 @@ ThreadProc(LPVOID lpParameter){ thread_memory->size = new_size; } } - full_job->job.callback(thread, thread_memory, full_job->job.data); + full_job->job.callback(win32vars.system, thread, thread_memory, full_job->job.data); full_job->running_thread = 0; thread->running = 0; } @@ -796,6 +777,16 @@ system_post_job(Thread_Group_ID group_id, Job_Data job){ return result; } +internal void +system_acquire_lock(i32 id){ + WaitForSingleObject(win32vars.locks[id], INFINITE); +} + +internal void +system_release_lock(i32 id){ + ReleaseSemaphore(win32vars.locks[id], 1, 0); +} + internal void system_cancel_job(Thread_Group_ID group_id, u32 job_id){ Work_Queue *queue = win32vars.queues + group_id; @@ -815,7 +806,7 @@ system_cancel_job(Thread_Group_ID group_id, u32 job_id){ 0, THREAD_NOT_ASSIGNED); if (thread_id != THREAD_NOT_ASSIGNED){ - system_aquire_lock(CANCEL_LOCK0 + thread_id - 1); + system_acquire_lock(CANCEL_LOCK0 + thread_id - 1); thread = group->threads + thread_id - 1; TerminateThread(thread->handle, 0); u32 creation_flag = 0; @@ -831,29 +822,9 @@ system_job_is_pending(Thread_Group_ID group_id, u32 job_id){ return Win32JobIsPending(queue, job_id); } -internal void -system_aquire_lock(Lock_ID id){ - WaitForSingleObject(win32vars.locks[id], INFINITE); -} - -internal void -system_release_lock(Lock_ID id){ - ReleaseSemaphore(win32vars.locks[id], 1, 0); -} - -internal void -system_aquire_lock(i32 id){ - WaitForSingleObject(win32vars.locks[id], INFINITE); -} - -internal void -system_release_lock(i32 id){ - ReleaseSemaphore(win32vars.locks[id], 1, 0); -} - internal void system_grow_thread_memory(Thread_Memory *memory){ - system_aquire_lock(CANCEL_LOCK0 + memory->id - 1); + system_acquire_lock(CANCEL_LOCK0 + memory->id - 1); void *old_data = memory->data; i32 old_size = memory->size; i32 new_size = LargeRoundUp(memory->size*2, Kbytes(4)); @@ -1012,13 +983,80 @@ system_cli_end_update(CLI_Handles *cli){ return close_me; } +internal b32 +Win32LoadAppCode(){ + b32 result = 0; + + win32vars.app_code = LoadLibraryA("4ed_app.dll"); + if (win32vars.app_code){ + result = 1; + win32vars.app.init = (App_Init*) + GetProcAddress(win32vars.app_code, "app_init"); + win32vars.app.step = (App_Step*) + GetProcAddress(win32vars.app_code, "app_step"); + } + + return result; +} + +internal void +Win32LoadSystemCode(){ + win32vars.system->load_file = system_load_file; + win32vars.system->save_file = system_save_file; + win32vars.system->file_time_stamp = system_file_time_stamp; + win32vars.system->time_stamp_now = system_time_stamp_now; + win32vars.system->free_file = system_free_file; + + win32vars.system->get_current_directory = system_get_current_directory; + win32vars.system->get_easy_directory = system_get_easy_directory; + + win32vars.system->get_file_list = system_get_file_list; + win32vars.system->free_file_list = system_free_file_list; + + win32vars.system->get_memory_full = system_get_memory_; + win32vars.system->free_memory = system_free_memory; + + win32vars.system->post_clipboard = system_post_clipboard; + win32vars.system->time = system_time; + + win32vars.system->cli_call = system_cli_call; + win32vars.system->cli_begin_update = system_cli_begin_update; + win32vars.system->cli_update_step = system_cli_update_step; + win32vars.system->cli_end_update = system_cli_end_update; + + win32vars.system->thread_get_id = system_thread_get_id; + win32vars.system->thread_current_job_id = system_thread_current_job_id; + win32vars.system->post_job = system_post_job; + win32vars.system->cancel_job = system_cancel_job; + win32vars.system->job_is_pending = system_job_is_pending; + win32vars.system->grow_thread_memory = system_grow_thread_memory; + win32vars.system->acquire_lock = system_acquire_lock; + win32vars.system->release_lock = system_release_lock; + + win32vars.system->force_redraw = system_force_redraw; + + win32vars.system->internal_sentinel = INTERNAL_system_sentinel; + win32vars.system->internal_get_thread_states = INTERNAL_get_thread_states; +} + int WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow){ win32vars = {}; - TEMP = {}; + config_api = {}; + + if (!Win32LoadAppCode()){ + // TODO(allen): Failed to load app code, serious problem. + return 99; + } + + System_Functions system_; + System_Functions *system = &system_; + win32vars.system = system; + Win32LoadSystemCode(); + LARGE_INTEGER lpf; QueryPerformanceFrequency(&lpf); win32vars.performance_frequency = lpf.QuadPart; @@ -1026,14 +1064,9 @@ WinMain(HINSTANCE hInstance, win32vars.start_pcount = lpf.QuadPart; #if FRED_INTERNAL - memset(INTERNAL_event_hits, 0, INTERNAL_event_index_count * sizeof(u32)); - INTERNAL_frame_index = 0; - INTERNAL_updating_profile = 1; - INTERNAL_collecting_events = 1; - - INTERNAL_sentinel.next = &INTERNAL_sentinel; - INTERNAL_sentinel.prev = &INTERNAL_sentinel; - INTERNAL_sentinel.flags = MEM_BUBBLE_SYS_DEBUG; + win32vars.internal_bubble.next = &win32vars.internal_bubble; + win32vars.internal_bubble.prev = &win32vars.internal_bubble; + win32vars.internal_bubble.flags = MEM_BUBBLE_SYS_DEBUG; #endif keycode_init(&win32vars.key_codes, &win32vars.loose_codes); @@ -1041,10 +1074,10 @@ WinMain(HINSTANCE hInstance, #ifdef FRED_SUPER win32vars.custom = LoadLibraryA("4coder_custom.dll"); if (win32vars.custom){ - TEMP.get_bindings = (Get_Binding_Data_Function*) + config_api.get_bindings = (Get_Binding_Data_Function*) GetProcAddress(win32vars.custom, "get_bindings"); - TEMP.set_extra_font = (Set_Extra_Font_Function*) + config_api.set_extra_font = (Set_Extra_Font_Function*) GetProcAddress(win32vars.custom, "set_extra_font"); } #endif @@ -1092,8 +1125,6 @@ WinMain(HINSTANCE hInstance, window_class.lpszClassName = "4coder-win32-wndclass"; if (!RegisterClass(&window_class)){ - // TODO(allen): diagnostics - FatalError("Failed to create window class"); return 1; } @@ -1122,8 +1153,6 @@ WinMain(HINSTANCE hInstance, 0, 0, hInstance, 0); if (!window_handle){ - // TODO(allen): diagnostics - FatalError("Failed to create window"); return 2; } @@ -1152,9 +1181,9 @@ WinMain(HINSTANCE hInstance, win32vars.pixel_data = system_get_memory(win32vars.true_pixel_size); if (!win32vars.pixel_data){ - FatalError("Failure allocating screen memory"); return 3; } + #else static PIXELFORMATDESCRIPTOR pfd = { sizeof(PIXELFORMATDESCRIPTOR), @@ -1215,7 +1244,6 @@ WinMain(HINSTANCE hInstance, PAGE_READWRITE); if (!win32memory.vars_memory){ - FatalError("Failure allocating application memory"); return 4; } @@ -1228,7 +1256,7 @@ WinMain(HINSTANCE hInstance, win32vars.next_clipboard_is_self = 0; if (win32vars.clipboard_sequence == 0){ - FatalError("Failure to access platform's clipboard"); + // TODO(allen): diagnostics } } else{ @@ -1248,63 +1276,36 @@ WinMain(HINSTANCE hInstance, } } - if (!app_init(&win32vars.main_thread, - &win32memory, &win32vars.key_codes, - win32vars.clipboard_contents)){ + if (!win32vars.app.init(win32vars.system, &win32vars.main_thread, + &win32memory, &win32vars.key_codes, + win32vars.clipboard_contents, config_api)){ return 5; } win32vars.keep_playing = 1; timeBeginPeriod(1); - system_aquire_lock(FRAME_LOCK); + system_acquire_lock(FRAME_LOCK); Thread_Context *thread = &win32vars.main_thread; AllowLocal(thread); bool32 first = 1; i64 timer_start = system_time(); while (win32vars.keep_playing){ -#if FRED_INTERNAL - i64 dbg_procing_start = system_time(); - if (!first){ - if (INTERNAL_updating_profile){ - i32 j = (INTERNAL_frame_index % 30); - Profile_Frame *frame = past_frames + j; - - sort(&profile_frame.events); - - frame->events.count = profile_frame.events.count; - memcpy(frame->events.e, profile_frame.events.e, sizeof(Debug_Event)*profile_frame.events.count); - - past_frames[j].dbg_procing_start = profile_frame.dbg_procing_start; - past_frames[j].dbg_procing_end = profile_frame.dbg_procing_end; - past_frames[j].index = profile_frame.index; - past_frames[j].first_key = profile_frame.first_key; - - ++INTERNAL_frame_index; - if (INTERNAL_frame_index < 0){ - INTERNAL_frame_index = ((INTERNAL_frame_index - 1) % 30) + 1; - } - memset(INTERNAL_event_hits, 0, INTERNAL_event_index_count * sizeof(u32)); - } - } - profile_frame.events.count = 0; - profile_frame.first_key = -1; - profile_frame.index = INTERNAL_frame_index; - INTERNAL_frame_start_time = timer_start; - profile_frame.dbg_procing_start = (i32)(dbg_procing_start - INTERNAL_frame_start_time); - profile_frame.dbg_procing_end = (i32)(system_time() - INTERNAL_frame_start_time); -#endif - ProfileStart(OS_input); win32vars.previous_data = win32vars.input_data; win32vars.input_data.press_count = 0; win32vars.input_data.hold_count = 0; win32vars.input_data.caps_lock = GetKeyState(VK_CAPITAL) & 0x1; - win32vars.input_data.control_keys[CONTROL_KEY_SHIFT] = (GetKeyState(VK_SHIFT) & 0x0100) >> 8; - win32vars.input_data.control_keys[CONTROL_KEY_CONTROL] = (GetKeyState(VK_CONTROL) & 0x0100) >> 8; - win32vars.input_data.control_keys[CONTROL_KEY_ALT] = (GetKeyState(VK_MENU) & 0x0100) >> 8; + win32vars.input_data.control_keys[CONTROL_KEY_SHIFT] = + (GetKeyState(VK_SHIFT) & 0x0100) >> 8; + + win32vars.input_data.control_keys[CONTROL_KEY_CONTROL] = + (GetKeyState(VK_CONTROL) & 0x0100) >> 8; + + win32vars.input_data.control_keys[CONTROL_KEY_ALT] = + (GetKeyState(VK_MENU) & 0x0100) >> 8; win32vars.mouse.left_button_prev = win32vars.mouse.left_button; win32vars.mouse.right_button_prev = win32vars.mouse.right_button; @@ -1391,13 +1392,13 @@ WinMain(HINSTANCE hInstance, ProfileEnd(OS_input); Application_Step_Result result = - app_step(&win32vars.main_thread, - &win32vars.key_codes, - &win32vars.input_data, &win32vars.mouse, - 1, &win32vars.target, - &win32memory, - win32vars.clipboard_contents, - first, redraw); + win32vars.app.step(win32vars.system, + &win32vars.main_thread, &win32vars.key_codes, + &win32vars.input_data, &win32vars.mouse, + 1, &win32vars.target, + &win32memory, + win32vars.clipboard_contents, + first, redraw); ProfileStart(OS_frame_out); first = 0; @@ -1428,7 +1429,7 @@ WinMain(HINSTANCE hInstance, if (samount > 0) Sleep(samount); timer_end = system_time(); } - system_aquire_lock(FRAME_LOCK); + system_acquire_lock(FRAME_LOCK); timer_start = system_time(); ProfileEnd(frame_sleep); } @@ -1436,10 +1437,6 @@ WinMain(HINSTANCE hInstance, return 0; } -#if FRED_INTERNAL -const i32 INTERNAL_event_index_count = __COUNTER__; -u32 INTERNAL_event_hits[__COUNTER__]; -#endif - // BOTTOM +