diff --git a/4coder_custom.cpp b/4coder_custom.cpp index bed69b15..91a498be 100644 --- a/4coder_custom.cpp +++ b/4coder_custom.cpp @@ -23,7 +23,7 @@ enum My_Maps{ HOOK_SIG(my_start){ exec_command(cmd_context, cmdid_open_panel_hsplit); exec_command(cmd_context, cmdid_change_active_panel); - + exec_command(cmd_context, cmdid_open_panel_vsplit); exec_command(cmd_context, cmdid_change_active_panel); } @@ -50,9 +50,9 @@ bool str_match(const char *a, int len_a, const char *b, int len_b){ HOOK_SIG(my_file_settings){ Buffer_Summary buffer = get_active_buffer(cmd_context); - + int treat_as_code = 0; - + // NOTE(allen|a3.1): This checks buffer.file_name just in case get_active_buffer returns back // a null buffer (where every member is 0). if (buffer.file_name && buffer.size < (16 << 20)){ @@ -63,7 +63,7 @@ HOOK_SIG(my_file_settings){ else if (str_match(extension, extension_len, literal("c"))) treat_as_code = 1; else if (str_match(extension, extension_len, literal("hpp"))) treat_as_code = 1; } - + push_parameter(app, cmd_context, par_lex_as_cpp_file, treat_as_code); push_parameter(app, cmd_context, par_wrap_lines, !treat_as_code); push_parameter(app, cmd_context, par_key_mapid, (treat_as_code)?(my_code_map):(mapid_file)); @@ -81,21 +81,21 @@ CUSTOM_COMMAND_SIG(open_my_files){ // cmdid_interactive_open behaves as usual. push_parameter(app, cmd_context, par_name, literal("w:/4ed/data/test/basic.cpp")); exec_command(cmd_context, cmdid_interactive_open); - + exec_command(cmd_context, cmdid_change_active_panel); - + char my_file[256]; int my_file_len; - + my_file_len = sizeof("w:/4ed/data/test/basic.txt") - 1; for (int i = 0; i < my_file_len; ++i){ my_file[i] = ("w:/4ed/data/test/basic.txt")[i]; } - + // NOTE(allen|a3.1): null terminators are not needed for strings. push_parameter(app, cmd_context, par_name, my_file, my_file_len); exec_command(cmd_context, cmdid_interactive_open); - + exec_command(cmd_context, cmdid_change_active_panel); } @@ -147,20 +147,20 @@ CUSTOM_COMMAND_SIG(build_search){ push_parameter(app, cmd_context, par_cli_overlap_with_conflict, 0); push_parameter(app, cmd_context, par_target_buffer_name, literal("*compilation*")); push_parameter(app, cmd_context, par_cli_path, dir.str, dir.size); - + if (append(&dir, "build")){ app->push_parameter(cmd_context, - dynamic_int(par_cli_command), - dynamic_string(dir.str, dir.size)); + dynamic_int(par_cli_command), + dynamic_string(dir.str, dir.size)); exec_command(cmd_context, cmdid_build); } else{ clear_parameters(cmd_context); } - + return; } - + if (app->directory_cd(&dir, "..") == 0){ keep_going = 0; } @@ -187,14 +187,14 @@ CUSTOM_COMMAND_SIG(cut_line){ extern "C" GET_BINDING_DATA(get_bindings){ Bind_Helper context_actual = begin_bind_helper(data, size); Bind_Helper *context = &context_actual; - + // NOTE(allen|a3.1): Right now hooks have no loyalties to maps, all hooks are // global and once set they always apply, regardless of what map is active. set_hook(context, hook_start, my_start); set_hook(context, hook_open_file, my_file_settings); - + begin_map(context, mapid_global); - + bind(context, 'p', MDFR_CTRL, cmdid_open_panel_vsplit); bind(context, '-', MDFR_CTRL, cmdid_open_panel_hsplit); bind(context, 'P', MDFR_CTRL, cmdid_close_panel); @@ -206,18 +206,18 @@ extern "C" GET_BINDING_DATA(get_bindings){ bind(context, 'c', MDFR_ALT, cmdid_open_color_tweaker); bind(context, 'x', MDFR_ALT, cmdid_open_menu); bind_me(context, 'o', MDFR_ALT, open_in_other); - + // NOTE(allen): These callbacks may not actually be useful to you, but // go look at them and see what they do. bind_me(context, 'M', MDFR_ALT | MDFR_CTRL, open_my_files); bind_me(context, 'M', MDFR_ALT, build_at_launch_location); bind_me(context, 'm', MDFR_ALT, build_search); - + end_map(context); - - + + begin_map(context, my_code_map); - + // NOTE(allen|a3.1): Set this map (my_code_map == mapid_user_custom) to // inherit from mapid_file. When searching if a key is bound // in this map, if it is not found here it will then search mapid_file. @@ -228,7 +228,7 @@ extern "C" GET_BINDING_DATA(get_bindings){ // NOTE(allen|a3.1): Children can override parent's bindings. bind(context, codes->right, MDFR_CTRL, cmdid_seek_alphanumeric_or_camel_right); bind(context, codes->left, MDFR_CTRL, cmdid_seek_alphanumeric_or_camel_left); - + // NOTE(allen|a3.2): Specific keys can override vanilla keys, // and write character writes whichever character corresponds // to the key that triggered the command. @@ -237,11 +237,11 @@ extern "C" GET_BINDING_DATA(get_bindings){ bind_me(context, ')', MDFR_NONE, write_and_auto_tab); bind_me(context, ']', MDFR_NONE, write_and_auto_tab); bind_me(context, ';', MDFR_NONE, write_and_auto_tab); - - bind(context, '\t', MDFR_NONE, cmdid_auto_tab_line_at_cursor); - bind(context, '\t', MDFR_CTRL, cmdid_auto_tab_range); - bind(context, '\t', MDFR_CTRL | MDFR_SHIFT, cmdid_write_character); + bind(context, '\t', MDFR_NONE, cmdid_word_complete); + bind(context, '\t', MDFR_CTRL, cmdid_auto_tab_range); + bind(context, '\t', MDFR_SHIFT, cmdid_auto_tab_line_at_cursor); + end_map(context); diff --git a/4coder_custom.h b/4coder_custom.h index f67b6623..084cb646 100644 --- a/4coder_custom.h +++ b/4coder_custom.h @@ -64,6 +64,7 @@ enum Command_ID{ cmdid_seek_alphanumeric_or_camel_right, cmdid_search, cmdid_rsearch, + cmdid_word_complete, cmdid_goto_line, cmdid_set_mark, cmdid_copy, @@ -96,7 +97,6 @@ enum Command_ID{ cmdid_clean_all_lines, cmdid_eol_dosify, cmdid_eol_nixify, - cmdid_auto_tab, cmdid_auto_tab_range, cmdid_auto_tab_line_at_cursor, cmdid_auto_tab_whole_file, diff --git a/4coder_string.h b/4coder_string.h index 36daa985..98dc3d39 100644 --- a/4coder_string.h +++ b/4coder_string.h @@ -173,6 +173,7 @@ FCPP_LINK int reverse_seek_slash(String str); FCPP_LINK int reverse_seek_slash(String str, int start_pos); inline bool get_front_of_directory(String *dest, String dir) { return append_checked(dest, substr(dir, reverse_seek_slash(dir) + 1)); } inline bool get_path_of_directory(String *dest, String dir) { return append_checked(dest, substr(dir, 0, reverse_seek_slash(dir) + 1)); } +inline void truncate_to_path_of_directory(String *dir) { dir->size = reverse_seek_slash(*dir) + 1; } FCPP_LINK bool set_last_folder(String *dir, char *folder_name); FCPP_LINK bool set_last_folder(String *dir, String folder_name); FCPP_LINK String file_extension(String str); diff --git a/4ed.cpp b/4ed.cpp index af0722f8..91d8d17b 100644 --- a/4ed.cpp +++ b/4ed.cpp @@ -44,6 +44,7 @@ struct Complete_State{ Table hits; String_Space str; i32 word_start, word_end; + b32 initialized; }; struct App_Vars{ @@ -487,6 +488,10 @@ COMMAND_DECL(word_complete){ if (vars->prev_command.function != command_word_complete){ do_init = 1; } + + if (complete_state->initialized == 0){ + do_init = 1; + } if (do_init){ word_end = view->cursor.pos; @@ -514,6 +519,12 @@ COMMAND_DECL(word_complete){ size = word_end - word_start; + if (size == 0){ + complete_state->initialized = 0; + return; + } + + complete_state->initialized = 1; search_iter_init(general, &complete_state->iter, size); buffer_stringify(buffer, word_start, word_end, complete_state->iter.word.str); complete_state->iter.word.size = size; @@ -863,65 +874,6 @@ COMMAND_DECL(interactive_new){ copy(&int_view->query, "New: "); } -#if 0 -internal File_View* -app_open_file(System_Functions *system, Exchange *exchange, - 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; - Editing_File *target_file = 0; - b32 created_file = 0; - - target_file = working_set_contains(working_set, *string); - if (!target_file){ - Get_File_Result file = working_set_get_available_file(working_set); - if (file.file){ - file_get_dummy(file.file); - 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; - } - } - } - - if (target_file){ - View *new_view = live_set_alloc_view(live_set, &vars->mem); - - view_replace_major(system, exchange, new_view, panel, live_set); - - File_View *file_view = file_view_init(new_view, &vars->layout); - result = file_view; - - View *old_view = command_data->view; - command_data->view = new_view; - - Partition old_part = command_data->part; - Temp_Memory temp = begin_temp_memory(&vars->mem.part); - command_data->part = partition_sub_part(&vars->mem.part, 16 << 10); - - view_set_file(system, file_view, target_file, style, - vars->hooks[hook_open_file], command_data, &app_links); - - command_data->part = old_part; - end_temp_memory(temp); - command_data->view = old_view; - - new_view->map = app_get_map(vars, target_file->base_map_id); - -#if BUFFER_EXPERIMENT_SCALPEL <= 0 - if (created_file && target_file->tokens_exist && - target_file->token_stack.tokens == 0){ - file_first_lex_parallel(system, &mem->general, target_file); - } -#endif - } - - return result; -} -#endif - internal void app_push_file_binding(App_Vars *vars, int sys_id, int app_id){ Sys_App_Binding binding; @@ -951,7 +903,7 @@ app_open_file_background(App_Vars *vars, Exchange *exchange, Working_Set *workin result.is_new = 1; result.file = file.file; file_init_strings(result.file); - file_set_name(result.file, filename.str); + file_set_name(working_set, result.file, filename.str); file_set_to_loading(result.file); table_add(&working_set->table, result.file->name.source_path, file.index); @@ -1311,21 +1263,6 @@ COMMAND_DECL(eol_nixify){ file->state.last_4ed_edit_time = system->time(); } -COMMAND_DECL(auto_tab){ -#if 0 - ProfileMomentFunction(); - REQ_FILE_VIEW(view); - REQ_FILE(file, view); - USE_LAYOUT(layout); - USE_MEM(mem); - - 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); - } -#endif -} - COMMAND_DECL(auto_tab_range){ ProfileMomentFunction(); REQ_FILE_VIEW(view); @@ -1887,7 +1824,7 @@ build(System_Functions *system, Mem_Options *mem, } if (file){ - file_create_super_locked(system, mem, file, buffer_name, font_set, style->font_id); + file_create_super_locked(system, mem, working_set, file, buffer_name, font_set, style->font_id); file->settings.unimportant = 1; table_add(&working_set->table, file->name.source_path, index); @@ -2246,7 +2183,6 @@ setup_file_commands(Command_Map *commands, Partition *part, Key_Codes *codes, Co map_add(commands, 'j', MDFR_CTRL, command_to_lowercase); map_add(commands, '~', MDFR_CTRL, command_clean_all_lines); map_add(commands, 'f', MDFR_CTRL, command_search); - map_add(commands, 't', MDFR_CTRL, command_word_complete); map_add(commands, 'r', MDFR_CTRL, command_rsearch); map_add(commands, 'g', MDFR_CTRL, command_goto_line); @@ -2257,9 +2193,9 @@ setup_file_commands(Command_Map *commands, Partition *part, Key_Codes *codes, Co map_add(commands, ']', MDFR_NONE, compose_write_auto_tab_line); map_add(commands, ';', MDFR_NONE, compose_write_auto_tab_line); - map_add(commands, '\t', MDFR_NONE, command_auto_tab_line_at_cursor); + map_add(commands, '\t', MDFR_NONE, command_word_complete); map_add(commands, '\t', MDFR_CTRL, command_auto_tab_range); - map_add(commands, '\t', MDFR_CTRL | MDFR_SHIFT, command_write_character); + map_add(commands, '\t', MDFR_SHIFT, command_auto_tab_line_at_cursor); map_add(commands, 'K', MDFR_CTRL, command_kill_buffer); map_add(commands, 'O', MDFR_CTRL, command_reopen); @@ -2312,6 +2248,7 @@ setup_command_table(){ SET(seek_alphanumeric_or_camel_left); SET(search); SET(rsearch); + SET(word_complete); SET(goto_line); SET(set_mark); SET(copy); @@ -2343,7 +2280,6 @@ setup_command_table(){ SET(clean_all_lines); SET(eol_dosify); SET(eol_nixify); - SET(auto_tab); SET(auto_tab_range); SET(auto_tab_line_at_cursor); SET(auto_tab_whole_file); @@ -3629,7 +3565,7 @@ App_Step_Sig(app_step){ if (fview){ Editing_File *file = fview->file; if (file && !file->state.is_dummy){ - i32 sys_id = file_save_and_set_names(system, exchange, mem, file, string->str); + i32 sys_id = file_save_and_set_names(system, exchange, mem, working_set, file, string->str); app_push_file_binding(vars, sys_id, get_file_id(working_set, file)); } } @@ -3647,7 +3583,7 @@ App_Step_Sig(app_step){ case DACT_NEW: { Get_File_Result file = working_set_get_available_file(working_set); - file_create_empty(system, mem, file.file, string->str, + file_create_empty(system, mem, working_set, file.file, string->str, vars->font_set, style->font_id); table_add(&working_set->table, file.file->name.source_path, file.index); @@ -3818,20 +3754,22 @@ App_Step_Sig(app_step){ Editing_File_Preload preload_settings; char *filename; + Working_Set *working_set = &vars->working_set; + if (exchange_file_ready(exchange, binding->sys_id, &data, &size, &max)){ - ed_file = vars->working_set.files + binding->app_id; + ed_file = working_set->files + binding->app_id; filename = exchange_file_filename(exchange, binding->sys_id); preload_settings = ed_file->preload; if (data){ String val = make_string((char*)data, size); - file_create_from_string(system, &vars->mem, ed_file, filename, + file_create_from_string(system, &vars->mem, working_set, ed_file, filename, vars->font_set, vars->style.font_id, val); if (ed_file->settings.tokens_exist) file_first_lex_parallel(system, &vars->mem.general, ed_file); } else{ - file_create_empty(system, &vars->mem, ed_file, filename, + file_create_empty(system, &vars->mem, working_set, ed_file, filename, vars->font_set, vars->style.font_id); } @@ -3854,7 +3792,7 @@ App_Step_Sig(app_step){ exchange_clear_file(exchange, binding->sys_id); } - Editing_File *file = get_file(&vars->working_set, binding->app_id); + Editing_File *file = get_file(working_set, binding->app_id); if (file){ file_synchronize_times(system, file, file->name.source_path.str); } diff --git a/4ed_command.cpp b/4ed_command.cpp index 6b519872..c53084da 100644 --- a/4ed_command.cpp +++ b/4ed_command.cpp @@ -1,163 +1,165 @@ -/* - * Mr. 4th Dimention - Allen Webster - * - * 19.08.2015 - * - * Command management functions for 4coder - * - */ - -// TOP - -#define Command_Function_Sig(name) void (name)( \ - System_Functions *system, \ - struct Command_Data *command, \ - struct Command_Binding binding) - -typedef Command_Function_Sig(*Command_Function); - -struct Command_Binding{ - Command_Function function; - Custom_Command_Function *custom; - i64 hash; -}; - -struct Command_Map{ - Command_Map *parent; - Command_Binding vanilla_keyboard_default; - Command_Binding *commands; - i32 count, max; -}; - -internal void command_null(Command_Data *command); - -internal i64 -map_hash(u16 event_code, u8 modifiers){ - i64 result = (event_code << 8) | modifiers; - return result; -} - -internal b32 -map_add(Command_Map *map, u16 event_code, u8 modifiers, - Command_Function function, Custom_Command_Function *custom = 0){ - Assert(map->count * 8 < map->max * 7); - Command_Binding bind; - bind.function = function; - bind.custom = custom; - bind.hash = map_hash(event_code, modifiers); - - i32 max = map->max; - i32 index = bind.hash % max; - Command_Binding entry; - while ((entry = map->commands[index]).function && entry.hash != -1){ - if (entry.hash == bind.hash){ - return 1; - } - index = (index + 1) % max; - } - map->commands[index] = bind; - ++map->count; - return 0; -} - -internal b32 -map_find_entry(Command_Map *map, u16 event_code, u8 modifiers, - i32 *index_out){ - i64 hash = map_hash(event_code, modifiers); - i32 max = map->max; - i32 index = hash % map->max; - Command_Binding entry; - while ((entry = map->commands[index]).function){ - if (entry.hash == hash){ - *index_out = index; - return 1; - } - index = (index + 1) % max; - } - return 0; -} - -internal b32 -map_find(Command_Map *map, u16 event_code, u8 modifiers, - Command_Binding *bind_out){ - b32 result; - i32 index; - result = map_find_entry(map, event_code, modifiers, &index); - if (result){ - *bind_out = map->commands[index]; - } - return result; -} - -internal b32 -map_drop(Command_Map *map, u16 event_code, u8 modifiers){ - b32 result; - i32 index; - result = map_find_entry(map, event_code, modifiers, &index); - if (result){ - map->commands[index].function = 0; - map->commands[index].hash = -1; - } - return result; -} - -internal void -map_init(Command_Map *commands, Partition *part, i32 max, Command_Map *parent){ - max = ((max < 6)?(6):(max)); - commands->parent = parent; - commands->commands = push_array(part, Command_Binding, max); - memset(commands->commands, 0, max*sizeof(*commands->commands)); - commands->vanilla_keyboard_default = {}; - commands->max = max; - commands->count = 0; -} - -internal void -map_get_vanilla_keyboard_default(Command_Map *map, u8 command, - Command_Binding *bind_out){ - if (command == MDFR_NONE){ - *bind_out = map->vanilla_keyboard_default; - } -} - -inline u8 -apply_shift_to_code(u8 keycode){ - return !(keycode >= 0x20 && keycode < 0x7F && keycode != ' '); -} - -internal Command_Binding -map_extract(Command_Map *map, Key_Event_Data key){ - Command_Binding bind = {}; - - b32 ctrl = key.modifiers[CONTROL_KEY_CONTROL]; - b32 alt = key.modifiers[CONTROL_KEY_ALT]; - b32 shift = key.modifiers[CONTROL_KEY_SHIFT]; - u16 code; - u8 command = MDFR_NONE; - - if (key.character_no_caps_lock != 0 && - key.character_no_caps_lock != ' ') shift = 0; - - if (shift) command |= MDFR_SHIFT; - if (ctrl) command |= MDFR_CTRL; - if (alt) command |= MDFR_ALT; - - code = key.character_no_caps_lock; - if (code == 0){ - code = key.keycode; - map_find(map, code, command, &bind); - } - else{ - command &= ~(MDFR_SHIFT); - - map_find(map, code, command, &bind); - if (bind.function == 0){ - map_get_vanilla_keyboard_default(map, command, &bind); - } - } - - return bind; -} - -// BOTTOM - +/* + * Mr. 4th Dimention - Allen Webster + * + * 19.08.2015 + * + * Command management functions for 4coder + * + */ + +// TOP + +#define Command_Function_Sig(name) void (name)( \ + System_Functions *system, \ + struct Command_Data *command, \ + struct Command_Binding binding) + +typedef Command_Function_Sig(*Command_Function); + +struct Command_Binding{ + Command_Function function; + Custom_Command_Function *custom; + i64 hash; +}; + +struct Command_Map{ + Command_Map *parent; + Command_Binding vanilla_keyboard_default; + Command_Binding *commands; + i32 count, max; +}; + +internal void command_null(Command_Data *command); + +internal i64 +map_hash(u16 event_code, u8 modifiers){ + i64 result = (event_code << 8) | modifiers; + return result; +} + +internal b32 +map_add(Command_Map *map, u16 event_code, u8 modifiers, + Command_Function function, Custom_Command_Function *custom = 0){ + Assert(map->count * 8 < map->max * 7); + Command_Binding bind; + bind.function = function; + bind.custom = custom; + bind.hash = map_hash(event_code, modifiers); + + i32 max = map->max; + i32 index = bind.hash % max; + Command_Binding entry; + while ((entry = map->commands[index]).function && entry.hash != -1){ + if (entry.hash == bind.hash){ + return 1; + } + index = (index + 1) % max; + } + map->commands[index] = bind; + ++map->count; + return 0; +} + +internal b32 +map_find_entry(Command_Map *map, u16 event_code, u8 modifiers, + i32 *index_out){ + i64 hash = map_hash(event_code, modifiers); + i32 max = map->max; + i32 index = hash % map->max; + Command_Binding entry; + while ((entry = map->commands[index]).function){ + if (entry.hash == hash){ + *index_out = index; + return 1; + } + index = (index + 1) % max; + } + return 0; +} + +internal b32 +map_find(Command_Map *map, u16 event_code, u8 modifiers, + Command_Binding *bind_out){ + b32 result; + i32 index; + result = map_find_entry(map, event_code, modifiers, &index); + if (result){ + *bind_out = map->commands[index]; + } + return result; +} + +internal b32 +map_drop(Command_Map *map, u16 event_code, u8 modifiers){ + b32 result; + i32 index; + result = map_find_entry(map, event_code, modifiers, &index); + if (result){ + map->commands[index].function = 0; + map->commands[index].hash = -1; + } + return result; +} + +internal void +map_init(Command_Map *commands, Partition *part, i32 max, Command_Map *parent){ + max = ((max < 6)?(6):(max)); + commands->parent = parent; + commands->commands = push_array(part, Command_Binding, max); + memset(commands->commands, 0, max*sizeof(*commands->commands)); + commands->vanilla_keyboard_default = {}; + commands->max = max; + commands->count = 0; +} + +internal void +map_get_vanilla_keyboard_default(Command_Map *map, u8 command, + Command_Binding *bind_out){ + if (command == MDFR_NONE){ + *bind_out = map->vanilla_keyboard_default; + } +} + +inline u8 +apply_shift_to_code(u8 keycode){ + return !(keycode >= 0x20 && keycode < 0x7F && keycode != ' '); +} + +internal Command_Binding +map_extract(Command_Map *map, Key_Event_Data key){ + Command_Binding bind = {}; + + b32 ctrl = key.modifiers[CONTROL_KEY_CONTROL]; + b32 alt = key.modifiers[CONTROL_KEY_ALT]; + b32 shift = key.modifiers[CONTROL_KEY_SHIFT]; + u16 code; + u8 command = MDFR_NONE; + + //if (key.character_no_caps_lock != 0 && + // key.character_no_caps_lock != ' ') shift = 0; + + if (shift) command |= MDFR_SHIFT; + if (ctrl) command |= MDFR_CTRL; + if (alt) command |= MDFR_ALT; + + code = key.character_no_caps_lock; + if (code == 0){ + code = key.keycode; + map_find(map, code, command, &bind); + } + else{ + if (code != '\n' && code != '\t' && code != ' '){ + command &= ~(MDFR_SHIFT); + } + + map_find(map, code, command, &bind); + if (bind.function == 0){ + map_get_vanilla_keyboard_default(map, command, &bind); + } + } + + return bind; +} + +// BOTTOM + diff --git a/4ed_file_view.cpp b/4ed_file_view.cpp index fc10f919..aca25ace 100644 --- a/4ed_file_view.cpp +++ b/4ed_file_view.cpp @@ -1203,16 +1203,30 @@ file_init_strings(Editing_File *file){ file->name.extension = make_fixed_width_string(file->name.extension_); } +inline b32 +file_is_ready(Editing_File *file){ + b32 result = 0; + if (file && file->state.is_loading == 0){ + result = 1; + } + return(result); +} + inline void -file_set_name(Editing_File *file, char *filename){ +file_set_name(Working_Set *working_set, Editing_File *file, char *filename){ String f, ext; + Editing_File *file_ptr; + i32 i, count, file_x, original_len; + b32 hit_conflict; Assert(file->name.live_name.str != 0); f = make_string_slowly(filename); copy_checked(&file->name.source_path, f); + file->name.live_name.size = 0; get_front_of_directory(&file->name.live_name, f); + if (file->name.source_path.size == file->name.live_name.size){ file->name.extension.size = 0; } @@ -1220,6 +1234,31 @@ file_set_name(Editing_File *file, char *filename){ ext = file_extension(f); copy(&file->name.extension, ext); } + + original_len = file->name.live_name.size; + count = working_set->file_index_count; + hit_conflict = 1; + file_x = 0; + while (hit_conflict){ + hit_conflict = 0; + file_ptr = working_set->files; + for (i = 0; i < count; ++i, ++file_ptr){ + if (file_ptr != file && !file_ptr->state.is_dummy && file_is_ready(file_ptr)){ + if (match(file->name.live_name, file_ptr->name.live_name)){ + ++file_x; + hit_conflict = 1; + break; + } + } + } + + if (hit_conflict){ + file->name.live_name.size = original_len; + append(&file->name.live_name, " <"); + append_int_to_str(file_x, &file->name.live_name); + append(&file->name.live_name, ">"); + } + } } inline void @@ -1271,11 +1310,12 @@ file_save(System_Functions *system, Exchange *exchange, Mem_Options *mem, inline b32 file_save_and_set_names(System_Functions *system, Exchange *exchange, - Mem_Options *mem, Editing_File *file, char *filename){ + Mem_Options *mem, Working_Set *working_set, Editing_File *file, + char *filename){ b32 result = 0; result = file_save(system, exchange, mem, file, filename); if (result){ - file_set_name(file, filename); + file_set_name(working_set, file, filename); } return result; } @@ -1501,9 +1541,10 @@ alloc_for_buffer(void *context, int *size){ internal void file_create_from_string(System_Functions *system, Mem_Options *mem, - Editing_File *file, char *filename, - Font_Set *set, i16 font_id, - String val, b8 super_locked = 0){ + Working_Set *working_set, Editing_File *file, char *filename, + Font_Set *set, i16 font_id, + String val, b8 super_locked = 0){ + General_Memory *general = &mem->general; Partition *part = &mem->part; Buffer_Init_Type init; @@ -1529,7 +1570,7 @@ file_create_from_string(System_Functions *system, Mem_Options *mem, #endif file_init_strings(file); - file_set_name(file, (char*)filename); + file_set_name(working_set, file, (char*)filename); file->state.font_id = font_id; @@ -1570,20 +1611,25 @@ file_create_from_string(System_Functions *system, Mem_Options *mem, } internal b32 -file_create_empty(System_Functions *system, Mem_Options *mem, Editing_File *file, - char *filename, Font_Set *set, i16 font_id){ +file_create_empty( + System_Functions *system, Mem_Options *mem, + Working_Set *working_set, Editing_File *file, + char *filename, Font_Set *set, i16 font_id){ + b32 result = 1; String empty_str = {}; - file_create_from_string(system, mem, file, filename, set, font_id, empty_str); + file_create_from_string(system, mem, working_set, file, filename, set, font_id, empty_str); return result; } internal b32 -file_create_super_locked(System_Functions *system, Mem_Options *mem, Editing_File *file, - char *filename, Font_Set *set, i16 font_id){ +file_create_super_locked( + System_Functions *system, Mem_Options *mem, + Working_Set *working_set, Editing_File *file, + char *filename, Font_Set *set, i16 font_id){ b32 result = 1; String empty_str = {}; - file_create_from_string(system, mem, file, filename, set, font_id, empty_str, 1); + file_create_from_string(system, mem, working_set, file, filename, set, font_id, empty_str, 1); return result; } @@ -1671,15 +1717,6 @@ file_set_to_loading(Editing_File *file){ file->state.is_loading = 1; } -inline b32 -file_is_ready(Editing_File *file){ - b32 result = 0; - if (file && file->state.is_loading == 0){ - result = 1; - } - return(result); -} - struct Shift_Information{ i32 start, end, amount; }; @@ -2826,14 +2863,6 @@ file_do_single_edit(System_Functions *system, void *old_data = buffer_edit_provide_memory(&file->state.buffer, new_data, request_amount); if (old_data) general_memory_free(general, old_data); } - -#if BUFFER_EXPERIMENT_SCALPEL == 3 - buffer_rope_check(&file->buffer, part->base + part->pos, scratch_size); -#endif - -#if BUFFER_EXPERIMENT_SCALPEL == 2 - buffer_mugab_check(&file->buffer); -#endif i32 line_start = buffer_get_line_index(&file->state.buffer, start); i32 line_end = buffer_get_line_index(&file->state.buffer, end); @@ -3544,8 +3573,8 @@ view_auto_tab_tokens(System_Functions *system, i32 start = file->state.buffer.line_starts[line_i]; i32 preferred_indentation; i32 correct_indentation; - bool32 all_whitespace = 0; - bool32 all_space = 0; + b32 all_whitespace = 0; + b32 all_space = 0; i32 hard_start = buffer_find_hard_start(&file->state.buffer, start, &all_whitespace, &all_space, &preferred_indentation, 4); @@ -3565,6 +3594,7 @@ view_auto_tab_tokens(System_Functions *system, new_edit.end = hard_start; edits[edit_count++] = new_edit; } + Assert(edit_count <= edit_max); } @@ -3583,6 +3613,18 @@ view_auto_tab_tokens(System_Functions *system, view_do_white_batch_edit(system, mem, view, file, layout, spec, hist_normal); } + { + b32 all_whitespace = 0; + b32 all_space = 0; + i32 preferred_indentation; + i32 start = view->cursor.pos; + i32 hard_start = buffer_find_hard_start( + &file->state.buffer, start, &all_whitespace, &all_space, + &preferred_indentation, 4); + + view_cursor_move(view, hard_start); + } + end_temp_memory(temp); #endif } diff --git a/4ed_layout.cpp b/4ed_layout.cpp index 7cbfab3e..4a973db1 100644 --- a/4ed_layout.cpp +++ b/4ed_layout.cpp @@ -1,527 +1,545 @@ -/* - * Mr. 4th Dimention - Allen Webster - * - * 19.08.2015 - * - * Panel layout and general view functions for 4coder - * - */ - -// TOP -// TODO(allen): -// -// BUGS -// - -struct Interactive_Style{ - u32 bar_color; - u32 bar_active_color; - u32 base_color; - u32 pop1_color; - u32 pop2_color; -}; - -struct Interactive_Bar{ - Interactive_Style style; - real32 pos_x, pos_y; - real32 text_shift_x, text_shift_y; - i32_Rect rect; - i16 font_id; -}; - -enum View_Message{ - VMSG_STEP, - VMSG_DRAW, - VMSG_RESIZE, - VMSG_STYLE_CHANGE, - VMSG_FREE -}; - -struct View; -#define Do_View_Sig(name) \ - i32 (name)(System_Functions *system, Exchange *exchange, \ - 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)(System_Functions *system, View *view, \ - Command_Data *command, Command_Binding binding, \ - Key_Event_Data key, Key_Codes *codes) - -typedef HANDLE_COMMAND_SIG(Handle_Command_Function); - -// TODO(allen): this shouldn't exist -enum View_Type{ - VIEW_TYPE_NONE, - VIEW_TYPE_FILE, - VIEW_TYPE_COLOR, - VIEW_TYPE_DEBUG, - VIEW_TYPE_INTERACTIVE, - VIEW_TYPE_MENU, - VIEW_TYPE_CONFIG -}; - -struct Panel; -struct View{ - union{ - View *next_free; - View *major; - View *minor; - }; - Panel *panel; - Command_Map *map; - Do_View_Function *do_view; - Handle_Command_Function *handle_command; - Mem_Options *mem; - i32 type; - i32 block_size; - Application_Mouse_Cursor mouse_cursor_type; - b32 is_active; - b32 is_minor; -}; - -struct Live_Views{ - void *views; - View *free_view; - i32 count, max; - i32 stride; -}; - -struct Panel_Divider{ - Panel_Divider *next_free; - i32 parent; - i32 which_child; - i32 child1, child2; - bool32 v_divider; - i32 pos; -}; - -struct Screen_Region{ - i32_Rect full; - i32_Rect inner; - i32_Rect prev_inner; - i32 l_margin, r_margin; - i32 t_margin, b_margin; -}; - -struct Panel{ - View *view; - i32 parent; - i32 which_child; - union{ - struct{ - i32_Rect full; - i32_Rect inner; - i32_Rect prev_inner; - i32 l_margin, r_margin; - i32 t_margin, b_margin; - }; - Screen_Region screen_region; - }; -}; - -struct Editing_Layout{ - Panel *panels; - Panel_Divider *dividers; - Panel_Divider *free_divider; - i32 panel_count, panel_max_count; - i32 root; - i32 active_panel; - i32 full_width, full_height; -}; - -internal void -intbar_draw_string(Render_Target *target, - Interactive_Bar *bar, u8 *str, u32 char_color){ - i16 font_id = bar->font_id; - for (i32 i = 0; str[i]; ++i){ - char c = str[i]; - font_draw_glyph(target, font_id, c, - bar->pos_x + bar->text_shift_x, - bar->pos_y + bar->text_shift_y, - char_color); - bar->pos_x += font_get_glyph_width(target, font_id, c); - } -} - -internal void -intbar_draw_string(Render_Target *target, Interactive_Bar *bar, - String str, u32 char_color){ - i16 font_id = bar->font_id; - for (i32 i = 0; i < str.size; ++i){ - char c = str.str[i]; - font_draw_glyph(target, font_id, c, - bar->pos_x + bar->text_shift_x, - bar->pos_y + bar->text_shift_y, - char_color); - bar->pos_x += font_get_glyph_width(target, font_id, c); - } -} - -internal void -panel_init(Panel *panel){ - *panel = {}; - panel->parent = -1; - panel->l_margin = 3; - panel->r_margin = 3; - panel->t_margin = 3; - panel->b_margin = 3; -} - -internal View* -live_set_get_view(Live_Views *live_set, i32 i){ - void *result = ((char*)live_set->views + i*live_set->stride); - return (View*)result; -} - -internal View* -live_set_alloc_view(Live_Views *live_set, Mem_Options *mem){ - Assert(live_set->count < live_set->max); - View *result = 0; - result = live_set->free_view; - live_set->free_view = result->next_free; - memset(result, 0, live_set->stride); - ++live_set->count; - result->is_active = 1; - result->mem = mem; - return result; -} - -inline void -live_set_free_view(System_Functions *system, Exchange *exchange, Live_Views *live_set, View *view){ - Assert(live_set->count > 0); - view->do_view(system, exchange, view, {}, 0, VMSG_FREE, 0, {}, 0); - view->next_free = live_set->free_view; - live_set->free_view = view; - --live_set->count; - view->is_active = 0; -} - -inline void -view_replace_major(System_Functions *system, Exchange *exchange, - 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(system, exchange, live_set, view->major); - } - live_set_free_view(system, exchange, live_set, view); - } - new_view->panel = panel; - new_view->minor = 0; - panel->view = new_view; -} - -inline void -view_replace_minor(System_Functions *system, Exchange *exchange, - 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(system, exchange, live_set, view); - } - else{ - new_view->major = view; - view->is_active = 0; - } - } - else{ - new_view->major = 0; - } - new_view->panel = panel; - panel->view = new_view; -} - -inline void -view_remove_major(System_Functions *system, Exchange *exchange, - Panel *panel, Live_Views *live_set){ - View *view = panel->view; - if (view){ - if (view->is_minor && view->major){ - live_set_free_view(system, exchange, live_set, view->major); - } - live_set_free_view(system, exchange, live_set, view); - } - panel->view = 0; -} - -inline void -view_remove_major_leave_minor(System_Functions *system, Exchange *exchange, - Panel *panel, Live_Views *live_set){ - View *view = panel->view; - if (view){ - if (view->is_minor && view->major){ - live_set_free_view(system, exchange, live_set, view->major); - view->major = 0; - } - else{ - live_set_free_view(system, exchange, live_set, view); - panel->view = 0; - } - } -} - -inline void -view_remove_minor(System_Functions *system, Exchange *exchange, - 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(system, exchange, live_set, view); - } - } - panel->view = major; - if (major) major->is_active = 1; -} - -inline void -view_remove(System_Functions *system, Exchange *exchange, - Panel *panel, Live_Views *live_set){ - View *view = panel->view; - if (view->is_minor) view_remove_minor(system, exchange, panel, live_set); - else view_remove_major(system, exchange, panel, live_set); -} - -struct Divider_And_ID{ - Panel_Divider* divider; - i32 id; -}; - -internal Divider_And_ID -layout_alloc_divider(Editing_Layout *layout){ - Assert(layout->free_divider); - Divider_And_ID result; - result.divider = layout->free_divider; - layout->free_divider = result.divider->next_free; - *result.divider = {}; - result.divider->parent = -1; - result.divider->child1 = -1; - result.divider->child2 = -1; - result.id = (i32)(result.divider - layout->dividers); - if (layout->panel_count == 1){ - layout->root = result.id; - } - return result; -} - -internal Divider_And_ID -layout_get_divider(Editing_Layout *layout, i32 id){ - Assert(id >= 0 && id < layout->panel_max_count-1); - Divider_And_ID result; - result.id = id; - result.divider = layout->dividers + id; - return result; -} - -internal Panel* -layout_alloc_panel(Editing_Layout *layout){ - Assert(layout->panel_count < layout->panel_max_count); - Panel *result = layout->panels + layout->panel_count; - *result = {}; - ++layout->panel_count; - return result; -} - -internal void -layout_free_divider(Editing_Layout *layout, Panel_Divider *divider){ - divider->next_free = layout->free_divider; - layout->free_divider = divider; -} - -internal void -layout_free_panel(Editing_Layout *layout, Panel *panel){ - Panel *panels = layout->panels; - i32 panel_count = --layout->panel_count; - i32 panel_i = (i32)(panel - layout->panels); - for (i32 i = panel_i; i < panel_count; ++i){ - Panel *p = panels + i; - *p = panels[i+1]; - if (p->view){ - p->view->panel = p; - } - } -} - -internal Divider_And_ID -layout_calc_divider_id(Editing_Layout *layout, Panel_Divider *divider){ - Divider_And_ID result; - result.divider = divider; - result.id = (i32)(divider - layout->dividers); - return result; -} - -struct Split_Result{ - Panel_Divider *divider; - Panel *panel; -}; - -internal Split_Result -layout_split_panel(Editing_Layout *layout, Panel *panel, bool32 vertical){ - Divider_And_ID div = layout_alloc_divider(layout); - if (panel->parent != -1){ - Divider_And_ID pdiv = layout_get_divider(layout, panel->parent); - if (panel->which_child == -1){ - pdiv.divider->child1 = div.id; - } - else{ - pdiv.divider->child2 = div.id; - } - } - - div.divider->parent = panel->parent; - div.divider->which_child = panel->which_child; - if (vertical){ - div.divider->v_divider = 1; - div.divider->pos = (panel->full.x0 + panel->full.x1) / 2; - } - else{ - div.divider->v_divider = 0; - div.divider->pos = (panel->full.y0 + panel->full.y1) / 2; - } - - Panel *new_panel = layout_alloc_panel(layout); - panel->parent = div.id; - panel->which_child = -1; - new_panel->parent = div.id; - new_panel->which_child = 1; - - Split_Result result; - result.divider = div.divider; - result.panel = new_panel; - return result; -} - -internal void -panel_fix_internal_area(Panel *panel){ - i32 left, right, top, bottom; - left = panel->l_margin; - right = panel->r_margin; - top = panel->t_margin; - bottom = panel->b_margin; - - panel->inner.x0 = panel->full.x0 + left; - panel->inner.x1 = panel->full.x1 - right; - panel->inner.y0 = panel->full.y0 + top; - panel->inner.y1 = panel->full.y1 - bottom; -} - -internal void -layout_fix_all_panels(Editing_Layout *layout){ - Panel *panels = layout->panels; - if (layout->panel_count > 1){ - Panel_Divider *dividers = layout->dividers; - int panel_count = layout->panel_count; - - Panel *panel = panels; - for (i32 i = 0; i < panel_count; ++i){ - i32 x0, x1, y0, y1; - x0 = 0; - x1 = x0 + layout->full_width; - y0 = 0; - y1 = y0 + layout->full_height; - - i32 pos; - i32 which_child = panel->which_child; - Divider_And_ID div; - div.id = panel->parent; - - for (;;){ - div.divider = dividers + div.id; - pos = div.divider->pos; - div.divider = dividers + div.id; - // NOTE(allen): sorry if this is hard to read through, there are - // two binary conditionals that combine into four possible cases. - // Why am I appologizing to you? IF YOU CANT HANDLE MY CODE GET OUT! - i32 action = (div.divider->v_divider << 1) | (which_child > 0); - switch (action){ - case 0: // v_divider : 0, which_child : -1 - if (pos < y1) y1 = pos; - break; - case 1: // v_divider : 0, which_child : 1 - if (pos > y0) y0 = pos; - break; - case 2: // v_divider : 1, which_child : -1 - if (pos < x1) x1 = pos; - break; - case 3: // v_divider : 1, which_child : 1 - if (pos > x0) x0 = pos; - break; - } - - if (div.id != layout->root){ - div.id = div.divider->parent; - which_child = div.divider->which_child; - } - else{ - break; - } - } - - panel->full.x0 = x0; - panel->full.y0 = y0; - panel->full.x1 = x1; - panel->full.y1 = y1; - panel_fix_internal_area(panel); - ++panel; - } - } - - else{ - panels[0].full.x0 = 0; - panels[0].full.y0 = 0; - panels[0].full.x1 = layout->full_width; - panels[0].full.y1 = layout->full_height; - panel_fix_internal_area(panels); - } -} - -internal void -layout_refit(Editing_Layout *layout, - i32 prev_x_off, i32 prev_y_off, - i32 prev_width, i32 prev_height){ - Panel_Divider *dividers = layout->dividers; - i32 divider_max_count = layout->panel_max_count - 1; - - i32 x_off = 0; - i32 y_off = 0; - - real32 h_ratio = ((real32)layout->full_width) / prev_width; - real32 v_ratio = ((real32)layout->full_height) / prev_height; - - for (i32 divider_id = 0; divider_id < divider_max_count; ++divider_id){ - Panel_Divider *divider = dividers + divider_id; - if (divider->v_divider){ - divider->pos = x_off + ROUND32((divider->pos - prev_x_off) * h_ratio); - } - else{ - divider->pos = y_off + ROUND32((divider->pos - prev_y_off) * v_ratio); - } - } - - layout_fix_all_panels(layout); -} - -inline real32 -view_base_compute_width(View *view){ - Panel *panel = view->panel; - return (real32)(panel->inner.x1 - panel->inner.x0); -} - -inline real32 -view_base_compute_height(View *view){ - Panel *panel = view->panel; - return (real32)(panel->inner.y1 - panel->inner.y0); -} - -#define view_compute_width(view) (view_base_compute_width(&(view)->view_base)) -#define view_compute_height(view) (view_base_compute_height(&(view)->view_base)) - -// BOTTOM - +/* + * Mr. 4th Dimention - Allen Webster + * + * 19.08.2015 + * + * Panel layout and general view functions for 4coder + * + */ + +// TOP +// TODO(allen): +// +// BUGS +// + +struct Interactive_Style{ + u32 bar_color; + u32 bar_active_color; + u32 base_color; + u32 pop1_color; + u32 pop2_color; +}; + +struct Interactive_Bar{ + Interactive_Style style; + real32 pos_x, pos_y; + real32 text_shift_x, text_shift_y; + i32_Rect rect; + i16 font_id; +}; + +enum View_Message{ + VMSG_STEP, + VMSG_DRAW, + VMSG_RESIZE, + VMSG_STYLE_CHANGE, + VMSG_FREE +}; + +struct View; +#define Do_View_Sig(name) \ + i32 (name)(System_Functions *system, Exchange *exchange, \ + 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)(System_Functions *system, View *view, \ + Command_Data *command, Command_Binding binding, \ + Key_Event_Data key, Key_Codes *codes) + +typedef HANDLE_COMMAND_SIG(Handle_Command_Function); + +// TODO(allen): this shouldn't exist +enum View_Type{ + VIEW_TYPE_NONE, + VIEW_TYPE_FILE, + VIEW_TYPE_COLOR, + VIEW_TYPE_DEBUG, + VIEW_TYPE_INTERACTIVE, + VIEW_TYPE_MENU, + VIEW_TYPE_CONFIG +}; + +struct Panel; +struct View{ + union{ + View *next_free; + View *major; + View *minor; + }; + Panel *panel; + Command_Map *map; + Do_View_Function *do_view; + Handle_Command_Function *handle_command; + Mem_Options *mem; + i32 type; + i32 block_size; + Application_Mouse_Cursor mouse_cursor_type; + b32 is_active; + b32 is_minor; +}; + +struct Live_Views{ + void *views; + View *free_view; + i32 count, max; + i32 stride; +}; + +struct Panel_Divider{ + Panel_Divider *next_free; + i32 parent; + i32 which_child; + i32 child1, child2; + bool32 v_divider; + i32 pos; +}; + +struct Screen_Region{ + i32_Rect full; + i32_Rect inner; + i32_Rect prev_inner; + i32 l_margin, r_margin; + i32 t_margin, b_margin; +}; + +struct Panel{ + View *view; + i32 parent; + i32 which_child; + union{ + struct{ + i32_Rect full; + i32_Rect inner; + i32_Rect prev_inner; + i32 l_margin, r_margin; + i32 t_margin, b_margin; + }; + Screen_Region screen_region; + }; +}; + +struct Editing_Layout{ + Panel *panels; + Panel_Divider *dividers; + Panel_Divider *free_divider; + i32 panel_count, panel_max_count; + i32 root; + i32 active_panel; + i32 full_width, full_height; +}; + +internal void +intbar_draw_string(Render_Target *target, + Interactive_Bar *bar, u8 *str, u32 char_color){ + i16 font_id = bar->font_id; + + draw_string(target, font_id, (char*)str, + (i32)(bar->pos_x + bar->text_shift_x), + (i32)(bar->pos_y + bar->text_shift_y), + char_color); + bar->pos_x += font_string_width(target, font_id, (char*)str); + +#if 0 + for (i32 i = 0; str[i]; ++i){ + char c = str[i]; + font_draw_glyph(target, font_id, c, + bar->pos_x + bar->text_shift_x, + bar->pos_y + bar->text_shift_y, + char_color); + bar->pos_x += font_get_glyph_width(target, font_id, c); + } +#endif +} + +internal void +intbar_draw_string(Render_Target *target, Interactive_Bar *bar, + String str, u32 char_color){ + i16 font_id = bar->font_id; + + draw_string(target, font_id, str, + (i32)(bar->pos_x + bar->text_shift_x), + (i32)(bar->pos_y + bar->text_shift_y), + char_color); + bar->pos_x += font_string_width(target, font_id, str); + +#if 0 + for (i32 i = 0; i < str.size; ++i){ + char c = str.str[i]; + font_draw_glyph(target, font_id, c, + bar->pos_x + bar->text_shift_x, + bar->pos_y + bar->text_shift_y, + char_color); + bar->pos_x += font_get_glyph_width(target, font_id, c); + } +#endif +} + +internal void +panel_init(Panel *panel){ + *panel = {}; + panel->parent = -1; + panel->l_margin = 3; + panel->r_margin = 3; + panel->t_margin = 3; + panel->b_margin = 3; +} + +internal View* +live_set_get_view(Live_Views *live_set, i32 i){ + void *result = ((char*)live_set->views + i*live_set->stride); + return (View*)result; +} + +internal View* +live_set_alloc_view(Live_Views *live_set, Mem_Options *mem){ + Assert(live_set->count < live_set->max); + View *result = 0; + result = live_set->free_view; + live_set->free_view = result->next_free; + memset(result, 0, live_set->stride); + ++live_set->count; + result->is_active = 1; + result->mem = mem; + return result; +} + +inline void +live_set_free_view(System_Functions *system, Exchange *exchange, Live_Views *live_set, View *view){ + Assert(live_set->count > 0); + view->do_view(system, exchange, view, {}, 0, VMSG_FREE, 0, {}, 0); + view->next_free = live_set->free_view; + live_set->free_view = view; + --live_set->count; + view->is_active = 0; +} + +inline void +view_replace_major(System_Functions *system, Exchange *exchange, + 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(system, exchange, live_set, view->major); + } + live_set_free_view(system, exchange, live_set, view); + } + new_view->panel = panel; + new_view->minor = 0; + panel->view = new_view; +} + +inline void +view_replace_minor(System_Functions *system, Exchange *exchange, + 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(system, exchange, live_set, view); + } + else{ + new_view->major = view; + view->is_active = 0; + } + } + else{ + new_view->major = 0; + } + new_view->panel = panel; + panel->view = new_view; +} + +inline void +view_remove_major(System_Functions *system, Exchange *exchange, + Panel *panel, Live_Views *live_set){ + View *view = panel->view; + if (view){ + if (view->is_minor && view->major){ + live_set_free_view(system, exchange, live_set, view->major); + } + live_set_free_view(system, exchange, live_set, view); + } + panel->view = 0; +} + +inline void +view_remove_major_leave_minor(System_Functions *system, Exchange *exchange, + Panel *panel, Live_Views *live_set){ + View *view = panel->view; + if (view){ + if (view->is_minor && view->major){ + live_set_free_view(system, exchange, live_set, view->major); + view->major = 0; + } + else{ + live_set_free_view(system, exchange, live_set, view); + panel->view = 0; + } + } +} + +inline void +view_remove_minor(System_Functions *system, Exchange *exchange, + 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(system, exchange, live_set, view); + } + } + panel->view = major; + if (major) major->is_active = 1; +} + +inline void +view_remove(System_Functions *system, Exchange *exchange, + Panel *panel, Live_Views *live_set){ + View *view = panel->view; + if (view->is_minor) view_remove_minor(system, exchange, panel, live_set); + else view_remove_major(system, exchange, panel, live_set); +} + +struct Divider_And_ID{ + Panel_Divider* divider; + i32 id; +}; + +internal Divider_And_ID +layout_alloc_divider(Editing_Layout *layout){ + Assert(layout->free_divider); + Divider_And_ID result; + result.divider = layout->free_divider; + layout->free_divider = result.divider->next_free; + *result.divider = {}; + result.divider->parent = -1; + result.divider->child1 = -1; + result.divider->child2 = -1; + result.id = (i32)(result.divider - layout->dividers); + if (layout->panel_count == 1){ + layout->root = result.id; + } + return result; +} + +internal Divider_And_ID +layout_get_divider(Editing_Layout *layout, i32 id){ + Assert(id >= 0 && id < layout->panel_max_count-1); + Divider_And_ID result; + result.id = id; + result.divider = layout->dividers + id; + return result; +} + +internal Panel* +layout_alloc_panel(Editing_Layout *layout){ + Assert(layout->panel_count < layout->panel_max_count); + Panel *result = layout->panels + layout->panel_count; + *result = {}; + ++layout->panel_count; + return result; +} + +internal void +layout_free_divider(Editing_Layout *layout, Panel_Divider *divider){ + divider->next_free = layout->free_divider; + layout->free_divider = divider; +} + +internal void +layout_free_panel(Editing_Layout *layout, Panel *panel){ + Panel *panels = layout->panels; + i32 panel_count = --layout->panel_count; + i32 panel_i = (i32)(panel - layout->panels); + for (i32 i = panel_i; i < panel_count; ++i){ + Panel *p = panels + i; + *p = panels[i+1]; + if (p->view){ + p->view->panel = p; + } + } +} + +internal Divider_And_ID +layout_calc_divider_id(Editing_Layout *layout, Panel_Divider *divider){ + Divider_And_ID result; + result.divider = divider; + result.id = (i32)(divider - layout->dividers); + return result; +} + +struct Split_Result{ + Panel_Divider *divider; + Panel *panel; +}; + +internal Split_Result +layout_split_panel(Editing_Layout *layout, Panel *panel, bool32 vertical){ + Divider_And_ID div = layout_alloc_divider(layout); + if (panel->parent != -1){ + Divider_And_ID pdiv = layout_get_divider(layout, panel->parent); + if (panel->which_child == -1){ + pdiv.divider->child1 = div.id; + } + else{ + pdiv.divider->child2 = div.id; + } + } + + div.divider->parent = panel->parent; + div.divider->which_child = panel->which_child; + if (vertical){ + div.divider->v_divider = 1; + div.divider->pos = (panel->full.x0 + panel->full.x1) / 2; + } + else{ + div.divider->v_divider = 0; + div.divider->pos = (panel->full.y0 + panel->full.y1) / 2; + } + + Panel *new_panel = layout_alloc_panel(layout); + panel->parent = div.id; + panel->which_child = -1; + new_panel->parent = div.id; + new_panel->which_child = 1; + + Split_Result result; + result.divider = div.divider; + result.panel = new_panel; + return result; +} + +internal void +panel_fix_internal_area(Panel *panel){ + i32 left, right, top, bottom; + left = panel->l_margin; + right = panel->r_margin; + top = panel->t_margin; + bottom = panel->b_margin; + + panel->inner.x0 = panel->full.x0 + left; + panel->inner.x1 = panel->full.x1 - right; + panel->inner.y0 = panel->full.y0 + top; + panel->inner.y1 = panel->full.y1 - bottom; +} + +internal void +layout_fix_all_panels(Editing_Layout *layout){ + Panel *panels = layout->panels; + if (layout->panel_count > 1){ + Panel_Divider *dividers = layout->dividers; + int panel_count = layout->panel_count; + + Panel *panel = panels; + for (i32 i = 0; i < panel_count; ++i){ + i32 x0, x1, y0, y1; + x0 = 0; + x1 = x0 + layout->full_width; + y0 = 0; + y1 = y0 + layout->full_height; + + i32 pos; + i32 which_child = panel->which_child; + Divider_And_ID div; + div.id = panel->parent; + + for (;;){ + div.divider = dividers + div.id; + pos = div.divider->pos; + div.divider = dividers + div.id; + // NOTE(allen): sorry if this is hard to read through, there are + // two binary conditionals that combine into four possible cases. + // Why am I appologizing to you? IF YOU CANT HANDLE MY CODE GET OUT! + i32 action = (div.divider->v_divider << 1) | (which_child > 0); + switch (action){ + case 0: // v_divider : 0, which_child : -1 + if (pos < y1) y1 = pos; + break; + case 1: // v_divider : 0, which_child : 1 + if (pos > y0) y0 = pos; + break; + case 2: // v_divider : 1, which_child : -1 + if (pos < x1) x1 = pos; + break; + case 3: // v_divider : 1, which_child : 1 + if (pos > x0) x0 = pos; + break; + } + + if (div.id != layout->root){ + div.id = div.divider->parent; + which_child = div.divider->which_child; + } + else{ + break; + } + } + + panel->full.x0 = x0; + panel->full.y0 = y0; + panel->full.x1 = x1; + panel->full.y1 = y1; + panel_fix_internal_area(panel); + ++panel; + } + } + + else{ + panels[0].full.x0 = 0; + panels[0].full.y0 = 0; + panels[0].full.x1 = layout->full_width; + panels[0].full.y1 = layout->full_height; + panel_fix_internal_area(panels); + } +} + +internal void +layout_refit(Editing_Layout *layout, + i32 prev_x_off, i32 prev_y_off, + i32 prev_width, i32 prev_height){ + Panel_Divider *dividers = layout->dividers; + i32 divider_max_count = layout->panel_max_count - 1; + + i32 x_off = 0; + i32 y_off = 0; + + real32 h_ratio = ((real32)layout->full_width) / prev_width; + real32 v_ratio = ((real32)layout->full_height) / prev_height; + + for (i32 divider_id = 0; divider_id < divider_max_count; ++divider_id){ + Panel_Divider *divider = dividers + divider_id; + if (divider->v_divider){ + divider->pos = x_off + ROUND32((divider->pos - prev_x_off) * h_ratio); + } + else{ + divider->pos = y_off + ROUND32((divider->pos - prev_y_off) * v_ratio); + } + } + + layout_fix_all_panels(layout); +} + +inline real32 +view_base_compute_width(View *view){ + Panel *panel = view->panel; + return (real32)(panel->inner.x1 - panel->inner.x0); +} + +inline real32 +view_base_compute_height(View *view){ + Panel *panel = view->panel; + return (real32)(panel->inner.y1 - panel->inner.y0); +} + +#define view_compute_width(view) (view_base_compute_width(&(view)->view_base)) +#define view_compute_height(view) (view_base_compute_height(&(view)->view_base)) + +// BOTTOM + diff --git a/4ed_rendering.cpp b/4ed_rendering.cpp index 8d1367cd..d4cecd53 100644 --- a/4ed_rendering.cpp +++ b/4ed_rendering.cpp @@ -1,498 +1,508 @@ -/* - * Mr. 4th Dimention - Allen Webster - * - * 12.17.2014 - * - * Rendering layer for project codename "4ed" - * - */ - -// TOP - -inline void -draw_set_clip(Render_Target *target, i32_Rect clip_box){ - glScissor(clip_box.x0, - target->height - clip_box.y1, - clip_box.x1 - clip_box.x0, - clip_box.y1 - clip_box.y0); -} - -inline void -draw_bind_texture(Render_Target *target, i32 texid){ - if (target->bound_texture != texid){ - glBindTexture(GL_TEXTURE_2D, texid); - target->bound_texture = texid; - } -} - -inline void -draw_set_color(Render_Target *target, u32 color){ - if (target->color != color){ - target->color = color; - Vec4 c = unpack_color4(color); - glColor4f(c.r, c.g, c.b, c.a); - } -} - -#define PutStruct(s,x) *(s*)(target->push_buffer + target->size) = x; target->size += sizeof(s) - -internal void -draw_push_piece(Render_Target *target, Render_Piece_Combined piece){ - PutStruct(Render_Piece_Header, piece.header); - - switch (piece.header.type){ - case piece_type_rectangle: - case piece_type_outline: - PutStruct(Render_Piece_Rectangle, piece.rectangle); - break; - - case piece_type_gradient: - PutStruct(Render_Piece_Gradient, piece.gradient); - break; - - case piece_type_glyph: - case piece_type_mono_glyph: - PutStruct(Render_Piece_Glyph, piece.glyph); - break; - - case piece_type_mono_glyph_advance: - PutStruct(Render_Piece_Glyph_Advance, piece.glyph_advance); - break; - } - - Assert(target->size <= target->max); -} - -internal void -draw_push_piece_clip(Render_Target *target, i32_Rect clip_box){ - // TODO(allen): optimize out if there are two clip box changes in a row - Render_Piece_Change_Clip clip; - Render_Piece_Header header; - - header.type = piece_type_change_clip; - clip.box = clip_box; - - PutStruct(Render_Piece_Header, header); - PutStruct(Render_Piece_Change_Clip, clip); -} - -internal void -draw_push_clip(Render_Target *target, i32_Rect clip_box){ - Assert(target->clip_top == -1 || - fits_inside(clip_box, target->clip_boxes[target->clip_top])); - Assert(target->clip_top+1 < ArrayCount(target->clip_boxes)); - target->clip_boxes[++target->clip_top] = clip_box; - - draw_push_piece_clip(target, clip_box); -} - -internal void -draw_pop_clip(Render_Target *target){ - i32_Rect clip_box; - Assert(target->clip_top > 0); - --target->clip_top; - clip_box = target->clip_boxes[target->clip_top]; - - draw_push_piece_clip(target, clip_box); -} - -#define ExtractStruct(s) ((s*)cursor); cursor += sizeof(s) - -inline void -private_draw_rectangle(Render_Target *target, f32_Rect rect, u32 color){ - draw_set_color(target, color); - draw_bind_texture(target, 0); - glBegin(GL_QUADS); - { - glVertex2f(rect.x0, rect.y0); - glVertex2f(rect.x0, rect.y1); - glVertex2f(rect.x1, rect.y1); - glVertex2f(rect.x1, rect.y0); - } - glEnd(); -} - -inline void -private_draw_rectangle_outline(Render_Target *target, f32_Rect rect, u32 color){ - f32_Rect r; - r.x0 = rect.x0 + .5f; - r.y0 = rect.y0 + .5f; - r.x1 = rect.x1 - .5f; - r.y1 = rect.y1 - .5f; - - draw_set_color(target, color); - draw_bind_texture(target, 0); - glBegin(GL_LINE_STRIP); - { - glVertex2f(r.x0, r.y0); - glVertex2f(r.x1, r.y0); - glVertex2f(r.x1, r.y1); - glVertex2f(r.x0, r.y1); - glVertex2f(r.x0, r.y0); - } - glEnd(); -} - -inline void -private_draw_gradient(Render_Target *target, f32_Rect rect, - Vec4 color_left, Vec4 color_right){ - Vec4 cl = color_left; - Vec4 cr = color_right; - - draw_bind_texture(target, 0); - glBegin(GL_QUADS); - { - glColor4f(cl.r, cl.g, cl.b, cl.a); - glVertex2f(rect.x0, rect.y0); - glVertex2f(rect.x0, rect.y1); - - glColor4f(cr.r, cr.g, cr.b, cr.a); - glVertex2f(rect.x1, rect.y1); - glVertex2f(rect.x1, rect.y0); - } - glEnd(); -} - -inline void -private_draw_glyph(Render_Target *target, Render_Font *font, - u8 character, f32 x, f32 y, u32 color){ - f32 x_shift, y_shift; - x_shift = 0; - y_shift = (f32)font->ascent; - - x += x_shift; - y += y_shift; - - stbtt_aligned_quad q; - stbtt_GetPackedQuad(font->chardata, font->tex_width, font->tex_height, - character, &x, &y, &q, 0); - - draw_set_color(target, color); - draw_bind_texture(target, font->tex); - glBegin(GL_QUADS); - { - glTexCoord2f(q.s0, q.t1); glVertex2f(q.x0, q.y1); - glTexCoord2f(q.s1, q.t1); glVertex2f(q.x1, q.y1); - glTexCoord2f(q.s1, q.t0); glVertex2f(q.x1, q.y0); - glTexCoord2f(q.s0, q.t0); glVertex2f(q.x0, q.y0); - } - glEnd(); -} - -inline void -private_draw_glyph_mono(Render_Target *target, Render_Font *font, u8 character, - f32 x, f32 y, f32 advance, u32 color){ - f32 x_shift, y_shift; - i32 left = font->chardata[character].x0; - i32 right = font->chardata[character].x1; - i32 width = (right - left); - x_shift = (f32)(advance - width) * .5f - font->chardata[character].xoff; - y_shift = (f32)font->ascent; - - x += x_shift; - y += y_shift; - - stbtt_aligned_quad q; - stbtt_GetPackedQuad(font->chardata, font->tex_width, font->tex_height, - character, &x, &y, &q, 0); - - draw_set_color(target, color); - draw_bind_texture(target, font->tex); - glBegin(GL_QUADS); - { - glTexCoord2f(q.s0, q.t1); glVertex2f(q.x0, q.y1); - glTexCoord2f(q.s1, q.t1); glVertex2f(q.x1, q.y1); - glTexCoord2f(q.s1, q.t0); glVertex2f(q.x1, q.y0); - glTexCoord2f(q.s0, q.t0); glVertex2f(q.x0, q.y0); - } - glEnd(); -} - -inline void -private_draw_glyph_mono(Render_Target *target, Render_Font *font, u8 character, - real32 x, real32 y, u32 color){ - private_draw_glyph_mono(target, font, character, x, y, (f32)font->advance, color); -} - -internal void -launch_rendering(Render_Target *target){ - byte *cursor = target->push_buffer; - byte *cursor_end = cursor + target->size; - - for (; cursor < cursor_end;){ - Render_Piece_Header *header = ExtractStruct(Render_Piece_Header); - - i32 type = header->type; - switch (type){ - case piece_type_rectangle: - { - Render_Piece_Rectangle *rectangle = - ExtractStruct(Render_Piece_Rectangle); - private_draw_rectangle(target, rectangle->rect, rectangle->color); - }break; - - case piece_type_outline: - { - Render_Piece_Rectangle *rectangle = - ExtractStruct(Render_Piece_Rectangle); - private_draw_rectangle_outline(target, rectangle->rect, rectangle->color); - }break; - - case piece_type_gradient: - { - Render_Piece_Gradient *gradient = - ExtractStruct(Render_Piece_Gradient); - private_draw_gradient(target, gradient->rect, - unpack_color4(gradient->left_color), - unpack_color4(gradient->right_color)); - }break; - - case piece_type_glyph: - { - Render_Piece_Glyph *glyph = - ExtractStruct(Render_Piece_Glyph); - - Render_Font *font = get_font_info(&target->font_set, glyph->font_id)->font; - if (font) - private_draw_glyph(target, font, glyph->character, - glyph->pos.x, glyph->pos.y, glyph->color); - }break; - - case piece_type_mono_glyph: - { - Render_Piece_Glyph *glyph = - ExtractStruct(Render_Piece_Glyph); - - Render_Font *font = get_font_info(&target->font_set, glyph->font_id)->font; - if (font) - private_draw_glyph_mono(target, font, glyph->character, - glyph->pos.x, glyph->pos.y, glyph->color); - }break; - - case piece_type_mono_glyph_advance: - { - Render_Piece_Glyph_Advance *glyph = - ExtractStruct(Render_Piece_Glyph_Advance); - - Render_Font *font = get_font_info(&target->font_set, glyph->font_id)->font; - if (font) - private_draw_glyph_mono(target, font, glyph->character, - glyph->pos.x, glyph->pos.y, - glyph->advance, glyph->color); - }break; - - case piece_type_change_clip: - { - Render_Piece_Change_Clip *clip = - ExtractStruct(Render_Piece_Change_Clip); - draw_set_clip(target, clip->box); - }break; - } - } -} - -#undef ExtractStruct - -internal i32 -draw_font_info_load(Partition *partition, - char *filename, - i32 pt_size, - i32 *height, - i32 *advance){ - i32 result = 1; - Data file; - file = system_load_file(filename); - - Temp_Memory temp = begin_temp_memory(partition); - stbtt_packedchar *chardata = push_array(partition, stbtt_packedchar, 256); - - i32 oversample = 2; - - i32 tex_width, tex_height; - tex_width = pt_size*128*oversample; - tex_height = pt_size*2*oversample; - void *block = push_block(partition, tex_width * tex_height); - - if (!file.data){ - result = 0; - } - else{ - stbtt_fontinfo font; - if (!stbtt_InitFont(&font, (u8*)file.data, 0)){ - result = 0; - } - else{ - i32 ascent, descent, line_gap; - f32 scale; - - stbtt_GetFontVMetrics(&font, &ascent, &descent, &line_gap); - scale = stbtt_ScaleForPixelHeight(&font, (f32)pt_size); - - f32 scaled_ascent, scaled_descent, scaled_line_gap; - - scaled_ascent = scale*ascent; - scaled_descent = scale*descent; - scaled_line_gap = scale*line_gap; - - i32 font_height = (i32)(scaled_ascent - scaled_descent + scaled_line_gap); - - stbtt_pack_context spc; - if (stbtt_PackBegin(&spc, (u8*)block, tex_width, tex_height, tex_width, 1, partition)){ - stbtt_PackSetOversampling(&spc, oversample, oversample); - if (stbtt_PackFontRange(&spc, (u8*)file.data, 0, - STBTT_POINT_SIZE((f32)pt_size), 0, 128, chardata)){ - // do nothing - } - else{ - result = 0; - } - - stbtt_PackEnd(&spc); - } - else{ - result = 0; - } - - if (result){ - i32 max_advance = 0; - for (u8 code_point = 0; code_point < 128; ++code_point){ - if (stbtt_FindGlyphIndex(&font, code_point) != 0){ - i32 adv = CEIL32(chardata[code_point].xadvance); - if (max_advance < adv){ - max_advance = adv; - } - } - } - - *height = font_height; - *advance = max_advance - 1; - } - } - - system_free_memory(file.data); - } - - end_temp_memory(temp); - - return(result); -} - -internal i32 -draw_font_load(void *base_block, i32 size, - Render_Font *font_out, - char *filename, - i32 pt_size, - i32 tab_width){ - i32 result = 1; - Data file; - file = system_load_file(filename); - - Partition partition_ = partition_open(base_block, size); - Partition *partition = &partition_; - - stbtt_packedchar *chardata = font_out->chardata; - - i32 oversample = 2; - - i32 tex_width, tex_height; - tex_width = pt_size*128*oversample; - tex_height = pt_size*2*oversample; - void *block = push_block(partition, tex_width * tex_height); - - if (!file.data){ - result = 0; - } - - else{ - stbtt_fontinfo font; - if (!stbtt_InitFont(&font, (u8*)file.data, 0)){ - result = 0; - } - else{ - i32 ascent, descent, line_gap; - f32 scale; - - stbtt_GetFontVMetrics(&font, &ascent, &descent, &line_gap); - scale = stbtt_ScaleForPixelHeight(&font, (f32)pt_size); - - f32 scaled_ascent, scaled_descent, scaled_line_gap; - - scaled_ascent = scale*ascent; - scaled_descent = scale*descent; - scaled_line_gap = scale*line_gap; - - font_out->height = (i32)(scaled_ascent - scaled_descent + scaled_line_gap); - font_out->ascent = (i32)(scaled_ascent); - font_out->descent = (i32)(scaled_descent); - font_out->line_skip = (i32)(scaled_line_gap); - - font_out->tex_width = tex_width; - font_out->tex_height = tex_height; - - stbtt_pack_context spc; - - if (stbtt_PackBegin(&spc, (u8*)block, tex_width, tex_height, tex_width, 1, partition)){ - stbtt_PackSetOversampling(&spc, oversample, oversample); - if (stbtt_PackFontRange(&spc, (u8*)file.data, 0, - STBTT_POINT_SIZE((f32)pt_size), 0, 128, chardata)){ - // do nothing - } - else{ - result = 0; - } - - stbtt_PackEnd(&spc); - } - else{ - result = 0; - } - - if (result){ - GLuint font_tex; - glGenTextures(1, &font_tex); - glBindTexture(GL_TEXTURE_2D, font_tex); - - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - - glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, tex_width, tex_height, 0, GL_ALPHA, GL_UNSIGNED_BYTE, block); - - font_out->tex = font_tex; - glBindTexture(GL_TEXTURE_2D, 0); - - font_out->chardata['\r'] = font_out->chardata[' ']; - font_out->chardata['\n'] = font_out->chardata[' ']; - font_out->chardata['\t'] = font_out->chardata[' ']; - font_out->chardata['\t'].xadvance *= tab_width; - - i32 max_advance = 0; - for (u8 code_point = 0; code_point < 128; ++code_point){ - if (stbtt_FindGlyphIndex(&font, code_point) != 0){ - font_out->glyphs[code_point].exists = 1; - i32 advance = CEIL32(font_out->chardata[code_point].xadvance); - if (max_advance < advance) max_advance = advance; - font_out->advance_data[code_point] = font_out->chardata[code_point].xadvance; - } - else if (code_point == '\r' || code_point == '\n' || code_point == '\t'){ - font_out->advance_data[code_point] = font_out->chardata[code_point].xadvance; - } - } - font_out->advance = max_advance - 1; - } - - } - system_free_memory(file.data); - } - - return result; -} - -internal -Release_Font_Sig(draw_release_font){ - glDeleteTextures(1, &font->tex); - font->tex = 0; -} - -// BOTTOM - +/* + * Mr. 4th Dimention - Allen Webster + * + * 12.17.2014 + * + * Rendering layer for project codename "4ed" + * + */ + +// TOP + +inline void +draw_set_clip(Render_Target *target, i32_Rect clip_box){ + glScissor(clip_box.x0, + target->height - clip_box.y1, + clip_box.x1 - clip_box.x0, + clip_box.y1 - clip_box.y0); +} + +inline void +draw_bind_texture(Render_Target *target, i32 texid){ + if (target->bound_texture != texid){ + glBindTexture(GL_TEXTURE_2D, texid); + target->bound_texture = texid; + } +} + +inline void +draw_set_color(Render_Target *target, u32 color){ + if (target->color != color){ + target->color = color; + Vec4 c = unpack_color4(color); + glColor4f(c.r, c.g, c.b, c.a); + } +} + +#define PutStruct(s,x) *(s*)(target->push_buffer + target->size) = x; target->size += sizeof(s) + +internal void +draw_push_piece(Render_Target *target, Render_Piece_Combined piece){ + PutStruct(Render_Piece_Header, piece.header); + + switch (piece.header.type){ + case piece_type_rectangle: + case piece_type_outline: + PutStruct(Render_Piece_Rectangle, piece.rectangle); + break; + + case piece_type_gradient: + PutStruct(Render_Piece_Gradient, piece.gradient); + break; + + case piece_type_glyph: + case piece_type_mono_glyph: + PutStruct(Render_Piece_Glyph, piece.glyph); + break; + + case piece_type_mono_glyph_advance: + PutStruct(Render_Piece_Glyph_Advance, piece.glyph_advance); + break; + } + + Assert(target->size <= target->max); +} + +internal void +draw_push_piece_clip(Render_Target *target, i32_Rect clip_box){ + // TODO(allen): optimize out if there are two clip box changes in a row + Render_Piece_Change_Clip clip; + Render_Piece_Header header; + + header.type = piece_type_change_clip; + clip.box = clip_box; + + PutStruct(Render_Piece_Header, header); + PutStruct(Render_Piece_Change_Clip, clip); +} + +internal void +draw_push_clip(Render_Target *target, i32_Rect clip_box){ + Assert(target->clip_top == -1 || + fits_inside(clip_box, target->clip_boxes[target->clip_top])); + Assert(target->clip_top+1 < ArrayCount(target->clip_boxes)); + target->clip_boxes[++target->clip_top] = clip_box; + + draw_push_piece_clip(target, clip_box); +} + +internal void +draw_pop_clip(Render_Target *target){ + i32_Rect clip_box; + Assert(target->clip_top > 0); + --target->clip_top; + clip_box = target->clip_boxes[target->clip_top]; + + draw_push_piece_clip(target, clip_box); +} + +#define ExtractStruct(s) ((s*)cursor); cursor += sizeof(s) + +inline void +private_draw_rectangle(Render_Target *target, f32_Rect rect, u32 color){ + draw_set_color(target, color); + draw_bind_texture(target, 0); + glBegin(GL_QUADS); + { + glVertex2f(rect.x0, rect.y0); + glVertex2f(rect.x0, rect.y1); + glVertex2f(rect.x1, rect.y1); + glVertex2f(rect.x1, rect.y0); + } + glEnd(); +} + +inline void +private_draw_rectangle_outline(Render_Target *target, f32_Rect rect, u32 color){ + f32_Rect r; + r.x0 = rect.x0 + .5f; + r.y0 = rect.y0 + .5f; + r.x1 = rect.x1 - .5f; + r.y1 = rect.y1 - .5f; + + draw_set_color(target, color); + draw_bind_texture(target, 0); + glBegin(GL_LINE_STRIP); + { + glVertex2f(r.x0, r.y0); + glVertex2f(r.x1, r.y0); + glVertex2f(r.x1, r.y1); + glVertex2f(r.x0, r.y1); + glVertex2f(r.x0, r.y0); + } + glEnd(); +} + +inline void +private_draw_gradient(Render_Target *target, f32_Rect rect, + Vec4 color_left, Vec4 color_right){ + Vec4 cl = color_left; + Vec4 cr = color_right; + + draw_bind_texture(target, 0); + glBegin(GL_QUADS); + { + glColor4f(cl.r, cl.g, cl.b, cl.a); + glVertex2f(rect.x0, rect.y0); + glVertex2f(rect.x0, rect.y1); + + glColor4f(cr.r, cr.g, cr.b, cr.a); + glVertex2f(rect.x1, rect.y1); + glVertex2f(rect.x1, rect.y0); + } + glEnd(); +} + +inline void +private_draw_glyph(Render_Target *target, Render_Font *font, + u8 character, f32 x, f32 y, u32 color){ + f32 x_shift, y_shift; + x_shift = 0; + y_shift = (f32)font->ascent; + + x += x_shift; + y += y_shift; + + stbtt_aligned_quad q; + stbtt_GetPackedQuad(font->chardata, font->tex_width, font->tex_height, + character, &x, &y, &q, 0); + + draw_set_color(target, color); + draw_bind_texture(target, font->tex); + glBegin(GL_QUADS); + { + glTexCoord2f(q.s0, q.t1); glVertex2f(q.x0, q.y1); + glTexCoord2f(q.s1, q.t1); glVertex2f(q.x1, q.y1); + glTexCoord2f(q.s1, q.t0); glVertex2f(q.x1, q.y0); + glTexCoord2f(q.s0, q.t0); glVertex2f(q.x0, q.y0); + } + glEnd(); +} + +inline void +private_draw_glyph_mono(Render_Target *target, Render_Font *font, u8 character, + f32 x, f32 y, f32 advance, u32 color){ + f32 x_shift, y_shift; + i32 left = font->chardata[character].x0; + i32 right = font->chardata[character].x1; + i32 width = (right - left); + x_shift = (f32)(advance - width) * .5f - font->chardata[character].xoff; + y_shift = (f32)font->ascent; + + x += x_shift; + y += y_shift; + + stbtt_aligned_quad q; + stbtt_GetPackedQuad(font->chardata, font->tex_width, font->tex_height, + character, &x, &y, &q, 0); + + draw_set_color(target, color); + draw_bind_texture(target, font->tex); + glBegin(GL_QUADS); + { + glTexCoord2f(q.s0, q.t1); glVertex2f(q.x0, q.y1); + glTexCoord2f(q.s1, q.t1); glVertex2f(q.x1, q.y1); + glTexCoord2f(q.s1, q.t0); glVertex2f(q.x1, q.y0); + glTexCoord2f(q.s0, q.t0); glVertex2f(q.x0, q.y0); + } + glEnd(); +} + +inline void +private_draw_glyph_mono(Render_Target *target, Render_Font *font, u8 character, + real32 x, real32 y, u32 color){ + private_draw_glyph_mono(target, font, character, x, y, (f32)font->advance, color); +} + +internal void +launch_rendering(Render_Target *target){ + byte *cursor = target->push_buffer; + byte *cursor_end = cursor + target->size; + + for (; cursor < cursor_end;){ + Render_Piece_Header *header = ExtractStruct(Render_Piece_Header); + + i32 type = header->type; + switch (type){ + case piece_type_rectangle: + { + Render_Piece_Rectangle *rectangle = + ExtractStruct(Render_Piece_Rectangle); + private_draw_rectangle(target, rectangle->rect, rectangle->color); + }break; + + case piece_type_outline: + { + Render_Piece_Rectangle *rectangle = + ExtractStruct(Render_Piece_Rectangle); + private_draw_rectangle_outline(target, rectangle->rect, rectangle->color); + }break; + + case piece_type_gradient: + { + Render_Piece_Gradient *gradient = + ExtractStruct(Render_Piece_Gradient); + private_draw_gradient(target, gradient->rect, + unpack_color4(gradient->left_color), + unpack_color4(gradient->right_color)); + }break; + + case piece_type_glyph: + { + Render_Piece_Glyph *glyph = + ExtractStruct(Render_Piece_Glyph); + + Render_Font *font = get_font_info(&target->font_set, glyph->font_id)->font; + if (font) + private_draw_glyph(target, font, glyph->character, + glyph->pos.x, glyph->pos.y, glyph->color); + }break; + + case piece_type_mono_glyph: + { + Render_Piece_Glyph *glyph = + ExtractStruct(Render_Piece_Glyph); + + Render_Font *font = get_font_info(&target->font_set, glyph->font_id)->font; + if (font) + private_draw_glyph_mono(target, font, glyph->character, + glyph->pos.x, glyph->pos.y, glyph->color); + }break; + + case piece_type_mono_glyph_advance: + { + Render_Piece_Glyph_Advance *glyph = + ExtractStruct(Render_Piece_Glyph_Advance); + + Render_Font *font = get_font_info(&target->font_set, glyph->font_id)->font; + if (font) + private_draw_glyph_mono(target, font, glyph->character, + glyph->pos.x, glyph->pos.y, + glyph->advance, glyph->color); + }break; + + case piece_type_change_clip: + { + Render_Piece_Change_Clip *clip = + ExtractStruct(Render_Piece_Change_Clip); + draw_set_clip(target, clip->box); + }break; + } + } +} + +#undef ExtractStruct + +internal i32 +draw_font_info_load(Partition *partition, + char *filename_untranslated, + i32 pt_size, i32 *height, i32 *advance){ + + char space_[1024]; + String filename = make_fixed_width_string(space_); + b32 translate_success = system_to_binary_path(&filename, filename_untranslated); + if (!translate_success) return 0; + + i32 result = 1; + Data file; + file = system_load_file(filename.str); + + Temp_Memory temp = begin_temp_memory(partition); + stbtt_packedchar *chardata = push_array(partition, stbtt_packedchar, 256); + + i32 oversample = 2; + + i32 tex_width, tex_height; + tex_width = pt_size*128*oversample; + tex_height = pt_size*2*oversample; + void *block = push_block(partition, tex_width * tex_height); + + if (!file.data){ + result = 0; + } + else{ + stbtt_fontinfo font; + if (!stbtt_InitFont(&font, (u8*)file.data, 0)){ + result = 0; + } + else{ + i32 ascent, descent, line_gap; + f32 scale; + + stbtt_GetFontVMetrics(&font, &ascent, &descent, &line_gap); + scale = stbtt_ScaleForPixelHeight(&font, (f32)pt_size); + + f32 scaled_ascent, scaled_descent, scaled_line_gap; + + scaled_ascent = scale*ascent; + scaled_descent = scale*descent; + scaled_line_gap = scale*line_gap; + + i32 font_height = (i32)(scaled_ascent - scaled_descent + scaled_line_gap); + + stbtt_pack_context spc; + if (stbtt_PackBegin(&spc, (u8*)block, tex_width, tex_height, tex_width, 1, partition)){ + stbtt_PackSetOversampling(&spc, oversample, oversample); + if (stbtt_PackFontRange(&spc, (u8*)file.data, 0, + STBTT_POINT_SIZE((f32)pt_size), 0, 128, chardata)){ + // do nothing + } + else{ + result = 0; + } + + stbtt_PackEnd(&spc); + } + else{ + result = 0; + } + + if (result){ + i32 max_advance = 0; + for (u8 code_point = 0; code_point < 128; ++code_point){ + if (stbtt_FindGlyphIndex(&font, code_point) != 0){ + i32 adv = CEIL32(chardata[code_point].xadvance); + if (max_advance < adv){ + max_advance = adv; + } + } + } + + *height = font_height; + *advance = max_advance - 1; + } + } + + system_free_memory(file.data); + } + + end_temp_memory(temp); + + return(result); +} + +internal i32 +draw_font_load(void *base_block, i32 size, + Render_Font *font_out, + char *filename_untranslated, + i32 pt_size, + i32 tab_width){ + + char space_[1024]; + String filename = make_fixed_width_string(space_); + b32 translate_success = system_to_binary_path(&filename, filename_untranslated); + if (!translate_success) return 0; + + i32 result = 1; + Data file; + file = system_load_file(filename.str); + + Partition partition_ = partition_open(base_block, size); + Partition *partition = &partition_; + + stbtt_packedchar *chardata = font_out->chardata; + + i32 oversample = 2; + + i32 tex_width, tex_height; + tex_width = pt_size*128*oversample; + tex_height = pt_size*2*oversample; + void *block = push_block(partition, tex_width * tex_height); + + if (!file.data){ + result = 0; + } + + else{ + stbtt_fontinfo font; + if (!stbtt_InitFont(&font, (u8*)file.data, 0)){ + result = 0; + } + else{ + i32 ascent, descent, line_gap; + f32 scale; + + stbtt_GetFontVMetrics(&font, &ascent, &descent, &line_gap); + scale = stbtt_ScaleForPixelHeight(&font, (f32)pt_size); + + f32 scaled_ascent, scaled_descent, scaled_line_gap; + + scaled_ascent = scale*ascent; + scaled_descent = scale*descent; + scaled_line_gap = scale*line_gap; + + font_out->height = (i32)(scaled_ascent - scaled_descent + scaled_line_gap); + font_out->ascent = (i32)(scaled_ascent); + font_out->descent = (i32)(scaled_descent); + font_out->line_skip = (i32)(scaled_line_gap); + + font_out->tex_width = tex_width; + font_out->tex_height = tex_height; + + stbtt_pack_context spc; + + if (stbtt_PackBegin(&spc, (u8*)block, tex_width, tex_height, tex_width, 1, partition)){ + stbtt_PackSetOversampling(&spc, oversample, oversample); + if (stbtt_PackFontRange(&spc, (u8*)file.data, 0, + STBTT_POINT_SIZE((f32)pt_size), 0, 128, chardata)){ + // do nothing + } + else{ + result = 0; + } + + stbtt_PackEnd(&spc); + } + else{ + result = 0; + } + + if (result){ + GLuint font_tex; + glGenTextures(1, &font_tex); + glBindTexture(GL_TEXTURE_2D, font_tex); + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + + glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, tex_width, tex_height, 0, GL_ALPHA, GL_UNSIGNED_BYTE, block); + + font_out->tex = font_tex; + glBindTexture(GL_TEXTURE_2D, 0); + + font_out->chardata['\r'] = font_out->chardata[' ']; + font_out->chardata['\n'] = font_out->chardata[' ']; + font_out->chardata['\t'] = font_out->chardata[' ']; + font_out->chardata['\t'].xadvance *= tab_width; + + i32 max_advance = 0; + for (u8 code_point = 0; code_point < 128; ++code_point){ + if (stbtt_FindGlyphIndex(&font, code_point) != 0){ + font_out->glyphs[code_point].exists = 1; + i32 advance = CEIL32(font_out->chardata[code_point].xadvance); + if (max_advance < advance) max_advance = advance; + font_out->advance_data[code_point] = font_out->chardata[code_point].xadvance; + } + else if (code_point == '\r' || code_point == '\n' || code_point == '\t'){ + font_out->advance_data[code_point] = font_out->chardata[code_point].xadvance; + } + } + font_out->advance = max_advance - 1; + } + + } + system_free_memory(file.data); + } + + return result; +} + +internal +Release_Font_Sig(draw_release_font){ + glDeleteTextures(1, &font->tex); + font->tex = 0; +} + +// BOTTOM + diff --git a/4ed_rendering_helper.cpp b/4ed_rendering_helper.cpp index 91d3ecd0..c2c1d756 100644 --- a/4ed_rendering_helper.cpp +++ b/4ed_rendering_helper.cpp @@ -1,241 +1,267 @@ -/* - * Mr. 4th Dimention - Allen Webster - * - * 12.17.2014 - * - * Rendering layer for project codename "4ed" - * - */ - -// TOP - -inline void -draw_push_clip(Render_Target *target, i32_Rect clip_box){ - target->push_clip(target, clip_box); -} - -inline void -draw_pop_clip(Render_Target *target){ - target->pop_clip(target); -} - -internal void -begin_render_section(Render_Target *target, System_Functions *system){ - Font_Set *font_set = &target->font_set; - system->acquire_lock(RENDER_LOCK); - font_set->used_this_frame = 0; - memset(font_set->font_used_flags, 0, font_set->max); - target->size = 0; - target->clip_top = -1; - - i32_Rect clip; - clip.x0 = 0; - clip.y0 = 0; - clip.x1 = target->width; - clip.y1 = target->height; - draw_push_clip(target, clip); -} - -internal void -end_render_section(Render_Target *target, System_Functions *system){ - Assert(target->clip_top == 0); - system->release_lock(RENDER_LOCK); -} - -internal void -draw_rectangle(Render_Target *target, i32_Rect rect, u32 color){ - Render_Piece_Combined piece; - piece.header.type = piece_type_rectangle; - piece.rectangle.rect = f32R(rect); - piece.rectangle.color = color; - target->push_piece(target, piece); -} - -internal void -draw_rectangle(Render_Target *target, f32_Rect rect, u32 color){ - Render_Piece_Combined piece; - piece.header.type = piece_type_rectangle; - piece.rectangle.rect = rect; - piece.rectangle.color = color; - target->push_piece(target, piece); -} - -internal void -draw_gradient_2corner_clipped(Render_Target *target, f32_Rect rect, - Vec4 left_color, Vec4 right_color){ - Render_Piece_Combined piece; - piece.header.type = piece_type_gradient; - piece.gradient.rect = rect; - piece.gradient.left_color = pack_color4(left_color); - piece.gradient.right_color = pack_color4(right_color); - target->push_piece(target, piece); -} - -inline void -draw_gradient_2corner_clipped(Render_Target *target, f32 l, f32 t, f32 r, f32 b, - Vec4 color_left, Vec4 color_right){ - draw_gradient_2corner_clipped(target, f32R(l,t,r,b), color_left, color_right); -} - -internal void -draw_rectangle_outline(Render_Target *target, f32_Rect rect, u32 color){ - Render_Piece_Combined piece; - piece.header.type = piece_type_outline; - piece.rectangle.rect = rect; - piece.rectangle.color = color; - target->push_piece(target, piece); -} - -inline void -draw_rectangle_outline(Render_Target *target, i32_Rect rect, u32 color){ - draw_rectangle_outline(target, f32R(rect), color); -} - -internal void -draw_margin(Render_Target *target, i32_Rect outer, i32_Rect inner, u32 color){ - draw_rectangle(target, i32R(outer.x0, outer.y0, outer.x1, inner.y0), color); - draw_rectangle(target, i32R(outer.x0, inner.y1, outer.x1, outer.y1), color); - draw_rectangle(target, i32R(outer.x0, inner.y0, inner.x0, inner.y1), color); - draw_rectangle(target, i32R(inner.x1, inner.y0, outer.x1, inner.y1), color); -} - -inline void -draw_margin(Render_Target *target, i32_Rect outer, i32 width, u32 color){ - i32_Rect inner = get_inner_rect(outer, width); - draw_margin(target, outer, inner, color); -} - -inline internal i32 -font_predict_size(i32 pt_size){ - return pt_size*pt_size*128; -} - -internal void -font_set_tabwidth(Render_Font *font, i32 tab_width){ - font->chardata['\t'].xadvance *= font->chardata[' '].xadvance * tab_width; -} - -internal void -font_draw_glyph_mono(Render_Target *target, i16 font_id, - u8 character, f32 x, f32 y, f32 advance, u32 color){ - Render_Piece_Combined piece; - piece.header.type = piece_type_mono_glyph; - piece.glyph.pos.x = x; - piece.glyph.pos.y = y; - piece.glyph.color = color; - piece.glyph.font_id = font_id; - piece.glyph.character = character; - target->push_piece(target, piece); - font_set_use(target->partition, &target->font_set, font_id); -} - -inline void -font_draw_glyph_mono(Render_Target *target, i16 font_id, - u8 character, f32 x, f32 y, u32 color){ - f32 advance = (f32)get_font_info(&target->font_set, font_id)->advance; - font_draw_glyph_mono(target, font_id, character, x, y, advance, color); -} - -internal void -font_draw_glyph(Render_Target *target, i16 font_id, - u8 character, f32 x, f32 y, u32 color){ - Render_Piece_Combined piece; - piece.header.type = piece_type_glyph; - piece.glyph.pos.x = x; - piece.glyph.pos.y = y; - piece.glyph.color = color; - piece.glyph.font_id = font_id; - piece.glyph.character = character; - target->push_piece(target, piece); - font_set_use(target->partition, &target->font_set, font_id); -} - -inline f32 -font_get_glyph_width(Render_Target *target, i16 font_id, u16 character){ - Render_Font *font = get_font_info(&target->font_set, font_id)->font; - f32 result = 0.f; - if (font) result = font->chardata[character].xadvance; - return (result); -} - -internal f32 -font_string_width(Render_Target *target, i16 font_id, char *str){ - f32 x = 0; - for (i32 i = 0; str[i]; ++i){ - x += font_get_glyph_width(target, font_id, str[i]); - } - return x; -} - -internal i32 -draw_string(Render_Target *target, i16 font_id, - char *str, i32 x_, i32 y, u32 color){ - real32 x = (real32)x_; - for (i32 i = 0; str[i]; ++i){ - char c = str[i]; - font_draw_glyph(target, font_id, c, x, (f32)y, color); - x += font_get_glyph_width(target, font_id, c); - } - return CEIL32(x); -} - -internal f32 -draw_string_mono(Render_Target *target, i16 font_id, - char *str, f32 x, f32 y, f32 advance, u32 color){ - for (i32 i = 0; str[i]; ++i){ - font_draw_glyph_mono(target, font_id, str[i], - x, y, advance, color); - x += advance; - } - return x; -} - -internal i32 -draw_string(Render_Target *target, i16 font_id, - String str, i32 x_, i32 y, u32 color){ - f32 x = (f32)x_; - for (i32 i = 0; i < str.size; ++i){ - char c = str.str[i]; - font_draw_glyph(target, font_id, c, - x, (f32)y, color); - x += font_get_glyph_width(target, font_id, c); - } - return CEIL32(x); -} - -internal f32 -draw_string_mono(Render_Target *target, i16 font_id, - String str, f32 x, f32 y, f32 advance, u32 color){ - for (i32 i = 0; i < str.size; ++i){ - font_draw_glyph_mono(target, font_id, - str.str[i], x, y, advance, color); - x += advance; - } - return x; -} - -internal f32 -font_get_max_width(Font_Set *font_set, i16 font_id, char *characters){ - Render_Font *font = get_font_info(font_set, font_id)->font; - f32 cx, x = 0; - if (font){ - stbtt_packedchar *chardata = font->chardata; - for (i32 i = 0; characters[i]; ++i){ - cx = chardata[characters[i]].xadvance; - if (x < cx) x = cx; - } - } - return x; -} - -internal f32 -font_get_string_width(Render_Target *target, i16 font_id, String string){ - f32 result = 0; - for (i32 i = 0; i < string.size; ++i){ - font_get_glyph_width(target, font_id, string.str[i]); - } - return result; -} - -// BOTTOM - +/* + * Mr. 4th Dimention - Allen Webster + * + * 12.17.2014 + * + * Rendering layer for project codename "4ed" + * + */ + +// TOP + +inline void +draw_push_clip(Render_Target *target, i32_Rect clip_box){ + target->push_clip(target, clip_box); +} + +inline void +draw_pop_clip(Render_Target *target){ + target->pop_clip(target); +} + +internal void +begin_render_section(Render_Target *target, System_Functions *system){ + Font_Set *font_set = &target->font_set; + system->acquire_lock(RENDER_LOCK); + font_set->used_this_frame = 0; + memset(font_set->font_used_flags, 0, font_set->max); + target->size = 0; + target->clip_top = -1; + + i32_Rect clip; + clip.x0 = 0; + clip.y0 = 0; + clip.x1 = target->width; + clip.y1 = target->height; + draw_push_clip(target, clip); +} + +internal void +end_render_section(Render_Target *target, System_Functions *system){ + Assert(target->clip_top == 0); + system->release_lock(RENDER_LOCK); +} + +internal void +draw_rectangle(Render_Target *target, i32_Rect rect, u32 color){ + Render_Piece_Combined piece; + piece.header.type = piece_type_rectangle; + piece.rectangle.rect = f32R(rect); + piece.rectangle.color = color; + target->push_piece(target, piece); +} + +internal void +draw_rectangle(Render_Target *target, f32_Rect rect, u32 color){ + Render_Piece_Combined piece; + piece.header.type = piece_type_rectangle; + piece.rectangle.rect = rect; + piece.rectangle.color = color; + target->push_piece(target, piece); +} + +internal void +draw_gradient_2corner_clipped(Render_Target *target, f32_Rect rect, + Vec4 left_color, Vec4 right_color){ + Render_Piece_Combined piece; + piece.header.type = piece_type_gradient; + piece.gradient.rect = rect; + piece.gradient.left_color = pack_color4(left_color); + piece.gradient.right_color = pack_color4(right_color); + target->push_piece(target, piece); +} + +inline void +draw_gradient_2corner_clipped(Render_Target *target, f32 l, f32 t, f32 r, f32 b, + Vec4 color_left, Vec4 color_right){ + draw_gradient_2corner_clipped(target, f32R(l,t,r,b), color_left, color_right); +} + +internal void +draw_rectangle_outline(Render_Target *target, f32_Rect rect, u32 color){ + Render_Piece_Combined piece; + piece.header.type = piece_type_outline; + piece.rectangle.rect = rect; + piece.rectangle.color = color; + target->push_piece(target, piece); +} + +inline void +draw_rectangle_outline(Render_Target *target, i32_Rect rect, u32 color){ + draw_rectangle_outline(target, f32R(rect), color); +} + +internal void +draw_margin(Render_Target *target, i32_Rect outer, i32_Rect inner, u32 color){ + draw_rectangle(target, i32R(outer.x0, outer.y0, outer.x1, inner.y0), color); + draw_rectangle(target, i32R(outer.x0, inner.y1, outer.x1, outer.y1), color); + draw_rectangle(target, i32R(outer.x0, inner.y0, inner.x0, inner.y1), color); + draw_rectangle(target, i32R(inner.x1, inner.y0, outer.x1, inner.y1), color); +} + +inline void +draw_margin(Render_Target *target, i32_Rect outer, i32 width, u32 color){ + i32_Rect inner = get_inner_rect(outer, width); + draw_margin(target, outer, inner, color); +} + +inline internal i32 +font_predict_size(i32 pt_size){ + return pt_size*pt_size*128; +} + +internal void +font_set_tabwidth(Render_Font *font, i32 tab_width){ + font->chardata['\t'].xadvance *= font->chardata[' '].xadvance * tab_width; +} + +internal void +font_draw_glyph_mono(Render_Target *target, i16 font_id, + u8 character, f32 x, f32 y, f32 advance, u32 color){ + Render_Piece_Combined piece; + piece.header.type = piece_type_mono_glyph; + piece.glyph.pos.x = x; + piece.glyph.pos.y = y; + piece.glyph.color = color; + piece.glyph.font_id = font_id; + piece.glyph.character = character; + target->push_piece(target, piece); + font_set_use(target->partition, &target->font_set, font_id); +} + +inline void +font_draw_glyph_mono(Render_Target *target, i16 font_id, + u8 character, f32 x, f32 y, u32 color){ + f32 advance = (f32)get_font_info(&target->font_set, font_id)->advance; + font_draw_glyph_mono(target, font_id, character, x, y, advance, color); +} + +internal void +font_draw_glyph(Render_Target *target, i16 font_id, + u8 character, f32 x, f32 y, u32 color){ + Render_Piece_Combined piece; + piece.header.type = piece_type_glyph; + piece.glyph.pos.x = x; + piece.glyph.pos.y = y; + piece.glyph.color = color; + piece.glyph.font_id = font_id; + piece.glyph.character = character; + target->push_piece(target, piece); + font_set_use(target->partition, &target->font_set, font_id); +} + +inline f32 +font_get_glyph_width(Render_Target *target, i16 font_id, u16 character){ + Render_Font *font = get_font_info(&target->font_set, font_id)->font; + f32 result = 0.f; + if (font) result = font->chardata[character].xadvance; + return (result); +} + +internal f32 +font_string_width(Render_Target *target, i16 font_id, char *str){ + f32 x = 0; + for (i32 i = 0; str[i]; ++i){ + u8 c = str[i]; + // TODO(allen): Someday let's not punt on the the unicode rendering + c = c % 128; + x += font_get_glyph_width(target, font_id, c); + } + return x; +} + +internal f32 +font_string_width(Render_Target *target, i16 font_id, String str){ + f32 x = 0; + for (i32 i = 0; i < str.size; ++i){ + u8 c = str.str[i]; + // TODO(allen): Someday let's not punt on the the unicode rendering + c = c % 128; + x += font_get_glyph_width(target, font_id, c); + } + return x; +} + +internal i32 +draw_string(Render_Target *target, i16 font_id, + char *str, i32 x_, i32 y, u32 color){ + real32 x = (real32)x_; + for (i32 i = 0; str[i]; ++i){ + u8 c = str[i]; + // TODO(allen): Someday let's not punt on the the unicode rendering + c = c % 128; + font_draw_glyph(target, font_id, c, x, (f32)y, color); + x += font_get_glyph_width(target, font_id, c); + } + return CEIL32(x); +} + +internal f32 +draw_string_mono(Render_Target *target, i16 font_id, + char *str, f32 x, f32 y, f32 advance, u32 color){ + for (i32 i = 0; str[i]; ++i){ + u8 c = str[i]; + // TODO(allen): Someday let's not punt on the the unicode rendering + c = c % 128; + font_draw_glyph_mono(target, font_id, c, x, y, advance, color); + x += advance; + } + return x; +} + +internal i32 +draw_string(Render_Target *target, i16 font_id, + String str, i32 x_, i32 y, u32 color){ + f32 x = (f32)x_; + for (i32 i = 0; i < str.size; ++i){ + u8 c = str.str[i]; + // TODO(allen): Someday let's not punt on the the unicode rendering + c = c % 128; + font_draw_glyph(target, font_id, c, + x, (f32)y, color); + x += font_get_glyph_width(target, font_id, c); + } + return CEIL32(x); +} + +internal f32 +draw_string_mono(Render_Target *target, i16 font_id, + String str, f32 x, f32 y, f32 advance, u32 color){ + for (i32 i = 0; i < str.size; ++i){ + u8 c = str.str[i]; + // TODO(allen): Someday let's not punt on the the unicode rendering + c = c % 128; + font_draw_glyph_mono(target, font_id, c, x, y, advance, color); + x += advance; + } + return x; +} + +internal f32 +font_get_max_width(Font_Set *font_set, i16 font_id, char *characters){ + Render_Font *font = get_font_info(font_set, font_id)->font; + f32 cx, x = 0; + if (font){ + stbtt_packedchar *chardata = font->chardata; + for (i32 i = 0; characters[i]; ++i){ + cx = chardata[characters[i]].xadvance; + if (x < cx) x = cx; + } + } + return x; +} + +internal f32 +font_get_string_width(Render_Target *target, i16 font_id, String string){ + f32 result = 0; + for (i32 i = 0; i < string.size; ++i){ + u8 c = string.str[i]; + // TODO(allen): Someday let's not punt on the the unicode rendering + c = c % 128; + font_get_glyph_width(target, font_id, c); + } + return result; +} + +// BOTTOM + diff --git a/linux_4ed.cpp b/linux_4ed.cpp index 544a2069..891a6e78 100644 --- a/linux_4ed.cpp +++ b/linux_4ed.cpp @@ -1061,100 +1061,6 @@ main(int argc, char **argv) }break; } - -#if 0 - if((Event.xcookie.type == GenericEvent) && - (Event.xcookie.extension == XInput2OpCode) && - XGetEventData(linuxvars.XDisplay, &Event.xcookie)) - { - switch(Event.xcookie.evtype) - { - case XI_Motion: - { - Window root_return, child_return; - int root_x_return, root_y_return; - int MouseX, MouseY; - unsigned int mask_return; - XQueryPointer(linuxvars.XDisplay, - linuxvars.XWindow, - &root_return, &child_return, - &root_x_return, &root_y_return, - &MouseX, &MouseY, - &mask_return); - } break; - - case XI_ButtonPress: - case XI_ButtonRelease: - { - b32 Down = (Event.xcookie.evtype == XI_ButtonPress); - XIDeviceEvent *DevEvent = (XIDeviceEvent *)Event.xcookie.data; - int Button = DevEvent->detail; - } break; - - case XI_KeyPress: - case XI_KeyRelease: - { - b32 Down = (Event.xcookie.evtype == XI_KeyPress); - XIDeviceEvent *DevEvent = (XIDeviceEvent *)Event.xcookie.data; - int keycode = DevEvent->detail; - - if (Down){ - printf("Keycode %d\n", keycode); - - // NOTE(allen): Thanks to eisbehr for providing the code - // for initializing an XKeyPressedEvent struct for use in - // Xmb8LookupString - XKeyPressedEvent eventBase = {}; - eventBase.type = KeyPress; - eventBase.serial = 0xF00D; - eventBase.send_event = 1; // at least admit that this isn't a genuine event - eventBase.display = DevEvent->display; - eventBase.window = DevEvent->event; - eventBase.root = DevEvent->root; - eventBase.subwindow = 0; - eventBase.time = {}; // Let's hope we don't need a real time. - eventBase.x = 0; - eventBase.y = 0; - eventBase.x_root = 0; - eventBase.y_root = 0; - eventBase.state = 0; // state of modifiers - // Button1Mask, Button2Mask, Button3Mask, Button4Mask, Button5Mask, - // ShiftMask, LockMask, ControlMask, - // Mod1Mask, Mod2Mask, Mod3Mask, Mod4Mask, Mod5Mask. - //eventBase.keycode = 10;//minKeyCode; - eventBase.same_screen = 1; - - eventBase.keycode = keycode; - - char lookup_buffer[32]; - Status status; - i32 size; - KeySym keysym; - - size = XmbLookupString(linuxvars.xic, &eventBase, - lookup_buffer, sizeof(lookup_buffer), - &keysym, &status); - - if (status == XBufferOverflow){ - printf("Buffer overflow %d\n", size); - } - else if (status == XLookupNone){ - printf("nothing branch\n"); - } - else if (status == XLookupChars || status == XLookupBoth){ - printf("keysym %lu translation: %.*s\n", keysym, size, lookup_buffer); - } - else{ - printf("unknown branch %d\n", status); - } - break; - } - } break; - } - - XFreeEventData(linuxvars.XDisplay, &Event.xcookie); - } -#endif } b32 redraw = 1; diff --git a/system_shared.h b/system_shared.h index adaa2d0f..8e272976 100644 --- a/system_shared.h +++ b/system_shared.h @@ -37,12 +37,14 @@ struct Font_Load_System{ #define Sys_File_Can_Be_Made(name) b32 name(char *filename) #define Sys_Load_File_Sig(name) Data name(char *filename) #define Sys_Save_File_Sig(name) b32 name(char *filename, char *data, i32 size) +#define Sys_To_Binary_Path(name) b32 name(String *out_filename, char *filename) internal Sys_Get_Memory_Sig(system_get_memory_); internal Sys_Free_Memory_Sig(system_free_memory); internal Sys_File_Can_Be_Made(system_file_can_be_made); internal Sys_Load_File_Sig(system_load_file); internal Sys_Save_File_Sig(system_save_file); +internal Sys_To_Binary_Path(system_to_binary_path); #define system_get_memory(size) system_get_memory_((size), __LINE__, __FILE__) diff --git a/vc120.pdb b/vc120.pdb index 4ce228dc..4e2ab7e7 100644 Binary files a/vc120.pdb and b/vc120.pdb differ diff --git a/win32_4ed.cpp b/win32_4ed.cpp index 5ecaac89..a7951358 100644 --- a/win32_4ed.cpp +++ b/win32_4ed.cpp @@ -1,1796 +1,1810 @@ -/* - * Mr. 4th Dimention - Allen Webster - * - * 12.12.2014 - * - * Win32 layer for project codename "4ed" - * - */ - -// TOP - -#include "4ed_config.h" - -#include "4ed_meta.h" - -#define FCPP_FORBID_MALLOC - -#include "4cpp_types.h" -#define FCPP_STRING_IMPLEMENTATION -#include "4coder_string.h" - -#include "4ed_mem.cpp" -#include "4ed_math.cpp" - -#include "4ed_dll_reader.h" - -#include "4coder_custom.h" -#include "4ed_system.h" -#include "4ed_rendering.h" -#include "4ed.h" - -#include -#include - -#include "4ed_dll_reader.cpp" -#include "4ed_internal.h" -#include "4ed_win32_keyboard.cpp" -#include "system_shared.h" - -#define FPS 30 -#define frame_useconds (1000000 / FPS) - -#define WM_4coder_LOAD_FONT (WM_USER + 1) -#define WM_4coder_PAINT (WM_USER + 2) -#define WM_4coder_SET_CURSOR (WM_USER + 3) - -struct Thread_Context{ - u32 job_id; - b32 running; - - Work_Queue *queue; - u32 id; - u32 windows_id; - HANDLE handle; -}; - -struct Thread_Group{ - Thread_Context *threads; - i32 count; -}; - -#define UseWinDll 1 - -struct Control_Keys{ - b8 l_ctrl; - b8 r_ctrl; - b8 l_alt; - b8 r_alt; -}; - -struct Win32_Input_Chunk_Transient{ - Key_Input_Data key_data; - - b8 mouse_l_press, mouse_l_release; - b8 mouse_r_press, mouse_r_release; - b32 out_of_window; - i16 mouse_wheel; - - b32 redraw; -}; - -struct Win32_Input_Chunk_Persistent{ - i32 mouse_x, mouse_y; - b8 mouse_l, mouse_r; - - b8 keep_playing; - - Control_Keys controls; - b8 control_keys[CONTROL_KEY_COUNT]; -}; - -struct Win32_Input_Chunk{ - Win32_Input_Chunk_Transient trans; - Win32_Input_Chunk_Persistent pers; -}; - -struct Win32_Vars{ - HWND window_handle; - HDC window_hdc; - Render_Target target; - - HANDLE update_loop_thread; - DWORD update_loop_thread_id; - - Key_Codes key_codes; - Win32_Input_Chunk input_chunk; - b32 lctrl_lalt_is_altgr; - - HCURSOR cursor_ibeam; - HCURSOR cursor_arrow; - HCURSOR cursor_leftright; - HCURSOR cursor_updown; - Application_Mouse_Cursor prev_mouse_cursor; - Clipboard_Contents clipboard_contents; - b32 next_clipboard_is_self; - DWORD clipboard_sequence; - - Thread_Group groups[THREAD_GROUP_COUNT]; - HANDLE locks[LOCK_COUNT]; - HANDLE DEBUG_sysmem_lock; - - Thread_Memory *thread_memory; - - u64 performance_frequency; - u64 start_pcount; - u64 start_time; - -#if UseWinDll - HMODULE app_code; - HMODULE custom; -#else - DLL_Loaded app_dll; - DLL_Loaded custom_dll; -#endif - - Plat_Settings settings; - System_Functions *system; - App_Functions app; - Custom_API custom_api; - b32 first; - -#if FRED_INTERNAL - Sys_Bubble internal_bubble; -#endif - - Font_Load_System fnt; -}; - -globalvar Win32_Vars win32vars; -globalvar Application_Memory memory_vars; -globalvar Exchange exchange_vars; - -#if FRED_INTERNAL -internal Bubble* -INTERNAL_system_sentinel(){ - return (&win32vars.internal_bubble); -} - -internal void -INTERNAL_system_debug_message(char *message){ - OutputDebugString(message); -} - -#endif - -// TODO(allen): Transition towards using system_shared functions - -internal void* -Win32GetMemory_(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; -} - -internal -Sys_Get_Memory_Sig(system_get_memory_){ - return(Win32GetMemory_(size, line_number, file_name)); -} - -#define Win32GetMemory(size) Win32GetMemory_(size, __LINE__, __FILE__) - -internal void -Win32FreeMemory(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 Partition -Win32ScratchPartition(i32 size){ - Partition part; - void *data; - data = Win32GetMemory(size); - part = partition_open(data, size); - return(part); -} - -internal void -Win32ScratchPartitionGrow(Partition *part, i32 new_size){ - void *data; - if (new_size > part->max){ - data = Win32GetMemory(new_size); - memcpy(data, part->base, part->pos); - Win32FreeMemory(part->base); - part->base = (u8*)data; - } -} - -internal void -Win32ScratchPartitionDouble(Partition *part){ - Win32ScratchPartitionGrow(part, part->max*2); -} - -inline void -system_free_memory(void *block){ - Win32FreeMemory(block); -} - -internal Data -system_load_file(char *filename){ - Data result = {}; - HANDLE file; - file = CreateFile((char*)filename, GENERIC_READ, 0, 0, - OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); - if (!file || file == INVALID_HANDLE_VALUE){ - return result; - } - - DWORD lo, hi; - lo = GetFileSize(file, &hi); - - if (hi != 0){ - CloseHandle(file); - return result; - } - - result.size = (lo) + (((u64)hi) << 32); - result.data = (byte*)Win32GetMemory(result.size); - - if (!result.data){ - CloseHandle(file); - result = {}; - return result; - } - - DWORD read_size; - BOOL read_result = ReadFile(file, result.data, result.size, - &read_size, 0); - if (!read_result || read_size != (u32)result.size){ - CloseHandle(file); - Win32FreeMemory(result.data); - result = {}; - return result; - } - - CloseHandle(file); - return result; -} - -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); - - if (!file || file == INVALID_HANDLE_VALUE){ - return 0; - } - - BOOL write_result; - DWORD bytes_written; - write_result = WriteFile(file, data, size, &bytes_written, 0); - - CloseHandle(file); - - if (!write_result || bytes_written != (u32)size){ - return 0; - } - - return 1; -} - -internal b32 -system_file_can_be_made(char *filename){ - HANDLE file; - file = CreateFile((char*)filename, FILE_APPEND_DATA, 0, 0, - OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0); - - if (!file || file == INVALID_HANDLE_VALUE){ - return 0; - } - - CloseHandle(file); - - return 1; -} - -internal -Sys_File_Time_Stamp_Sig(system_file_time_stamp){ - u64 result; - result = 0; - - FILETIME last_write; - WIN32_FILE_ATTRIBUTE_DATA data; - if (GetFileAttributesEx((char*)filename, GetFileExInfoStandard, &data)){ - last_write = data.ftLastWriteTime; - - result = ((u64)last_write.dwHighDateTime << 32) | (last_write.dwLowDateTime); - result /= 10; - } - - return result; -} - -internal -Sys_Time_Sig(system_time){ - u64 result = 0; - LARGE_INTEGER time; - if (QueryPerformanceCounter(&time)){ - result = (u64)(time.QuadPart - win32vars.start_pcount) * 1000000 / win32vars.performance_frequency; - result += win32vars.start_time; - } - return result; -} - -internal -Sys_Set_File_List_Sig(system_set_file_list){ - if (directory.size > 0){ - char dir_space[MAX_PATH + 32]; - String dir = make_string(dir_space, 0, MAX_PATH + 32); - append(&dir, directory); - char trail_str[] = "\\*"; - append(&dir, trail_str); - - char *c_str_dir = make_c_str(dir); - - WIN32_FIND_DATA find_data; - HANDLE search; - search = FindFirstFileA(c_str_dir, &find_data); - - if (search != INVALID_HANDLE_VALUE){ - i32 count = 0; - i32 file_count = 0; - BOOL more_files = 1; - do{ - if (!match(find_data.cFileName, ".") && - !match(find_data.cFileName, "..")){ - ++file_count; - i32 size = 0; - for(;find_data.cFileName[size];++size); - count += size + 1; - } - more_files = FindNextFile(search, &find_data); - }while(more_files); - FindClose(search); - - i32 required_size = count + file_count * sizeof(File_Info); - if (file_list->block_size < required_size){ - Win32FreeMemory(file_list->block); - file_list->block = Win32GetMemory(required_size); - } - - file_list->infos = (File_Info*)file_list->block; - char *name = (char*)(file_list->infos + file_count); - if (file_list->block){ - search = FindFirstFileA(c_str_dir, &find_data); - - if (search != INVALID_HANDLE_VALUE){ - File_Info *info = file_list->infos; - more_files = 1; - do{ - if (!match(find_data.cFileName, ".") && - !match(find_data.cFileName, "..")){ - info->folder = (find_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0; - info->filename.str = name; - - i32 i = 0; - for(;find_data.cFileName[i];++i) *name++ = find_data.cFileName[i]; - info->filename.size = i; - info->filename.memory_size = info->filename.size + 1; - *name++ = 0; - ++info; - } - more_files = FindNextFile(search, &find_data); - }while(more_files); - FindClose(search); - - file_list->count = file_count; - - }else{ - Win32FreeMemory(file_list->block); - file_list->block = 0; - file_list->block_size = 0; - } - } - } - } -} - -internal -DIRECTORY_HAS_FILE_SIG(system_directory_has_file){ - char *full_filename; - char space[1024]; - HANDLE file; - b32 result; - i32 len; - - full_filename = 0; - len = str_size(filename); - if (dir.memory_size - dir.size - 1 >= len){ - full_filename = dir.str; - memcpy(dir.str + dir.size, filename, len + 1); - } - else if (dir.size + len + 1 < 1024){ - full_filename = space; - memcpy(full_filename, dir.str, dir.size); - memcpy(full_filename + dir.size, filename, len + 1); - } - - result = 0; - if (full_filename){ - file = CreateFile((char*)full_filename, GENERIC_READ, 0, 0, - OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); - if (file != INVALID_HANDLE_VALUE){ - CloseHandle(file); - result = 1; - } - dir.str[dir.size] = 0; - } - - return(result); -} - -b32 Win32DirectoryExists(char *path){ - DWORD attrib = GetFileAttributesA(path); - return (attrib != INVALID_FILE_ATTRIBUTES && - (attrib & FILE_ATTRIBUTE_DIRECTORY)); -} - -internal -DIRECTORY_CD_SIG(system_directory_cd){ - b32 result = 0; - i32 old_size; - i32 len; - - if (rel_path[0] != 0){ - if (rel_path[0] == '.' && rel_path[1] == 0){ - result = 1; - } - else if (rel_path[0] == '.' && rel_path[1] == '.' && rel_path[2] == 0){ - result = remove_last_folder(dir); - terminate_with_null(dir); - } - else{ - len = str_size(rel_path); - if (dir->size + len + 1 > dir->memory_size){ - old_size = dir->size; - append_partial(dir, rel_path); - append_partial(dir, "\\"); - if (Win32DirectoryExists(dir->str)){ - result = 1; - } - else{ - dir->size = old_size; - } - } - } - } - - return(result); -} - -internal -Sys_Post_Clipboard_Sig(system_post_clipboard){ - if (OpenClipboard(win32vars.window_handle)){ - EmptyClipboard(); - HANDLE memory_handle; - memory_handle = GlobalAlloc(GMEM_MOVEABLE, str.size+1); - if (memory_handle){ - char *dest = (char*)GlobalLock(memory_handle); - copy_fast_unsafe(dest, str); - GlobalUnlock(memory_handle); - SetClipboardData(CF_TEXT, memory_handle); - win32vars.next_clipboard_is_self = 1; - } - CloseClipboard(); - } -} - -internal -Sys_Acquire_Lock_Sig(system_acquire_lock){ - WaitForSingleObject(win32vars.locks[id], INFINITE); -} - -internal -Sys_Release_Lock_Sig(system_release_lock){ - ReleaseSemaphore(win32vars.locks[id], 1, 0); -} - -internal void -Win32RedrawFromUpdate(){ - SendMessage( - win32vars.window_handle, - WM_4coder_PAINT, - 0, 0); -} - -internal void -Win32SetCursorFromUpdate(Application_Mouse_Cursor cursor){ - SendMessage( - win32vars.window_handle, - WM_4coder_SET_CURSOR, - cursor, 0); -} - -internal void -Win32Resize(i32 width, i32 height){ - if (width > 0 && height > 0){ - glViewport(0, 0, width, height); - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - glOrtho(0, width, height, 0, -1, 1); - glScissor(0, 0, width, height); - - win32vars.target.width = width; - win32vars.target.height = height; - } -} - -internal HANDLE -Win32Handle(Plat_Handle h){ - HANDLE result; - result = {}; - result = *(HANDLE*)(&h); - return(result); -} - -internal Plat_Handle -Win32GenHandle(HANDLE h){ - Assert(sizeof(Plat_Handle) >= sizeof(HANDLE)); - Plat_Handle result; - result = *(Plat_Handle*)(&h); - return(result); -} - -internal DWORD WINAPI -ThreadProc(LPVOID lpParameter){ - Thread_Context *thread = (Thread_Context*)lpParameter; - Work_Queue *queue = thread->queue; - - for (;;){ - u32 read_index = queue->read_position; - u32 write_index = queue->write_position; - - if (read_index != write_index){ - u32 next_read_index = (read_index + 1) % JOB_ID_WRAP; - u32 safe_read_index = - InterlockedCompareExchange(&queue->read_position, - next_read_index, read_index); - - if (safe_read_index == read_index){ - Full_Job_Data *full_job = queue->jobs + (safe_read_index % QUEUE_WRAP); - // NOTE(allen): This is interlocked so that it plays nice - // with the cancel job routine, which may try to cancel this job - // at the same time that we try to run it - - i32 safe_running_thread = - InterlockedCompareExchange(&full_job->running_thread, - thread->id, THREAD_NOT_ASSIGNED); - - if (safe_running_thread == THREAD_NOT_ASSIGNED){ - thread->job_id = full_job->id; - thread->running = 1; - Thread_Memory *thread_memory = 0; - - // TODO(allen): remove memory_request - if (full_job->job.memory_request != 0){ - thread_memory = win32vars.thread_memory + thread->id - 1; - if (thread_memory->size < full_job->job.memory_request){ - if (thread_memory->data){ - Win32FreeMemory(thread_memory->data); - } - i32 new_size = LargeRoundUp(full_job->job.memory_request, Kbytes(4)); - thread_memory->data = Win32GetMemory(new_size); - thread_memory->size = new_size; - } - } - full_job->job.callback(win32vars.system, thread, thread_memory, - &exchange_vars.thread, full_job->job.data); - full_job->running_thread = 0; - thread->running = 0; - } - } - } - else{ - WaitForSingleObject(Win32Handle(queue->semaphore), INFINITE); - } - } -} - -internal -Sys_Post_Job_Sig(system_post_job){ - Work_Queue *queue = exchange_vars.thread.queues + group_id; - - Assert((queue->write_position + 1) % QUEUE_WRAP != queue->read_position % QUEUE_WRAP); - - b32 success = 0; - u32 result = 0; - while (!success){ - u32 write_index = queue->write_position; - u32 next_write_index = (write_index + 1) % JOB_ID_WRAP; - u32 safe_write_index = - InterlockedCompareExchange(&queue->write_position, - next_write_index, write_index); - if (safe_write_index == write_index){ - result = write_index; - write_index = write_index % QUEUE_WRAP; - queue->jobs[write_index].job = job; - queue->jobs[write_index].running_thread = THREAD_NOT_ASSIGNED; - queue->jobs[write_index].id = result; - success = 1; - } - } - - ReleaseSemaphore(Win32Handle(queue->semaphore), 1, 0); - - return result; -} - -internal -Sys_Cancel_Job_Sig(system_cancel_job){ - Work_Queue *queue = exchange_vars.thread.queues + group_id; - Thread_Group *group = win32vars.groups + group_id; - - u32 job_index; - u32 thread_id; - Full_Job_Data *full_job; - Thread_Context *thread; - - job_index = job_id % QUEUE_WRAP; - full_job = queue->jobs + job_index; - - Assert(full_job->id == job_id); - thread_id = - InterlockedCompareExchange(&full_job->running_thread, - 0, THREAD_NOT_ASSIGNED); - - if (thread_id != THREAD_NOT_ASSIGNED){ - system_acquire_lock(CANCEL_LOCK0 + thread_id - 1); - thread = group->threads + thread_id - 1; - TerminateThread(thread->handle, 0); - u32 creation_flag = 0; - thread->handle = CreateThread(0, 0, ThreadProc, thread, creation_flag, (LPDWORD)&thread->windows_id); - system_release_lock(CANCEL_LOCK0 + thread_id - 1); - thread->running = 0; - } -} - -internal void -system_grow_thread_memory(Thread_Memory *memory){ - void *old_data; - i32 old_size, new_size; - - system_acquire_lock(CANCEL_LOCK0 + memory->id - 1); - old_data = memory->data; - old_size = memory->size; - new_size = LargeRoundUp(memory->size*2, Kbytes(4)); - memory->data = Win32GetMemory(new_size); - memory->size = new_size; - if (old_data){ - memcpy(memory->data, old_data, old_size); - Win32FreeMemory(old_data); - } - system_release_lock(CANCEL_LOCK0 + memory->id - 1); -} - -#if FRED_INTERNAL -internal void -INTERNAL_get_thread_states(Thread_Group_ID id, bool8 *running, i32 *pending){ - Work_Queue *queue = exchange_vars.thread.queues + id; - u32 write = queue->write_position; - u32 read = queue->read_position; - if (write < read) write += JOB_ID_WRAP; - *pending = (i32)(write - read); - - Thread_Group *group = win32vars.groups + id; - for (i32 i = 0; i < group->count; ++i){ - running[i] = (group->threads[i].running != 0); - } -} -#endif - -internal -Sys_CLI_Call_Sig(system_cli_call){ - char cmd[] = "c:\\windows\\system32\\cmd.exe"; - char *env_variables = 0; - char command_line[2048]; - - b32 success = 1; - String s = make_fixed_width_string(command_line); - copy(&s, make_lit_string("/C ")); - append_partial(&s, script_name); - success = terminate_with_null(&s); - - if (success){ - success = 0; - - SECURITY_ATTRIBUTES sec_attributes; - HANDLE out_read; - HANDLE out_write; - - sec_attributes = {}; - sec_attributes.nLength = sizeof(SECURITY_ATTRIBUTES); - sec_attributes.bInheritHandle = TRUE; - - if (CreatePipe(&out_read, &out_write, &sec_attributes, 0)){ - if (SetHandleInformation(out_read, HANDLE_FLAG_INHERIT, 0)){ - STARTUPINFO startup = {}; - startup.cb = sizeof(STARTUPINFO); - startup.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES; - startup.hStdError = out_write; - startup.hStdOutput = out_write; - startup.wShowWindow = SW_HIDE; - - PROCESS_INFORMATION info = {}; - - Assert(sizeof(Plat_Handle) >= sizeof(HANDLE)); - if (CreateProcess(cmd, command_line, - 0, 0, TRUE, 0, - env_variables, path, - &startup, &info)){ - success = 1; - CloseHandle(info.hThread); - *(HANDLE*)&cli_out->proc = info.hProcess; - *(HANDLE*)&cli_out->out_read = out_read; - *(HANDLE*)&cli_out->out_write = out_write; - } - else{ - CloseHandle(out_read); - CloseHandle(out_write); - *(HANDLE*)&cli_out->proc = INVALID_HANDLE_VALUE; - *(HANDLE*)&cli_out->out_read = INVALID_HANDLE_VALUE; - *(HANDLE*)&cli_out->out_write = INVALID_HANDLE_VALUE; - } - } - else{ - // TODO(allen): failed SetHandleInformation - } - } - else{ - // TODO(allen): failed CreatePipe - } - } - - return success; -} - -struct CLI_Loop_Control{ - u32 remaining_amount; -}; - -internal -Sys_CLI_Begin_Update_Sig(system_cli_begin_update){ - Assert(sizeof(cli->scratch_space) >= sizeof(CLI_Loop_Control)); - CLI_Loop_Control *loop = (CLI_Loop_Control*)cli->scratch_space; - loop->remaining_amount = 0; -} - -internal -Sys_CLI_Update_Step_Sig(system_cli_update_step){ - HANDLE handle = *(HANDLE*)&cli->out_read; - CLI_Loop_Control *loop = (CLI_Loop_Control*)cli->scratch_space; - b32 has_more = 0; - DWORD remaining = loop->remaining_amount; - u32 pos = 0; - DWORD read_amount = 0; - - for (;;){ - if (remaining == 0){ - if (!PeekNamedPipe(handle, 0, 0, 0, &remaining, 0)) break; - if (remaining == 0) break; - } - - if (remaining + pos < max){ - has_more = 1; - ReadFile(handle, dest + pos, remaining, &read_amount, 0); - TentativeAssert(remaining == read_amount); - pos += remaining; - remaining = 0; - } - else{ - has_more = 1; - ReadFile(handle, dest + pos, max - pos, &read_amount, 0); - TentativeAssert(max - pos == read_amount); - loop->remaining_amount = remaining - (max - pos); - pos = max; - break; - } - } - *amount = pos; - - return has_more; -} - -internal -Sys_CLI_End_Update_Sig(system_cli_end_update){ - b32 close_me = 0; - HANDLE proc = *(HANDLE*)&cli->proc; - DWORD result = 0; - - if (WaitForSingleObject(proc, 0) == WAIT_OBJECT_0){ - if (GetExitCodeProcess(proc, &result) == 0) - cli->exit = -1; - else - cli->exit = (i32)result; - - close_me = 1; - CloseHandle(*(HANDLE*)&cli->proc); - CloseHandle(*(HANDLE*)&cli->out_read); - CloseHandle(*(HANDLE*)&cli->out_write); - } - return close_me; -} - -internal b32 -Win32LoadAppCode(){ - b32 result = 0; - App_Get_Functions *get_funcs = 0; - -#if UseWinDll - win32vars.app_code = LoadLibraryA("4ed_app.dll"); - if (win32vars.app_code){ - get_funcs = (App_Get_Functions*) - GetProcAddress(win32vars.app_code, "app_get_functions"); - } - -#else - Data file = system_load_file("4ed_app.dll"); - - if (file.data){ - i32 error; - DLL_Data dll_data; - if (dll_parse_headers(file, &dll_data, &error)){ - Data img; - img.size = dll_total_loaded_size(&dll_data); - img.data = (byte*) - VirtualAlloc((LPVOID)Tbytes(3), img.size, - MEM_COMMIT | MEM_RESERVE, - PAGE_READWRITE); - - dll_load(img, &win32vars.app_dll, file, &dll_data); - - DWORD extra_; - VirtualProtect(img.data + win32vars.app_dll.text_start, - win32vars.app_dll.text_size, - PAGE_EXECUTE_READ, - &extra_); - - get_funcs = (App_Get_Functions*) - dll_load_function(&win32vars.app_dll, "app_get_functions", 17); - } - else{ - // TODO(allen): file loading error - } - - system_free(file.data); - - DUMP((byte*)(Tbytes(3)), Kbytes(400)); - } - else{ - // TODO(allen): file loading error - } - -#endif - - if (get_funcs){ - result = 1; - win32vars.app = get_funcs(); - } - - return result; -} - -internal void -Win32LoadSystemCode(){ - win32vars.system->file_time_stamp = system_file_time_stamp; - win32vars.system->set_file_list = system_set_file_list; - - win32vars.system->directory_has_file = system_directory_has_file; - win32vars.system->directory_cd = system_directory_cd; - - 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->post_job = system_post_job; - win32vars.system->cancel_job = system_cancel_job; - 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->internal_sentinel = INTERNAL_system_sentinel; - win32vars.system->internal_get_thread_states = INTERNAL_get_thread_states; - win32vars.system->internal_debug_message = INTERNAL_system_debug_message; -} - -#include "system_shared.cpp" -#include "4ed_rendering.cpp" - -internal -Font_Load_Sig(system_draw_font_load){ - Font_Load_Parameters *params; - - system_acquire_lock(FONT_LOCK); - params = win32vars.fnt.free_param.next; - fnt__remove(params); - fnt__insert(&win32vars.fnt.used_param, params); - system_release_lock(FONT_LOCK); - - params->font_out = font_out; - params->filename = filename; - params->pt_size = pt_size; - params->tab_width = tab_width; - - SendMessage(win32vars.window_handle, - WM_4coder_LOAD_FONT, - 0, (i32)(params - win32vars.fnt.params)); - return(1); -} - -internal void -Win32LoadRenderCode(){ - win32vars.target.push_clip = draw_push_clip; - win32vars.target.pop_clip = draw_pop_clip; - win32vars.target.push_piece = draw_push_piece; - - win32vars.target.font_set.font_info_load = draw_font_info_load; - win32vars.target.font_set.font_load = system_draw_font_load; - win32vars.target.font_set.release_font = draw_release_font; -} - -internal void -Win32RedrawScreen(HDC hdc){ - system_acquire_lock(RENDER_LOCK); - launch_rendering(&win32vars.target); - system_release_lock(RENDER_LOCK); - glFlush(); - SwapBuffers(hdc); -} - -internal LRESULT -Win32Callback(HWND hwnd, UINT uMsg, - WPARAM wParam, LPARAM lParam){ - LRESULT result = {}; - switch (uMsg){ - case WM_MENUCHAR: - case WM_SYSCHAR:break; - - case WM_SYSKEYDOWN: - case WM_SYSKEYUP: - case WM_KEYDOWN: - case WM_KEYUP: - { - switch (wParam){ - case VK_CONTROL:case VK_LCONTROL:case VK_RCONTROL: - case VK_MENU:case VK_LMENU:case VK_RMENU: - case VK_SHIFT:case VK_LSHIFT:case VK_RSHIFT: - { - Control_Keys *controls = 0; - b8 *control_keys = 0; - controls = &win32vars.input_chunk.pers.controls; - control_keys = win32vars.input_chunk.pers.control_keys; - - system_acquire_lock(INPUT_LOCK); - - b8 down = ((lParam & Bit_31)?(0):(1)); - b8 is_right = ((lParam & Bit_24)?(1):(0)); - - if (wParam != 255){ - switch (wParam){ - case VK_SHIFT: - { - control_keys[CONTROL_KEY_SHIFT] = down; - }break; - - case VK_CONTROL: - { - if (is_right) controls->r_ctrl = down; - else controls->l_ctrl = down; - }break; - - case VK_MENU: - { - if (is_right) controls->r_alt = down; - else controls->l_alt = down; - }break; - } - - b8 ctrl, alt; - ctrl = (controls->r_ctrl || (controls->l_ctrl && !controls->r_alt)); - alt = (controls->l_alt || (controls->r_alt && !controls->l_ctrl)); - - if (win32vars.lctrl_lalt_is_altgr){ - if (controls->l_alt && controls->l_ctrl){ - ctrl = 0; - alt = 0; - } - } - - control_keys[CONTROL_KEY_CONTROL] = ctrl; - control_keys[CONTROL_KEY_ALT] = alt; - } - system_release_lock(INPUT_LOCK); - }break; - - default: - b8 previous_state, current_state; - previous_state = ((lParam & Bit_30)?(1):(0)); - current_state = ((lParam & Bit_31)?(0):(1)); - - if (current_state){ - u8 key = keycode_lookup((u8)wParam); - - i32 *count = 0; - Key_Event_Data *data = 0; - b8 *control_keys = 0; - i32 control_keys_size = 0; - - system_acquire_lock(INPUT_LOCK); - if (!previous_state){ - count = &win32vars.input_chunk.trans.key_data.press_count; - data = win32vars.input_chunk.trans.key_data.press; - } - else{ - count = &win32vars.input_chunk.trans.key_data.hold_count; - data = win32vars.input_chunk.trans.key_data.hold; - } - control_keys = win32vars.input_chunk.pers.control_keys; - control_keys_size = sizeof(win32vars.input_chunk.pers.control_keys); - - if (*count < KEY_INPUT_BUFFER_SIZE){ - if (!key){ - UINT vk = (UINT)wParam; - UINT scan = (UINT)((lParam >> 16) & 0x7F); - BYTE state[256]; - WORD x; - int result; - - GetKeyboardState(state); - if (control_keys[CONTROL_KEY_CONTROL] && - !control_keys[CONTROL_KEY_ALT]) - state[VK_CONTROL] = 0; - x = 0; - result = ToAscii(vk, scan, state, &x, 0); - if (result == 1 && x < 128){ - key = (u8)x; - if (key == '\r') key = '\n'; - data[*count].character = key; - - state[VK_CAPITAL] = 0; - x = 0; - result = ToAscii(vk, scan, state, &x, 0); - if (result == 1 && x < 128){ - key = (u8)x; - if (key == '\r') key = '\n'; - data[*count].character_no_caps_lock = key; - data[*count].keycode = key; - } - } - if (result != 1 || x >= 128){ - data[*count].character = 0; - data[*count].character_no_caps_lock = 0; - data[*count].keycode = 0; - } - } - else{ - data[*count].character = 0; - data[*count].character_no_caps_lock = 0; - data[*count].keycode = key; - } - memcpy(data[*count].modifiers, control_keys, control_keys_size); - ++(*count); - } - } - system_release_lock(INPUT_LOCK); - - result = DefWindowProc(hwnd, uMsg, wParam, lParam); - } - }break; - - case WM_INPUT: - - - case WM_MOUSEMOVE: - { - system_acquire_lock(INPUT_LOCK); - win32vars.input_chunk.pers.mouse_x = LOWORD(lParam); - win32vars.input_chunk.pers.mouse_y = HIWORD(lParam); - system_release_lock(INPUT_LOCK); - }break; - - case WM_MOUSEWHEEL: - { - system_acquire_lock(INPUT_LOCK); - i16 rotation = GET_WHEEL_DELTA_WPARAM(wParam); - if (rotation > 0){ - win32vars.input_chunk.trans.mouse_wheel = 1; - } - else{ - win32vars.input_chunk.trans.mouse_wheel = -1; - } - system_release_lock(INPUT_LOCK); - }break; - - case WM_LBUTTONDOWN: - { - system_acquire_lock(INPUT_LOCK); - win32vars.input_chunk.trans.mouse_l_press = 1; - win32vars.input_chunk.pers.mouse_l = 1; - system_release_lock(INPUT_LOCK); - }break; - - case WM_RBUTTONDOWN: - { - system_acquire_lock(INPUT_LOCK); - win32vars.input_chunk.trans.mouse_r_press = 1; - win32vars.input_chunk.pers.mouse_r = 1; - system_release_lock(INPUT_LOCK); - }break; - - case WM_LBUTTONUP: - { - system_acquire_lock(INPUT_LOCK); - win32vars.input_chunk.trans.mouse_l_release = 1; - win32vars.input_chunk.pers.mouse_l = 0; - system_release_lock(INPUT_LOCK); - }break; - - case WM_RBUTTONUP: - { - system_acquire_lock(INPUT_LOCK); - win32vars.input_chunk.trans.mouse_r_release = 1; - win32vars.input_chunk.pers.mouse_r = 0; - system_release_lock(INPUT_LOCK); - }break; - - case WM_KILLFOCUS: - case WM_SETFOCUS: - { - system_acquire_lock(INPUT_LOCK); - win32vars.input_chunk.pers.mouse_l = 0; - win32vars.input_chunk.pers.mouse_r = 0; - - b8 *control_keys = win32vars.input_chunk.pers.control_keys; - for (int i = 0; i < CONTROL_KEY_COUNT; ++i) control_keys[i] = 0; - win32vars.input_chunk.pers.controls = {}; - - system_release_lock(INPUT_LOCK); - }break; - - case WM_SIZE: - { - if (win32vars.target.handle){ - i32 new_width = LOWORD(lParam); - i32 new_height = HIWORD(lParam); - - Win32Resize(new_width, new_height); - win32vars.input_chunk.trans.redraw = 1; - } - }break; - - case WM_PAINT: - { - PAINTSTRUCT ps; - HDC hdc = BeginPaint(hwnd, &ps); - Win32RedrawScreen(hdc); - EndPaint(hwnd, &ps); - - }break; - - case WM_4coder_PAINT: - { - PAINTSTRUCT ps; - HDC hdc = BeginPaint(hwnd, &ps); - Win32RedrawScreen(hdc); - EndPaint(hwnd, &ps); - }break; - - case WM_4coder_SET_CURSOR: - { - switch (wParam){ - case APP_MOUSE_CURSOR_ARROW: - SetCursor(win32vars.cursor_arrow); break; - - case APP_MOUSE_CURSOR_IBEAM: - SetCursor(win32vars.cursor_ibeam); break; - - case APP_MOUSE_CURSOR_LEFTRIGHT: - SetCursor(win32vars.cursor_leftright); break; - - case APP_MOUSE_CURSOR_UPDOWN: - SetCursor(win32vars.cursor_updown); break; - } - }break; - - case WM_CLOSE: // NOTE(allen): I expect WM_CLOSE not WM_DESTROY - case WM_DESTROY: - { - system_acquire_lock(INPUT_LOCK); - win32vars.input_chunk.pers.keep_playing = 0; - system_release_lock(INPUT_LOCK); - }break; - - case WM_4coder_LOAD_FONT: - { - if (win32vars.fnt.part.base == 0){ - win32vars.fnt.part = Win32ScratchPartition(Mbytes(8)); - } - - Font_Load_Parameters *params = win32vars.fnt.params + lParam; - - for (b32 success = 0; success == 0;){ - - success = draw_font_load(win32vars.fnt.part.base, - win32vars.fnt.part.max, - params->font_out, - params->filename, - params->pt_size, - params->tab_width); - - if (!success){ - Win32ScratchPartitionDouble(&win32vars.fnt.part); - } - } - - system_acquire_lock(FONT_LOCK); - fnt__remove(params); - fnt__insert(&win32vars.fnt.free_param, params); - system_release_lock(FONT_LOCK); - }break; - - default: - { - result = DefWindowProc(hwnd, uMsg, wParam, lParam); - }break; - } - return result; -} - -DWORD -UpdateLoop(LPVOID param){ - for (;win32vars.input_chunk.pers.keep_playing;){ - i64 timer_start = system_time(); - - system_acquire_lock(INPUT_LOCK); - Win32_Input_Chunk input_chunk = win32vars.input_chunk; - win32vars.input_chunk.trans = {}; - system_release_lock(INPUT_LOCK); - - input_chunk.pers.control_keys[CONTROL_KEY_CAPS] = GetKeyState(VK_CAPITAL) & 0x1; - - POINT mouse_point; - if (GetCursorPos(&mouse_point) && ScreenToClient(win32vars.window_handle, &mouse_point)){ - if (mouse_point.x < 0 || mouse_point.x >= win32vars.target.width || - mouse_point.y < 0 || mouse_point.y >= win32vars.target.height){ - input_chunk.trans.out_of_window = 1; - } - } - else{ - input_chunk.trans.out_of_window = 1; - } - - win32vars.clipboard_contents = {}; - if (win32vars.clipboard_sequence != 0){ - DWORD new_number = GetClipboardSequenceNumber(); - if (new_number != win32vars.clipboard_sequence){ - win32vars.clipboard_sequence = new_number; - if (win32vars.next_clipboard_is_self){ - win32vars.next_clipboard_is_self = 0; - } - else if (IsClipboardFormatAvailable(CF_TEXT)){ - if (OpenClipboard(win32vars.window_handle)){ - HANDLE clip_data; - clip_data = GetClipboardData(CF_TEXT); - if (clip_data){ - win32vars.clipboard_contents.str = (u8*)GlobalLock(clip_data); - if (win32vars.clipboard_contents.str){ - win32vars.clipboard_contents.size = str_size((char*)win32vars.clipboard_contents.str); - GlobalUnlock(clip_data); - } - } - CloseClipboard(); - } - } - } - } - - u32 redraw = exchange_vars.thread.force_redraw; - if (redraw) exchange_vars.thread.force_redraw = 0; - redraw = redraw || input_chunk.trans.redraw; - - - Key_Input_Data input_data; - Mouse_State mouse; - Application_Step_Result result; - - input_data = input_chunk.trans.key_data; - mouse.out_of_window = input_chunk.trans.out_of_window; - - mouse.left_button = input_chunk.pers.mouse_l; - mouse.left_button_pressed = input_chunk.trans.mouse_l_press; - mouse.left_button_released = input_chunk.trans.mouse_l_release; - - mouse.right_button = input_chunk.pers.mouse_r; - mouse.right_button_pressed = input_chunk.trans.mouse_r_press; - mouse.right_button_released = input_chunk.trans.mouse_r_release; - - mouse.wheel = input_chunk.trans.mouse_wheel; - - mouse.x = input_chunk.pers.mouse_x; - mouse.y = input_chunk.pers.mouse_y; - - result.mouse_cursor_type = APP_MOUSE_CURSOR_DEFAULT; - result.redraw = redraw; - result.lctrl_lalt_is_altgr = win32vars.lctrl_lalt_is_altgr; - - win32vars.app.step(win32vars.system, - &win32vars.key_codes, - &input_data, - &mouse, - &win32vars.target, - &memory_vars, - &exchange_vars, - win32vars.clipboard_contents, - 1, win32vars.first, redraw, - &result); - - ProfileStart(OS_frame_out); - - Win32SetCursorFromUpdate(result.mouse_cursor_type); - win32vars.lctrl_lalt_is_altgr = result.lctrl_lalt_is_altgr; - - if (result.redraw) Win32RedrawFromUpdate(); - - win32vars.first = 0; - - ProfileEnd(OS_frame_out); - - ProfileStart(OS_file_process); - { - File_Slot *file; - int d = 0; - - for (file = exchange_vars.file.active.next; - file != &exchange_vars.file.active; - file = file->next){ - ++d; - - if (file->flags & FEx_Save){ - Assert((file->flags & FEx_Request) == 0); - file->flags &= (~FEx_Save); - if (system_save_file(file->filename, file->data, file->size)){ - file->flags |= FEx_Save_Complete; - } - else{ - file->flags |= FEx_Save_Failed; - } - } - - if (file->flags & FEx_Request){ - Assert((file->flags & FEx_Save) == 0); - file->flags &= (~FEx_Request); - Data sysfile = - system_load_file(file->filename); - if (sysfile.data == 0){ - file->flags |= FEx_Not_Exist; - } - else{ - file->flags |= FEx_Ready; - file->data = sysfile.data; - file->size = sysfile.size; - } - } - } - - Assert(d == exchange_vars.file.num_active); - - for (file = exchange_vars.file.free_list.next; - file != &exchange_vars.file.free_list; - file = file->next){ - if (file->data){ - system_free_memory(file->data); - } - } - - if (exchange_vars.file.free_list.next != &exchange_vars.file.free_list){ - ex__insert_range(exchange_vars.file.free_list.next, exchange_vars.file.free_list.prev, - &exchange_vars.file.available); - } - - ex__check(&exchange_vars.file); - } - ProfileEnd(OS_file_process); - - ProfileStart(frame_sleep); - i64 timer_end = system_time(); - i64 end_target = (timer_start + frame_useconds); - - system_release_lock(FRAME_LOCK); - while (timer_end < end_target){ - DWORD samount = (DWORD)((end_target - timer_end) / 1000); - if (samount > 0) Sleep(samount); - timer_end = system_time(); - } - system_acquire_lock(FRAME_LOCK); - timer_start = system_time(); - ProfileEnd(frame_sleep); - } - - return(0); -} - -#if 0 -int -WinMain(HINSTANCE hInstance, - HINSTANCE hPrevInstance, - LPSTR lpCmdLine, - int nCmdShow){ -#else -int -main(int argc, char **argv){ -#endif - HINSTANCE hInstance = GetModuleHandle(0); - - win32vars = {}; - exchange_vars = {}; - -#if FRED_INTERNAL - win32vars.internal_bubble.next = &win32vars.internal_bubble; - win32vars.internal_bubble.prev = &win32vars.internal_bubble; - win32vars.internal_bubble.flags = MEM_BUBBLE_SYS_DEBUG; -#endif - - if (!Win32LoadAppCode()){ - // TODO(allen): Failed to load app code, serious problem. - return 99; - } - - System_Functions system_; - System_Functions *system = &system_; - win32vars.system = system; - Win32LoadSystemCode(); - - LPVOID base; -#if FRED_INTERNAL - base = (LPVOID)Tbytes(1); -#else - base = (LPVOID)0; -#endif - - memory_vars.vars_memory_size = Mbytes(2); - memory_vars.vars_memory = VirtualAlloc(base, memory_vars.vars_memory_size, - MEM_COMMIT | MEM_RESERVE, - PAGE_READWRITE); - -#if FRED_INTERNAL - base = (LPVOID)Tbytes(2); -#else - base = (LPVOID)0; -#endif - memory_vars.target_memory_size = Mbytes(512); - memory_vars.target_memory = VirtualAlloc(base, memory_vars.target_memory_size, - MEM_COMMIT | MEM_RESERVE, - PAGE_READWRITE); - // - - if (!memory_vars.vars_memory){ - return 4; - } - - DWORD required = GetCurrentDirectory(0, 0); - required += 1; - required *= 4; - char *current_directory_mem = (char*)system_get_memory(required); - DWORD written = GetCurrentDirectory(required, current_directory_mem); - - String current_directory = make_string(current_directory_mem, written, required); - terminate_with_null(¤t_directory); - - Command_Line_Parameters clparams; - clparams.argv = argv; - clparams.argc = argc; - - char **files; - i32 *file_count; - - files = 0; - file_count = 0; - - i32 output_size = - win32vars.app.read_command_line(system, - &memory_vars, - current_directory, - &win32vars.settings, - &files, &file_count, - clparams); - // - - if (output_size > 0){ - // TODO(allen): crt free version - printf("%.*s", output_size, memory_vars.target_memory); - } - if (output_size != 0) return 0; - FreeConsole(); - - sysshared_filter_real_files(files, file_count); - - LARGE_INTEGER lpf; - QueryPerformanceFrequency(&lpf); - win32vars.performance_frequency = lpf.QuadPart; - QueryPerformanceCounter(&lpf); - win32vars.start_pcount = lpf.QuadPart; - - FILETIME filetime; - GetSystemTimeAsFileTime(&filetime); - win32vars.start_time = ((u64)filetime.dwHighDateTime << 32) | (filetime.dwLowDateTime); - win32vars.start_time /= 10; - - keycode_init(&win32vars.key_codes); - -#ifdef FRED_SUPER - char *custom_file_default = "4coder_custom.dll"; - char *custom_file; - if (win32vars.settings.custom_dll) custom_file = win32vars.settings.custom_dll; - else custom_file = custom_file_default; - - win32vars.custom = LoadLibraryA(custom_file); - if (!win32vars.custom && custom_file != custom_file_default){ - if (!win32vars.settings.custom_dll_is_strict){ - win32vars.custom = LoadLibraryA(custom_file_default); - } - } - - if (win32vars.custom){ - win32vars.custom_api.get_bindings = (Get_Binding_Data_Function*) - GetProcAddress(win32vars.custom, "get_bindings"); - } -#endif - - Thread_Context background[4]; - memset(background, 0, sizeof(background)); - win32vars.groups[BACKGROUND_THREADS].threads = background; - win32vars.groups[BACKGROUND_THREADS].count = ArrayCount(background); - - Thread_Memory thread_memory[ArrayCount(background)]; - win32vars.thread_memory = thread_memory; - - exchange_vars.thread.queues[BACKGROUND_THREADS].semaphore = - Win32GenHandle( - CreateSemaphore(0, 0, win32vars.groups[BACKGROUND_THREADS].count, 0) - ); - - u32 creation_flag = 0; - for (i32 i = 0; i < win32vars.groups[BACKGROUND_THREADS].count; ++i){ - Thread_Context *thread = win32vars.groups[BACKGROUND_THREADS].threads + i; - thread->id = i + 1; - - Thread_Memory *memory = win32vars.thread_memory + i; - *memory = {}; - memory->id = thread->id; - - thread->queue = &exchange_vars.thread.queues[BACKGROUND_THREADS]; - thread->handle = CreateThread(0, 0, ThreadProc, thread, creation_flag, (LPDWORD)&thread->windows_id); - } - - Assert(win32vars.locks); - for (i32 i = 0; i < LOCK_COUNT; ++i){ - win32vars.locks[i] = CreateSemaphore(0, 1, 1, 0); - } - win32vars.DEBUG_sysmem_lock = CreateSemaphore(0, 1, 1, 0); - - Win32LoadRenderCode(); - win32vars.target.max = Mbytes(1); - win32vars.target.push_buffer = (byte*)system_get_memory(win32vars.target.max); - - win32vars.cursor_ibeam = LoadCursor(NULL, IDC_IBEAM); - win32vars.cursor_arrow = LoadCursor(NULL, IDC_ARROW); - win32vars.cursor_leftright = LoadCursor(NULL, IDC_SIZEWE); - win32vars.cursor_updown = LoadCursor(NULL, IDC_SIZENS); - win32vars.prev_mouse_cursor = APP_MOUSE_CURSOR_ARROW; - - WNDCLASS window_class = {}; - window_class.style = CS_HREDRAW|CS_VREDRAW|CS_OWNDC; - window_class.lpfnWndProc = Win32Callback; - window_class.hInstance = hInstance; - window_class.lpszClassName = "4coder-win32-wndclass"; - - if (!RegisterClass(&window_class)){ - return 1; - } - - RECT window_rect = {}; - - if (win32vars.settings.set_window_size){ - window_rect.right = win32vars.settings.window_w; - window_rect.bottom = win32vars.settings.window_h; - } - else{ - window_rect.right = 800; - window_rect.bottom = 600; - } - - if (!AdjustWindowRect(&window_rect, WS_OVERLAPPEDWINDOW, false)){ - // TODO(allen): non-fatal diagnostics - } - -#define WINDOW_NAME "4coder-window" - - i32 window_x; - i32 window_y; - i32 window_style; - - if (win32vars.settings.set_window_pos){ - window_x = win32vars.settings.window_x; - window_y = win32vars.settings.window_y; - } - else{ - window_x = CW_USEDEFAULT; - window_y = CW_USEDEFAULT; - } - - window_style = WS_OVERLAPPEDWINDOW | WS_VISIBLE; - if (win32vars.settings.maximize_window){ - window_style |= WS_MAXIMIZE; - } - - HWND window_handle = {}; - window_handle = CreateWindowA( - window_class.lpszClassName, - WINDOW_NAME, window_style, - window_x, window_y, - window_rect.right - window_rect.left, - window_rect.bottom - window_rect.top, - 0, 0, hInstance, 0); - - if (window_handle == 0){ - return 2; - } - - // TODO(allen): errors? - win32vars.window_handle = window_handle; - HDC hdc = GetDC(window_handle); - win32vars.window_hdc = hdc; - - GetClientRect(window_handle, &window_rect); - - static PIXELFORMATDESCRIPTOR pfd = { - sizeof(PIXELFORMATDESCRIPTOR), - 1, - PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER, - PFD_TYPE_RGBA, - 32, - 0, 0, 0, 0, 0, 0, - 0, - 0, - 0, - 0, 0, 0, 0, - 16, - 0, - 0, - PFD_MAIN_PLANE, - 0, - 0, 0, 0 }; - - i32 pixel_format; - pixel_format = ChoosePixelFormat(hdc, &pfd); - SetPixelFormat(hdc, pixel_format, &pfd); - - win32vars.target.handle = hdc; - win32vars.target.context = wglCreateContext(hdc); - wglMakeCurrent(hdc, (HGLRC)win32vars.target.context); - - glEnable(GL_TEXTURE_2D); - glEnable(GL_SCISSOR_TEST); - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - - Win32Resize(window_rect.right - window_rect.left, window_rect.bottom - window_rect.top); - - win32vars.clipboard_sequence = GetClipboardSequenceNumber(); - - if (win32vars.clipboard_sequence == 0){ - system_post_clipboard(make_lit_string("")); - - win32vars.clipboard_sequence = GetClipboardSequenceNumber(); - win32vars.next_clipboard_is_self = 0; - - if (win32vars.clipboard_sequence == 0){ - // TODO(allen): diagnostics - } - } - - else{ - if (IsClipboardFormatAvailable(CF_TEXT)){ - if (OpenClipboard(win32vars.window_handle)){ - HANDLE clip_data; - clip_data = GetClipboardData(CF_TEXT); - if (clip_data){ - win32vars.clipboard_contents.str = (u8*)GlobalLock(clip_data); - if (win32vars.clipboard_contents.str){ - win32vars.clipboard_contents.size = str_size((char*)win32vars.clipboard_contents.str); - GlobalUnlock(clip_data); - } - } - CloseClipboard(); - } - } - } - - - File_Slot file_slots[32]; - sysshared_init_file_exchange(&exchange_vars, file_slots, ArrayCount(file_slots), 0); - - Font_Load_Parameters params[32]; - sysshared_init_font_params(&win32vars.fnt, params, ArrayCount(params)); - - win32vars.app.init(win32vars.system, &win32vars.target, - &memory_vars, &exchange_vars, &win32vars.key_codes, - win32vars.clipboard_contents, current_directory, - win32vars.custom_api); - - system_free_memory(current_directory.str); - - win32vars.input_chunk.pers.keep_playing = 1; - win32vars.first = 1; - timeBeginPeriod(1); - - win32vars.update_loop_thread = - CreateThread(0, - 0, - UpdateLoop, - 0, - CREATE_SUSPENDED, - &win32vars.update_loop_thread_id); - - system_acquire_lock(FRAME_LOCK); - - ResumeThread(win32vars.update_loop_thread); - - MSG msg; - for (;win32vars.input_chunk.pers.keep_playing && GetMessage(&msg, 0, 0, 0);){ - if (msg.message == WM_QUIT){ - system_acquire_lock(INPUT_LOCK); - win32vars.input_chunk.pers.keep_playing = 0; - system_release_lock(INPUT_LOCK); - }else{ - TranslateMessage(&msg); - DispatchMessage(&msg); - } - } - - return 0; -} - -// BOTTOM - - +/* + * Mr. 4th Dimention - Allen Webster + * + * 12.12.2014 + * + * Win32 layer for project codename "4ed" + * + */ + +// TOP + +#include "4ed_config.h" + +#include "4ed_meta.h" + +#define FCPP_FORBID_MALLOC + +#include "4cpp_types.h" +#define FCPP_STRING_IMPLEMENTATION +#include "4coder_string.h" + +#include "4ed_mem.cpp" +#include "4ed_math.cpp" + +#include "4ed_dll_reader.h" + +#include "4coder_custom.h" +#include "4ed_system.h" +#include "4ed_rendering.h" +#include "4ed.h" + +#include +#include + +#include "4ed_dll_reader.cpp" +#include "4ed_internal.h" +#include "4ed_win32_keyboard.cpp" +#include "system_shared.h" + +#define FPS 30 +#define frame_useconds (1000000 / FPS) + +#define WM_4coder_LOAD_FONT (WM_USER + 1) +#define WM_4coder_PAINT (WM_USER + 2) +#define WM_4coder_SET_CURSOR (WM_USER + 3) + +struct Thread_Context{ + u32 job_id; + b32 running; + + Work_Queue *queue; + u32 id; + u32 windows_id; + HANDLE handle; +}; + +struct Thread_Group{ + Thread_Context *threads; + i32 count; +}; + +#define UseWinDll 1 + +struct Control_Keys{ + b8 l_ctrl; + b8 r_ctrl; + b8 l_alt; + b8 r_alt; +}; + +struct Win32_Input_Chunk_Transient{ + Key_Input_Data key_data; + + b8 mouse_l_press, mouse_l_release; + b8 mouse_r_press, mouse_r_release; + b32 out_of_window; + i16 mouse_wheel; + + b32 redraw; +}; + +struct Win32_Input_Chunk_Persistent{ + i32 mouse_x, mouse_y; + b8 mouse_l, mouse_r; + + b8 keep_playing; + + Control_Keys controls; + b8 control_keys[CONTROL_KEY_COUNT]; +}; + +struct Win32_Input_Chunk{ + Win32_Input_Chunk_Transient trans; + Win32_Input_Chunk_Persistent pers; +}; + +struct Win32_Vars{ + HWND window_handle; + HDC window_hdc; + Render_Target target; + + HANDLE update_loop_thread; + DWORD update_loop_thread_id; + + Key_Codes key_codes; + Win32_Input_Chunk input_chunk; + b32 lctrl_lalt_is_altgr; + + HCURSOR cursor_ibeam; + HCURSOR cursor_arrow; + HCURSOR cursor_leftright; + HCURSOR cursor_updown; + Application_Mouse_Cursor prev_mouse_cursor; + Clipboard_Contents clipboard_contents; + b32 next_clipboard_is_self; + DWORD clipboard_sequence; + + Thread_Group groups[THREAD_GROUP_COUNT]; + HANDLE locks[LOCK_COUNT]; + HANDLE DEBUG_sysmem_lock; + + Thread_Memory *thread_memory; + + u64 performance_frequency; + u64 start_pcount; + u64 start_time; + +#if UseWinDll + HMODULE app_code; + HMODULE custom; +#else + DLL_Loaded app_dll; + DLL_Loaded custom_dll; +#endif + + Plat_Settings settings; + System_Functions *system; + App_Functions app; + Custom_API custom_api; + b32 first; + +#if FRED_INTERNAL + Sys_Bubble internal_bubble; +#endif + + Font_Load_System fnt; +}; + +globalvar Win32_Vars win32vars; +globalvar Application_Memory memory_vars; +globalvar Exchange exchange_vars; + +#if FRED_INTERNAL +internal Bubble* +INTERNAL_system_sentinel(){ + return (&win32vars.internal_bubble); +} + +internal void +INTERNAL_system_debug_message(char *message){ + OutputDebugString(message); +} + +#endif + +// TODO(allen): Transition towards using system_shared functions + +internal void* +Win32GetMemory_(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; +} + +internal +Sys_Get_Memory_Sig(system_get_memory_){ + return(Win32GetMemory_(size, line_number, file_name)); +} + +#define Win32GetMemory(size) Win32GetMemory_(size, __LINE__, __FILE__) + +internal void +Win32FreeMemory(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 Partition +Win32ScratchPartition(i32 size){ + Partition part; + void *data; + data = Win32GetMemory(size); + part = partition_open(data, size); + return(part); +} + +internal void +Win32ScratchPartitionGrow(Partition *part, i32 new_size){ + void *data; + if (new_size > part->max){ + data = Win32GetMemory(new_size); + memcpy(data, part->base, part->pos); + Win32FreeMemory(part->base); + part->base = (u8*)data; + } +} + +internal void +Win32ScratchPartitionDouble(Partition *part){ + Win32ScratchPartitionGrow(part, part->max*2); +} + +inline void +system_free_memory(void *block){ + Win32FreeMemory(block); +} + +internal Data +system_load_file(char *filename){ + Data result = {}; + HANDLE file; + file = CreateFile((char*)filename, GENERIC_READ, 0, 0, + OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); + if (!file || file == INVALID_HANDLE_VALUE){ + return result; + } + + DWORD lo, hi; + lo = GetFileSize(file, &hi); + + if (hi != 0){ + CloseHandle(file); + return result; + } + + result.size = (lo) + (((u64)hi) << 32); + result.data = (byte*)Win32GetMemory(result.size); + + if (!result.data){ + CloseHandle(file); + result = {}; + return result; + } + + DWORD read_size; + BOOL read_result = ReadFile(file, result.data, result.size, + &read_size, 0); + if (!read_result || read_size != (u32)result.size){ + CloseHandle(file); + Win32FreeMemory(result.data); + result = {}; + return result; + } + + CloseHandle(file); + return result; +} + +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); + + if (!file || file == INVALID_HANDLE_VALUE){ + return 0; + } + + BOOL write_result; + DWORD bytes_written; + write_result = WriteFile(file, data, size, &bytes_written, 0); + + CloseHandle(file); + + if (!write_result || bytes_written != (u32)size){ + return 0; + } + + return 1; +} + +internal b32 +system_file_can_be_made(char *filename){ + HANDLE file; + file = CreateFile((char*)filename, FILE_APPEND_DATA, 0, 0, + OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0); + + if (!file || file == INVALID_HANDLE_VALUE){ + return 0; + } + + CloseHandle(file); + + return 1; +} + +internal +Sys_File_Time_Stamp_Sig(system_file_time_stamp){ + u64 result; + result = 0; + + FILETIME last_write; + WIN32_FILE_ATTRIBUTE_DATA data; + if (GetFileAttributesEx((char*)filename, GetFileExInfoStandard, &data)){ + last_write = data.ftLastWriteTime; + + result = ((u64)last_write.dwHighDateTime << 32) | (last_write.dwLowDateTime); + result /= 10; + } + + return result; +} + +internal +Sys_Time_Sig(system_time){ + u64 result = 0; + LARGE_INTEGER time; + if (QueryPerformanceCounter(&time)){ + result = (u64)(time.QuadPart - win32vars.start_pcount) * 1000000 / win32vars.performance_frequency; + result += win32vars.start_time; + } + return result; +} + +internal +Sys_Set_File_List_Sig(system_set_file_list){ + if (directory.size > 0){ + char dir_space[MAX_PATH + 32]; + String dir = make_string(dir_space, 0, MAX_PATH + 32); + append(&dir, directory); + char trail_str[] = "\\*"; + append(&dir, trail_str); + + char *c_str_dir = make_c_str(dir); + + WIN32_FIND_DATA find_data; + HANDLE search; + search = FindFirstFileA(c_str_dir, &find_data); + + if (search != INVALID_HANDLE_VALUE){ + i32 count = 0; + i32 file_count = 0; + BOOL more_files = 1; + do{ + if (!match(find_data.cFileName, ".") && + !match(find_data.cFileName, "..")){ + ++file_count; + i32 size = 0; + for(;find_data.cFileName[size];++size); + count += size + 1; + } + more_files = FindNextFile(search, &find_data); + }while(more_files); + FindClose(search); + + i32 required_size = count + file_count * sizeof(File_Info); + if (file_list->block_size < required_size){ + Win32FreeMemory(file_list->block); + file_list->block = Win32GetMemory(required_size); + } + + file_list->infos = (File_Info*)file_list->block; + char *name = (char*)(file_list->infos + file_count); + if (file_list->block){ + search = FindFirstFileA(c_str_dir, &find_data); + + if (search != INVALID_HANDLE_VALUE){ + File_Info *info = file_list->infos; + more_files = 1; + do{ + if (!match(find_data.cFileName, ".") && + !match(find_data.cFileName, "..")){ + info->folder = (find_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0; + info->filename.str = name; + + i32 i = 0; + for(;find_data.cFileName[i];++i) *name++ = find_data.cFileName[i]; + info->filename.size = i; + info->filename.memory_size = info->filename.size + 1; + *name++ = 0; + ++info; + } + more_files = FindNextFile(search, &find_data); + }while(more_files); + FindClose(search); + + file_list->count = file_count; + + }else{ + Win32FreeMemory(file_list->block); + file_list->block = 0; + file_list->block_size = 0; + } + } + } + } +} + +internal +DIRECTORY_HAS_FILE_SIG(system_directory_has_file){ + char *full_filename; + char space[1024]; + HANDLE file; + b32 result; + i32 len; + + full_filename = 0; + len = str_size(filename); + if (dir.memory_size - dir.size - 1 >= len){ + full_filename = dir.str; + memcpy(dir.str + dir.size, filename, len + 1); + } + else if (dir.size + len + 1 < 1024){ + full_filename = space; + memcpy(full_filename, dir.str, dir.size); + memcpy(full_filename + dir.size, filename, len + 1); + } + + result = 0; + if (full_filename){ + file = CreateFile((char*)full_filename, GENERIC_READ, 0, 0, + OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); + if (file != INVALID_HANDLE_VALUE){ + CloseHandle(file); + result = 1; + } + dir.str[dir.size] = 0; + } + + return(result); +} + +b32 Win32DirectoryExists(char *path){ + DWORD attrib = GetFileAttributesA(path); + return (attrib != INVALID_FILE_ATTRIBUTES && + (attrib & FILE_ATTRIBUTE_DIRECTORY)); +} + +internal +DIRECTORY_CD_SIG(system_directory_cd){ + b32 result = 0; + i32 old_size; + i32 len; + + if (rel_path[0] != 0){ + if (rel_path[0] == '.' && rel_path[1] == 0){ + result = 1; + } + else if (rel_path[0] == '.' && rel_path[1] == '.' && rel_path[2] == 0){ + result = remove_last_folder(dir); + terminate_with_null(dir); + } + else{ + len = str_size(rel_path); + if (dir->size + len + 1 > dir->memory_size){ + old_size = dir->size; + append_partial(dir, rel_path); + append_partial(dir, "\\"); + if (Win32DirectoryExists(dir->str)){ + result = 1; + } + else{ + dir->size = old_size; + } + } + } + } + + return(result); +} + +internal +Sys_Post_Clipboard_Sig(system_post_clipboard){ + if (OpenClipboard(win32vars.window_handle)){ + EmptyClipboard(); + HANDLE memory_handle; + memory_handle = GlobalAlloc(GMEM_MOVEABLE, str.size+1); + if (memory_handle){ + char *dest = (char*)GlobalLock(memory_handle); + copy_fast_unsafe(dest, str); + GlobalUnlock(memory_handle); + SetClipboardData(CF_TEXT, memory_handle); + win32vars.next_clipboard_is_self = 1; + } + CloseClipboard(); + } +} + +internal +Sys_Acquire_Lock_Sig(system_acquire_lock){ + WaitForSingleObject(win32vars.locks[id], INFINITE); +} + +internal +Sys_Release_Lock_Sig(system_release_lock){ + ReleaseSemaphore(win32vars.locks[id], 1, 0); +} + +internal void +Win32RedrawFromUpdate(){ + SendMessage( + win32vars.window_handle, + WM_4coder_PAINT, + 0, 0); +} + +internal void +Win32SetCursorFromUpdate(Application_Mouse_Cursor cursor){ + SendMessage( + win32vars.window_handle, + WM_4coder_SET_CURSOR, + cursor, 0); +} + +internal void +Win32Resize(i32 width, i32 height){ + if (width > 0 && height > 0){ + glViewport(0, 0, width, height); + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glOrtho(0, width, height, 0, -1, 1); + glScissor(0, 0, width, height); + + win32vars.target.width = width; + win32vars.target.height = height; + } +} + +internal HANDLE +Win32Handle(Plat_Handle h){ + HANDLE result; + result = {}; + result = *(HANDLE*)(&h); + return(result); +} + +internal Plat_Handle +Win32GenHandle(HANDLE h){ + Assert(sizeof(Plat_Handle) >= sizeof(HANDLE)); + Plat_Handle result; + result = *(Plat_Handle*)(&h); + return(result); +} + +internal DWORD WINAPI +ThreadProc(LPVOID lpParameter){ + Thread_Context *thread = (Thread_Context*)lpParameter; + Work_Queue *queue = thread->queue; + + for (;;){ + u32 read_index = queue->read_position; + u32 write_index = queue->write_position; + + if (read_index != write_index){ + u32 next_read_index = (read_index + 1) % JOB_ID_WRAP; + u32 safe_read_index = + InterlockedCompareExchange(&queue->read_position, + next_read_index, read_index); + + if (safe_read_index == read_index){ + Full_Job_Data *full_job = queue->jobs + (safe_read_index % QUEUE_WRAP); + // NOTE(allen): This is interlocked so that it plays nice + // with the cancel job routine, which may try to cancel this job + // at the same time that we try to run it + + i32 safe_running_thread = + InterlockedCompareExchange(&full_job->running_thread, + thread->id, THREAD_NOT_ASSIGNED); + + if (safe_running_thread == THREAD_NOT_ASSIGNED){ + thread->job_id = full_job->id; + thread->running = 1; + Thread_Memory *thread_memory = 0; + + // TODO(allen): remove memory_request + if (full_job->job.memory_request != 0){ + thread_memory = win32vars.thread_memory + thread->id - 1; + if (thread_memory->size < full_job->job.memory_request){ + if (thread_memory->data){ + Win32FreeMemory(thread_memory->data); + } + i32 new_size = LargeRoundUp(full_job->job.memory_request, Kbytes(4)); + thread_memory->data = Win32GetMemory(new_size); + thread_memory->size = new_size; + } + } + full_job->job.callback(win32vars.system, thread, thread_memory, + &exchange_vars.thread, full_job->job.data); + full_job->running_thread = 0; + thread->running = 0; + } + } + } + else{ + WaitForSingleObject(Win32Handle(queue->semaphore), INFINITE); + } + } +} + +internal +Sys_Post_Job_Sig(system_post_job){ + Work_Queue *queue = exchange_vars.thread.queues + group_id; + + Assert((queue->write_position + 1) % QUEUE_WRAP != queue->read_position % QUEUE_WRAP); + + b32 success = 0; + u32 result = 0; + while (!success){ + u32 write_index = queue->write_position; + u32 next_write_index = (write_index + 1) % JOB_ID_WRAP; + u32 safe_write_index = + InterlockedCompareExchange(&queue->write_position, + next_write_index, write_index); + if (safe_write_index == write_index){ + result = write_index; + write_index = write_index % QUEUE_WRAP; + queue->jobs[write_index].job = job; + queue->jobs[write_index].running_thread = THREAD_NOT_ASSIGNED; + queue->jobs[write_index].id = result; + success = 1; + } + } + + ReleaseSemaphore(Win32Handle(queue->semaphore), 1, 0); + + return result; +} + +internal +Sys_Cancel_Job_Sig(system_cancel_job){ + Work_Queue *queue = exchange_vars.thread.queues + group_id; + Thread_Group *group = win32vars.groups + group_id; + + u32 job_index; + u32 thread_id; + Full_Job_Data *full_job; + Thread_Context *thread; + + job_index = job_id % QUEUE_WRAP; + full_job = queue->jobs + job_index; + + Assert(full_job->id == job_id); + thread_id = + InterlockedCompareExchange(&full_job->running_thread, + 0, THREAD_NOT_ASSIGNED); + + if (thread_id != THREAD_NOT_ASSIGNED){ + system_acquire_lock(CANCEL_LOCK0 + thread_id - 1); + thread = group->threads + thread_id - 1; + TerminateThread(thread->handle, 0); + u32 creation_flag = 0; + thread->handle = CreateThread(0, 0, ThreadProc, thread, creation_flag, (LPDWORD)&thread->windows_id); + system_release_lock(CANCEL_LOCK0 + thread_id - 1); + thread->running = 0; + } +} + +internal void +system_grow_thread_memory(Thread_Memory *memory){ + void *old_data; + i32 old_size, new_size; + + system_acquire_lock(CANCEL_LOCK0 + memory->id - 1); + old_data = memory->data; + old_size = memory->size; + new_size = LargeRoundUp(memory->size*2, Kbytes(4)); + memory->data = Win32GetMemory(new_size); + memory->size = new_size; + if (old_data){ + memcpy(memory->data, old_data, old_size); + Win32FreeMemory(old_data); + } + system_release_lock(CANCEL_LOCK0 + memory->id - 1); +} + +#if FRED_INTERNAL +internal void +INTERNAL_get_thread_states(Thread_Group_ID id, bool8 *running, i32 *pending){ + Work_Queue *queue = exchange_vars.thread.queues + id; + u32 write = queue->write_position; + u32 read = queue->read_position; + if (write < read) write += JOB_ID_WRAP; + *pending = (i32)(write - read); + + Thread_Group *group = win32vars.groups + id; + for (i32 i = 0; i < group->count; ++i){ + running[i] = (group->threads[i].running != 0); + } +} +#endif + +internal +Sys_CLI_Call_Sig(system_cli_call){ + char cmd[] = "c:\\windows\\system32\\cmd.exe"; + char *env_variables = 0; + char command_line[2048]; + + b32 success = 1; + String s = make_fixed_width_string(command_line); + copy(&s, make_lit_string("/C ")); + append_partial(&s, script_name); + success = terminate_with_null(&s); + + if (success){ + success = 0; + + SECURITY_ATTRIBUTES sec_attributes; + HANDLE out_read; + HANDLE out_write; + + sec_attributes = {}; + sec_attributes.nLength = sizeof(SECURITY_ATTRIBUTES); + sec_attributes.bInheritHandle = TRUE; + + if (CreatePipe(&out_read, &out_write, &sec_attributes, 0)){ + if (SetHandleInformation(out_read, HANDLE_FLAG_INHERIT, 0)){ + STARTUPINFO startup = {}; + startup.cb = sizeof(STARTUPINFO); + startup.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES; + startup.hStdError = out_write; + startup.hStdOutput = out_write; + startup.wShowWindow = SW_HIDE; + + PROCESS_INFORMATION info = {}; + + Assert(sizeof(Plat_Handle) >= sizeof(HANDLE)); + if (CreateProcess(cmd, command_line, + 0, 0, TRUE, 0, + env_variables, path, + &startup, &info)){ + success = 1; + CloseHandle(info.hThread); + *(HANDLE*)&cli_out->proc = info.hProcess; + *(HANDLE*)&cli_out->out_read = out_read; + *(HANDLE*)&cli_out->out_write = out_write; + } + else{ + CloseHandle(out_read); + CloseHandle(out_write); + *(HANDLE*)&cli_out->proc = INVALID_HANDLE_VALUE; + *(HANDLE*)&cli_out->out_read = INVALID_HANDLE_VALUE; + *(HANDLE*)&cli_out->out_write = INVALID_HANDLE_VALUE; + } + } + else{ + // TODO(allen): failed SetHandleInformation + } + } + else{ + // TODO(allen): failed CreatePipe + } + } + + return success; +} + +struct CLI_Loop_Control{ + u32 remaining_amount; +}; + +internal +Sys_CLI_Begin_Update_Sig(system_cli_begin_update){ + Assert(sizeof(cli->scratch_space) >= sizeof(CLI_Loop_Control)); + CLI_Loop_Control *loop = (CLI_Loop_Control*)cli->scratch_space; + loop->remaining_amount = 0; +} + +internal +Sys_CLI_Update_Step_Sig(system_cli_update_step){ + HANDLE handle = *(HANDLE*)&cli->out_read; + CLI_Loop_Control *loop = (CLI_Loop_Control*)cli->scratch_space; + b32 has_more = 0; + DWORD remaining = loop->remaining_amount; + u32 pos = 0; + DWORD read_amount = 0; + + for (;;){ + if (remaining == 0){ + if (!PeekNamedPipe(handle, 0, 0, 0, &remaining, 0)) break; + if (remaining == 0) break; + } + + if (remaining + pos < max){ + has_more = 1; + ReadFile(handle, dest + pos, remaining, &read_amount, 0); + TentativeAssert(remaining == read_amount); + pos += remaining; + remaining = 0; + } + else{ + has_more = 1; + ReadFile(handle, dest + pos, max - pos, &read_amount, 0); + TentativeAssert(max - pos == read_amount); + loop->remaining_amount = remaining - (max - pos); + pos = max; + break; + } + } + *amount = pos; + + return has_more; +} + +internal +Sys_CLI_End_Update_Sig(system_cli_end_update){ + b32 close_me = 0; + HANDLE proc = *(HANDLE*)&cli->proc; + DWORD result = 0; + + if (WaitForSingleObject(proc, 0) == WAIT_OBJECT_0){ + if (GetExitCodeProcess(proc, &result) == 0) + cli->exit = -1; + else + cli->exit = (i32)result; + + close_me = 1; + CloseHandle(*(HANDLE*)&cli->proc); + CloseHandle(*(HANDLE*)&cli->out_read); + CloseHandle(*(HANDLE*)&cli->out_write); + } + return close_me; +} + +internal +Sys_To_Binary_Path(system_to_binary_path){ + b32 translate_success = 0; + i32 max = out_filename->memory_size; + i32 size = GetModuleFileName(0, out_filename->str, max); + if (size > 0 && size < max-1){ + out_filename->size = size; + truncate_to_path_of_directory(out_filename); + if (append(out_filename, filename) && terminate_with_null(out_filename)){ + translate_success = 1; + } + } + return (translate_success); +} + +internal b32 +Win32LoadAppCode(){ + b32 result = 0; + App_Get_Functions *get_funcs = 0; + +#if UseWinDll + win32vars.app_code = LoadLibraryA("4ed_app.dll"); + if (win32vars.app_code){ + get_funcs = (App_Get_Functions*) + GetProcAddress(win32vars.app_code, "app_get_functions"); + } + +#else + Data file = system_load_file("4ed_app.dll"); + + if (file.data){ + i32 error; + DLL_Data dll_data; + if (dll_parse_headers(file, &dll_data, &error)){ + Data img; + img.size = dll_total_loaded_size(&dll_data); + img.data = (byte*) + VirtualAlloc((LPVOID)Tbytes(3), img.size, + MEM_COMMIT | MEM_RESERVE, + PAGE_READWRITE); + + dll_load(img, &win32vars.app_dll, file, &dll_data); + + DWORD extra_; + VirtualProtect(img.data + win32vars.app_dll.text_start, + win32vars.app_dll.text_size, + PAGE_EXECUTE_READ, + &extra_); + + get_funcs = (App_Get_Functions*) + dll_load_function(&win32vars.app_dll, "app_get_functions", 17); + } + else{ + // TODO(allen): file loading error + } + + system_free(file.data); + + DUMP((byte*)(Tbytes(3)), Kbytes(400)); + } + else{ + // TODO(allen): file loading error + } + +#endif + + if (get_funcs){ + result = 1; + win32vars.app = get_funcs(); + } + + return result; +} + +internal void +Win32LoadSystemCode(){ + win32vars.system->file_time_stamp = system_file_time_stamp; + win32vars.system->set_file_list = system_set_file_list; + + win32vars.system->directory_has_file = system_directory_has_file; + win32vars.system->directory_cd = system_directory_cd; + + 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->post_job = system_post_job; + win32vars.system->cancel_job = system_cancel_job; + 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->internal_sentinel = INTERNAL_system_sentinel; + win32vars.system->internal_get_thread_states = INTERNAL_get_thread_states; + win32vars.system->internal_debug_message = INTERNAL_system_debug_message; +} + +#include "system_shared.cpp" +#include "4ed_rendering.cpp" + +internal +Font_Load_Sig(system_draw_font_load){ + Font_Load_Parameters *params; + + system_acquire_lock(FONT_LOCK); + params = win32vars.fnt.free_param.next; + fnt__remove(params); + fnt__insert(&win32vars.fnt.used_param, params); + system_release_lock(FONT_LOCK); + + params->font_out = font_out; + params->filename = filename; + params->pt_size = pt_size; + params->tab_width = tab_width; + + SendMessage(win32vars.window_handle, + WM_4coder_LOAD_FONT, + 0, (i32)(params - win32vars.fnt.params)); + return(1); +} + +internal void +Win32LoadRenderCode(){ + win32vars.target.push_clip = draw_push_clip; + win32vars.target.pop_clip = draw_pop_clip; + win32vars.target.push_piece = draw_push_piece; + + win32vars.target.font_set.font_info_load = draw_font_info_load; + win32vars.target.font_set.font_load = system_draw_font_load; + win32vars.target.font_set.release_font = draw_release_font; +} + +internal void +Win32RedrawScreen(HDC hdc){ + system_acquire_lock(RENDER_LOCK); + launch_rendering(&win32vars.target); + system_release_lock(RENDER_LOCK); + glFlush(); + SwapBuffers(hdc); +} + +internal LRESULT +Win32Callback(HWND hwnd, UINT uMsg, + WPARAM wParam, LPARAM lParam){ + LRESULT result = {}; + switch (uMsg){ + case WM_MENUCHAR: + case WM_SYSCHAR:break; + + case WM_SYSKEYDOWN: + case WM_SYSKEYUP: + case WM_KEYDOWN: + case WM_KEYUP: + { + switch (wParam){ + case VK_CONTROL:case VK_LCONTROL:case VK_RCONTROL: + case VK_MENU:case VK_LMENU:case VK_RMENU: + case VK_SHIFT:case VK_LSHIFT:case VK_RSHIFT: + { + Control_Keys *controls = 0; + b8 *control_keys = 0; + controls = &win32vars.input_chunk.pers.controls; + control_keys = win32vars.input_chunk.pers.control_keys; + + system_acquire_lock(INPUT_LOCK); + + b8 down = ((lParam & Bit_31)?(0):(1)); + b8 is_right = ((lParam & Bit_24)?(1):(0)); + + if (wParam != 255){ + switch (wParam){ + case VK_SHIFT: + { + control_keys[CONTROL_KEY_SHIFT] = down; + }break; + + case VK_CONTROL: + { + if (is_right) controls->r_ctrl = down; + else controls->l_ctrl = down; + }break; + + case VK_MENU: + { + if (is_right) controls->r_alt = down; + else controls->l_alt = down; + }break; + } + + b8 ctrl, alt; + ctrl = (controls->r_ctrl || (controls->l_ctrl && !controls->r_alt)); + alt = (controls->l_alt || (controls->r_alt && !controls->l_ctrl)); + + if (win32vars.lctrl_lalt_is_altgr){ + if (controls->l_alt && controls->l_ctrl){ + ctrl = 0; + alt = 0; + } + } + + control_keys[CONTROL_KEY_CONTROL] = ctrl; + control_keys[CONTROL_KEY_ALT] = alt; + } + system_release_lock(INPUT_LOCK); + }break; + + default: + b8 previous_state, current_state; + previous_state = ((lParam & Bit_30)?(1):(0)); + current_state = ((lParam & Bit_31)?(0):(1)); + + if (current_state){ + u8 key = keycode_lookup((u8)wParam); + + i32 *count = 0; + Key_Event_Data *data = 0; + b8 *control_keys = 0; + i32 control_keys_size = 0; + + system_acquire_lock(INPUT_LOCK); + if (!previous_state){ + count = &win32vars.input_chunk.trans.key_data.press_count; + data = win32vars.input_chunk.trans.key_data.press; + } + else{ + count = &win32vars.input_chunk.trans.key_data.hold_count; + data = win32vars.input_chunk.trans.key_data.hold; + } + control_keys = win32vars.input_chunk.pers.control_keys; + control_keys_size = sizeof(win32vars.input_chunk.pers.control_keys); + + if (*count < KEY_INPUT_BUFFER_SIZE){ + if (!key){ + UINT vk = (UINT)wParam; + UINT scan = (UINT)((lParam >> 16) & 0x7F); + BYTE state[256]; + WORD x; + int result; + + GetKeyboardState(state); + if (control_keys[CONTROL_KEY_CONTROL] && + !control_keys[CONTROL_KEY_ALT]) + state[VK_CONTROL] = 0; + x = 0; + result = ToAscii(vk, scan, state, &x, 0); + if (result == 1 && x < 128){ + key = (u8)x; + if (key == '\r') key = '\n'; + data[*count].character = key; + + state[VK_CAPITAL] = 0; + x = 0; + result = ToAscii(vk, scan, state, &x, 0); + if (result == 1 && x < 128){ + key = (u8)x; + if (key == '\r') key = '\n'; + data[*count].character_no_caps_lock = key; + data[*count].keycode = key; + } + } + if (result != 1 || x >= 128){ + data[*count].character = 0; + data[*count].character_no_caps_lock = 0; + data[*count].keycode = 0; + } + } + else{ + data[*count].character = 0; + data[*count].character_no_caps_lock = 0; + data[*count].keycode = key; + } + memcpy(data[*count].modifiers, control_keys, control_keys_size); + ++(*count); + } + } + system_release_lock(INPUT_LOCK); + + result = DefWindowProc(hwnd, uMsg, wParam, lParam); + } + }break; + + case WM_INPUT: + + + case WM_MOUSEMOVE: + { + system_acquire_lock(INPUT_LOCK); + win32vars.input_chunk.pers.mouse_x = LOWORD(lParam); + win32vars.input_chunk.pers.mouse_y = HIWORD(lParam); + system_release_lock(INPUT_LOCK); + }break; + + case WM_MOUSEWHEEL: + { + system_acquire_lock(INPUT_LOCK); + i16 rotation = GET_WHEEL_DELTA_WPARAM(wParam); + if (rotation > 0){ + win32vars.input_chunk.trans.mouse_wheel = 1; + } + else{ + win32vars.input_chunk.trans.mouse_wheel = -1; + } + system_release_lock(INPUT_LOCK); + }break; + + case WM_LBUTTONDOWN: + { + system_acquire_lock(INPUT_LOCK); + win32vars.input_chunk.trans.mouse_l_press = 1; + win32vars.input_chunk.pers.mouse_l = 1; + system_release_lock(INPUT_LOCK); + }break; + + case WM_RBUTTONDOWN: + { + system_acquire_lock(INPUT_LOCK); + win32vars.input_chunk.trans.mouse_r_press = 1; + win32vars.input_chunk.pers.mouse_r = 1; + system_release_lock(INPUT_LOCK); + }break; + + case WM_LBUTTONUP: + { + system_acquire_lock(INPUT_LOCK); + win32vars.input_chunk.trans.mouse_l_release = 1; + win32vars.input_chunk.pers.mouse_l = 0; + system_release_lock(INPUT_LOCK); + }break; + + case WM_RBUTTONUP: + { + system_acquire_lock(INPUT_LOCK); + win32vars.input_chunk.trans.mouse_r_release = 1; + win32vars.input_chunk.pers.mouse_r = 0; + system_release_lock(INPUT_LOCK); + }break; + + case WM_KILLFOCUS: + case WM_SETFOCUS: + { + system_acquire_lock(INPUT_LOCK); + win32vars.input_chunk.pers.mouse_l = 0; + win32vars.input_chunk.pers.mouse_r = 0; + + b8 *control_keys = win32vars.input_chunk.pers.control_keys; + for (int i = 0; i < CONTROL_KEY_COUNT; ++i) control_keys[i] = 0; + win32vars.input_chunk.pers.controls = {}; + + system_release_lock(INPUT_LOCK); + }break; + + case WM_SIZE: + { + if (win32vars.target.handle){ + i32 new_width = LOWORD(lParam); + i32 new_height = HIWORD(lParam); + + Win32Resize(new_width, new_height); + win32vars.input_chunk.trans.redraw = 1; + } + }break; + + case WM_PAINT: + { + PAINTSTRUCT ps; + HDC hdc = BeginPaint(hwnd, &ps); + Win32RedrawScreen(hdc); + EndPaint(hwnd, &ps); + + }break; + + case WM_4coder_PAINT: + { + PAINTSTRUCT ps; + HDC hdc = BeginPaint(hwnd, &ps); + Win32RedrawScreen(hdc); + EndPaint(hwnd, &ps); + }break; + + case WM_4coder_SET_CURSOR: + { + switch (wParam){ + case APP_MOUSE_CURSOR_ARROW: + SetCursor(win32vars.cursor_arrow); break; + + case APP_MOUSE_CURSOR_IBEAM: + SetCursor(win32vars.cursor_ibeam); break; + + case APP_MOUSE_CURSOR_LEFTRIGHT: + SetCursor(win32vars.cursor_leftright); break; + + case APP_MOUSE_CURSOR_UPDOWN: + SetCursor(win32vars.cursor_updown); break; + } + }break; + + case WM_CLOSE: // NOTE(allen): I expect WM_CLOSE not WM_DESTROY + case WM_DESTROY: + { + system_acquire_lock(INPUT_LOCK); + win32vars.input_chunk.pers.keep_playing = 0; + system_release_lock(INPUT_LOCK); + }break; + + case WM_4coder_LOAD_FONT: + { + if (win32vars.fnt.part.base == 0){ + win32vars.fnt.part = Win32ScratchPartition(Mbytes(8)); + } + + Font_Load_Parameters *params = win32vars.fnt.params + lParam; + + for (b32 success = 0; success == 0;){ + success = draw_font_load(win32vars.fnt.part.base, + win32vars.fnt.part.max, + params->font_out, + params->filename, + params->pt_size, + params->tab_width); + + if (!success){ + Win32ScratchPartitionDouble(&win32vars.fnt.part); + } + } + + system_acquire_lock(FONT_LOCK); + fnt__remove(params); + fnt__insert(&win32vars.fnt.free_param, params); + system_release_lock(FONT_LOCK); + }break; + + default: + { + result = DefWindowProc(hwnd, uMsg, wParam, lParam); + }break; + } + return result; +} + +DWORD +UpdateLoop(LPVOID param){ + for (;win32vars.input_chunk.pers.keep_playing;){ + i64 timer_start = system_time(); + + system_acquire_lock(INPUT_LOCK); + Win32_Input_Chunk input_chunk = win32vars.input_chunk; + win32vars.input_chunk.trans = {}; + system_release_lock(INPUT_LOCK); + + input_chunk.pers.control_keys[CONTROL_KEY_CAPS] = GetKeyState(VK_CAPITAL) & 0x1; + + POINT mouse_point; + if (GetCursorPos(&mouse_point) && ScreenToClient(win32vars.window_handle, &mouse_point)){ + if (mouse_point.x < 0 || mouse_point.x >= win32vars.target.width || + mouse_point.y < 0 || mouse_point.y >= win32vars.target.height){ + input_chunk.trans.out_of_window = 1; + } + } + else{ + input_chunk.trans.out_of_window = 1; + } + + win32vars.clipboard_contents = {}; + if (win32vars.clipboard_sequence != 0){ + DWORD new_number = GetClipboardSequenceNumber(); + if (new_number != win32vars.clipboard_sequence){ + win32vars.clipboard_sequence = new_number; + if (win32vars.next_clipboard_is_self){ + win32vars.next_clipboard_is_self = 0; + } + else if (IsClipboardFormatAvailable(CF_TEXT)){ + if (OpenClipboard(win32vars.window_handle)){ + HANDLE clip_data; + clip_data = GetClipboardData(CF_TEXT); + if (clip_data){ + win32vars.clipboard_contents.str = (u8*)GlobalLock(clip_data); + if (win32vars.clipboard_contents.str){ + win32vars.clipboard_contents.size = str_size((char*)win32vars.clipboard_contents.str); + GlobalUnlock(clip_data); + } + } + CloseClipboard(); + } + } + } + } + + u32 redraw = exchange_vars.thread.force_redraw; + if (redraw) exchange_vars.thread.force_redraw = 0; + redraw = redraw || input_chunk.trans.redraw; + + + Key_Input_Data input_data; + Mouse_State mouse; + Application_Step_Result result; + + input_data = input_chunk.trans.key_data; + mouse.out_of_window = input_chunk.trans.out_of_window; + + mouse.left_button = input_chunk.pers.mouse_l; + mouse.left_button_pressed = input_chunk.trans.mouse_l_press; + mouse.left_button_released = input_chunk.trans.mouse_l_release; + + mouse.right_button = input_chunk.pers.mouse_r; + mouse.right_button_pressed = input_chunk.trans.mouse_r_press; + mouse.right_button_released = input_chunk.trans.mouse_r_release; + + mouse.wheel = input_chunk.trans.mouse_wheel; + + mouse.x = input_chunk.pers.mouse_x; + mouse.y = input_chunk.pers.mouse_y; + + result.mouse_cursor_type = APP_MOUSE_CURSOR_DEFAULT; + result.redraw = redraw; + result.lctrl_lalt_is_altgr = win32vars.lctrl_lalt_is_altgr; + + win32vars.app.step(win32vars.system, + &win32vars.key_codes, + &input_data, + &mouse, + &win32vars.target, + &memory_vars, + &exchange_vars, + win32vars.clipboard_contents, + 1, win32vars.first, redraw, + &result); + + ProfileStart(OS_frame_out); + + Win32SetCursorFromUpdate(result.mouse_cursor_type); + win32vars.lctrl_lalt_is_altgr = result.lctrl_lalt_is_altgr; + + if (result.redraw) Win32RedrawFromUpdate(); + + win32vars.first = 0; + + ProfileEnd(OS_frame_out); + + ProfileStart(OS_file_process); + { + File_Slot *file; + int d = 0; + + for (file = exchange_vars.file.active.next; + file != &exchange_vars.file.active; + file = file->next){ + ++d; + + if (file->flags & FEx_Save){ + Assert((file->flags & FEx_Request) == 0); + file->flags &= (~FEx_Save); + if (system_save_file(file->filename, file->data, file->size)){ + file->flags |= FEx_Save_Complete; + } + else{ + file->flags |= FEx_Save_Failed; + } + } + + if (file->flags & FEx_Request){ + Assert((file->flags & FEx_Save) == 0); + file->flags &= (~FEx_Request); + Data sysfile = + system_load_file(file->filename); + if (sysfile.data == 0){ + file->flags |= FEx_Not_Exist; + } + else{ + file->flags |= FEx_Ready; + file->data = sysfile.data; + file->size = sysfile.size; + } + } + } + + Assert(d == exchange_vars.file.num_active); + + for (file = exchange_vars.file.free_list.next; + file != &exchange_vars.file.free_list; + file = file->next){ + if (file->data){ + system_free_memory(file->data); + } + } + + if (exchange_vars.file.free_list.next != &exchange_vars.file.free_list){ + ex__insert_range(exchange_vars.file.free_list.next, exchange_vars.file.free_list.prev, + &exchange_vars.file.available); + } + + ex__check(&exchange_vars.file); + } + ProfileEnd(OS_file_process); + + ProfileStart(frame_sleep); + i64 timer_end = system_time(); + i64 end_target = (timer_start + frame_useconds); + + system_release_lock(FRAME_LOCK); + while (timer_end < end_target){ + DWORD samount = (DWORD)((end_target - timer_end) / 1000); + if (samount > 0) Sleep(samount); + timer_end = system_time(); + } + system_acquire_lock(FRAME_LOCK); + timer_start = system_time(); + ProfileEnd(frame_sleep); + } + + return(0); +} + +#if 0 +int +WinMain(HINSTANCE hInstance, + HINSTANCE hPrevInstance, + LPSTR lpCmdLine, + int nCmdShow){ +#else +int +main(int argc, char **argv){ +#endif + HINSTANCE hInstance = GetModuleHandle(0); + + win32vars = {}; + exchange_vars = {}; + +#if FRED_INTERNAL + win32vars.internal_bubble.next = &win32vars.internal_bubble; + win32vars.internal_bubble.prev = &win32vars.internal_bubble; + win32vars.internal_bubble.flags = MEM_BUBBLE_SYS_DEBUG; +#endif + + if (!Win32LoadAppCode()){ + // TODO(allen): Failed to load app code, serious problem. + return 99; + } + + System_Functions system_; + System_Functions *system = &system_; + win32vars.system = system; + Win32LoadSystemCode(); + + LPVOID base; +#if FRED_INTERNAL + base = (LPVOID)Tbytes(1); +#else + base = (LPVOID)0; +#endif + + memory_vars.vars_memory_size = Mbytes(2); + memory_vars.vars_memory = VirtualAlloc(base, memory_vars.vars_memory_size, + MEM_COMMIT | MEM_RESERVE, + PAGE_READWRITE); + +#if FRED_INTERNAL + base = (LPVOID)Tbytes(2); +#else + base = (LPVOID)0; +#endif + memory_vars.target_memory_size = Mbytes(512); + memory_vars.target_memory = VirtualAlloc(base, memory_vars.target_memory_size, + MEM_COMMIT | MEM_RESERVE, + PAGE_READWRITE); + // + + if (!memory_vars.vars_memory){ + return 4; + } + + DWORD required = GetCurrentDirectory(0, 0); + required += 1; + required *= 4; + char *current_directory_mem = (char*)system_get_memory(required); + DWORD written = GetCurrentDirectory(required, current_directory_mem); + + String current_directory = make_string(current_directory_mem, written, required); + terminate_with_null(¤t_directory); + + Command_Line_Parameters clparams; + clparams.argv = argv; + clparams.argc = argc; + + char **files; + i32 *file_count; + + files = 0; + file_count = 0; + + i32 output_size = + win32vars.app.read_command_line(system, + &memory_vars, + current_directory, + &win32vars.settings, + &files, &file_count, + clparams); + // + + if (output_size > 0){ + // TODO(allen): crt free version + printf("%.*s", output_size, memory_vars.target_memory); + } + if (output_size != 0) return 0; + FreeConsole(); + + sysshared_filter_real_files(files, file_count); + + LARGE_INTEGER lpf; + QueryPerformanceFrequency(&lpf); + win32vars.performance_frequency = lpf.QuadPart; + QueryPerformanceCounter(&lpf); + win32vars.start_pcount = lpf.QuadPart; + + FILETIME filetime; + GetSystemTimeAsFileTime(&filetime); + win32vars.start_time = ((u64)filetime.dwHighDateTime << 32) | (filetime.dwLowDateTime); + win32vars.start_time /= 10; + + keycode_init(&win32vars.key_codes); + +#ifdef FRED_SUPER + char *custom_file_default = "4coder_custom.dll"; + char *custom_file; + if (win32vars.settings.custom_dll) custom_file = win32vars.settings.custom_dll; + else custom_file = custom_file_default; + + win32vars.custom = LoadLibraryA(custom_file); + if (!win32vars.custom && custom_file != custom_file_default){ + if (!win32vars.settings.custom_dll_is_strict){ + win32vars.custom = LoadLibraryA(custom_file_default); + } + } + + if (win32vars.custom){ + win32vars.custom_api.get_bindings = (Get_Binding_Data_Function*) + GetProcAddress(win32vars.custom, "get_bindings"); + } +#endif + + Thread_Context background[4]; + memset(background, 0, sizeof(background)); + win32vars.groups[BACKGROUND_THREADS].threads = background; + win32vars.groups[BACKGROUND_THREADS].count = ArrayCount(background); + + Thread_Memory thread_memory[ArrayCount(background)]; + win32vars.thread_memory = thread_memory; + + exchange_vars.thread.queues[BACKGROUND_THREADS].semaphore = + Win32GenHandle( + CreateSemaphore(0, 0, win32vars.groups[BACKGROUND_THREADS].count, 0) + ); + + u32 creation_flag = 0; + for (i32 i = 0; i < win32vars.groups[BACKGROUND_THREADS].count; ++i){ + Thread_Context *thread = win32vars.groups[BACKGROUND_THREADS].threads + i; + thread->id = i + 1; + + Thread_Memory *memory = win32vars.thread_memory + i; + *memory = {}; + memory->id = thread->id; + + thread->queue = &exchange_vars.thread.queues[BACKGROUND_THREADS]; + thread->handle = CreateThread(0, 0, ThreadProc, thread, creation_flag, (LPDWORD)&thread->windows_id); + } + + Assert(win32vars.locks); + for (i32 i = 0; i < LOCK_COUNT; ++i){ + win32vars.locks[i] = CreateSemaphore(0, 1, 1, 0); + } + win32vars.DEBUG_sysmem_lock = CreateSemaphore(0, 1, 1, 0); + + Win32LoadRenderCode(); + win32vars.target.max = Mbytes(1); + win32vars.target.push_buffer = (byte*)system_get_memory(win32vars.target.max); + + win32vars.cursor_ibeam = LoadCursor(NULL, IDC_IBEAM); + win32vars.cursor_arrow = LoadCursor(NULL, IDC_ARROW); + win32vars.cursor_leftright = LoadCursor(NULL, IDC_SIZEWE); + win32vars.cursor_updown = LoadCursor(NULL, IDC_SIZENS); + win32vars.prev_mouse_cursor = APP_MOUSE_CURSOR_ARROW; + + WNDCLASS window_class = {}; + window_class.style = CS_HREDRAW|CS_VREDRAW|CS_OWNDC; + window_class.lpfnWndProc = Win32Callback; + window_class.hInstance = hInstance; + window_class.lpszClassName = "4coder-win32-wndclass"; + + if (!RegisterClass(&window_class)){ + return 1; + } + + RECT window_rect = {}; + + if (win32vars.settings.set_window_size){ + window_rect.right = win32vars.settings.window_w; + window_rect.bottom = win32vars.settings.window_h; + } + else{ + window_rect.right = 800; + window_rect.bottom = 600; + } + + if (!AdjustWindowRect(&window_rect, WS_OVERLAPPEDWINDOW, false)){ + // TODO(allen): non-fatal diagnostics + } + +#define WINDOW_NAME "4coder-window" + + i32 window_x; + i32 window_y; + i32 window_style; + + if (win32vars.settings.set_window_pos){ + window_x = win32vars.settings.window_x; + window_y = win32vars.settings.window_y; + } + else{ + window_x = CW_USEDEFAULT; + window_y = CW_USEDEFAULT; + } + + window_style = WS_OVERLAPPEDWINDOW | WS_VISIBLE; + if (win32vars.settings.maximize_window){ + window_style |= WS_MAXIMIZE; + } + + HWND window_handle = {}; + window_handle = CreateWindowA( + window_class.lpszClassName, + WINDOW_NAME, window_style, + window_x, window_y, + window_rect.right - window_rect.left, + window_rect.bottom - window_rect.top, + 0, 0, hInstance, 0); + + if (window_handle == 0){ + return 2; + } + + // TODO(allen): errors? + win32vars.window_handle = window_handle; + HDC hdc = GetDC(window_handle); + win32vars.window_hdc = hdc; + + GetClientRect(window_handle, &window_rect); + + static PIXELFORMATDESCRIPTOR pfd = { + sizeof(PIXELFORMATDESCRIPTOR), + 1, + PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER, + PFD_TYPE_RGBA, + 32, + 0, 0, 0, 0, 0, 0, + 0, + 0, + 0, + 0, 0, 0, 0, + 16, + 0, + 0, + PFD_MAIN_PLANE, + 0, + 0, 0, 0 }; + + i32 pixel_format; + pixel_format = ChoosePixelFormat(hdc, &pfd); + SetPixelFormat(hdc, pixel_format, &pfd); + + win32vars.target.handle = hdc; + win32vars.target.context = wglCreateContext(hdc); + wglMakeCurrent(hdc, (HGLRC)win32vars.target.context); + + glEnable(GL_TEXTURE_2D); + glEnable(GL_SCISSOR_TEST); + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + Win32Resize(window_rect.right - window_rect.left, window_rect.bottom - window_rect.top); + + win32vars.clipboard_sequence = GetClipboardSequenceNumber(); + + if (win32vars.clipboard_sequence == 0){ + system_post_clipboard(make_lit_string("")); + + win32vars.clipboard_sequence = GetClipboardSequenceNumber(); + win32vars.next_clipboard_is_self = 0; + + if (win32vars.clipboard_sequence == 0){ + // TODO(allen): diagnostics + } + } + + else{ + if (IsClipboardFormatAvailable(CF_TEXT)){ + if (OpenClipboard(win32vars.window_handle)){ + HANDLE clip_data; + clip_data = GetClipboardData(CF_TEXT); + if (clip_data){ + win32vars.clipboard_contents.str = (u8*)GlobalLock(clip_data); + if (win32vars.clipboard_contents.str){ + win32vars.clipboard_contents.size = str_size((char*)win32vars.clipboard_contents.str); + GlobalUnlock(clip_data); + } + } + CloseClipboard(); + } + } + } + + + File_Slot file_slots[32]; + sysshared_init_file_exchange(&exchange_vars, file_slots, ArrayCount(file_slots), 0); + + Font_Load_Parameters params[32]; + sysshared_init_font_params(&win32vars.fnt, params, ArrayCount(params)); + + win32vars.app.init(win32vars.system, &win32vars.target, + &memory_vars, &exchange_vars, &win32vars.key_codes, + win32vars.clipboard_contents, current_directory, + win32vars.custom_api); + + system_free_memory(current_directory.str); + + win32vars.input_chunk.pers.keep_playing = 1; + win32vars.first = 1; + timeBeginPeriod(1); + + win32vars.update_loop_thread = + CreateThread(0, + 0, + UpdateLoop, + 0, + CREATE_SUSPENDED, + &win32vars.update_loop_thread_id); + + system_acquire_lock(FRAME_LOCK); + + ResumeThread(win32vars.update_loop_thread); + + MSG msg; + for (;win32vars.input_chunk.pers.keep_playing && GetMessage(&msg, 0, 0, 0);){ + if (msg.message == WM_QUIT){ + system_acquire_lock(INPUT_LOCK); + win32vars.input_chunk.pers.keep_playing = 0; + system_release_lock(INPUT_LOCK); + }else{ + TranslateMessage(&msg); + DispatchMessage(&msg); + } + } + + return 0; +} + +// BOTTOM + +