4coder/code/platform_win32/win32_4ed.cpp

2109 lines
66 KiB
C++
Raw Normal View History

2016-02-20 21:36:16 +00:00
/*
* Mr. 4th Dimention - Allen Webster
*
* 12.12.2014
*
* Win32 layer for 4coder
2016-02-20 21:36:16 +00:00
*
*/
// TOP
// #define FPS 144
// #define frame_useconds (1000000 / FPS)
// #define WIN32_DX11
2020-11-24 06:27:33 +00:00
#include <stdio.h>
2019-02-24 07:22:16 +00:00
#include "4coder_base_types.h"
#include "4coder_version.h"
#include "4coder_events.h"
2016-08-30 19:30:41 +00:00
#include "4coder_table.h"
#include "4coder_types.h"
#include "4coder_default_colors.h"
#include "4coder_system_types.h"
#define STATIC_LINK_API
#include "generated/system_api.h"
#include "4ed_font_interface.h"
#define STATIC_LINK_API
#include "generated/graphics_api.h"
#define STATIC_LINK_API
#include "generated/font_api.h"
#include "4ed_font_set.h"
#include "4ed_render_target.h"
#include "4coder_search_list.h"
#include "4ed.h"
#include "generated/system_api.cpp"
#include "generated/graphics_api.cpp"
#include "generated/font_api.cpp"
#include "4coder_base_types.cpp"
#include "4coder_stringf.cpp"
#include "4coder_events.cpp"
#include "4coder_hash_functions.cpp"
#include "4coder_table.cpp"
#include "4coder_log.cpp"
#include "4coder_search_list.cpp"
2016-02-20 21:36:16 +00:00
#undef function
2019-10-02 00:25:13 +00:00
#define UNICODE
#include <Windows.h>
#define function static
#include "win32_utf8.h"
2021-05-17 06:13:27 +00:00
////////////////////////////////
global b32 log_os_enabled = false;
#define log_os(...) \
Stmnt( if (log_os_enabled){ fprintf(stdout, __VA_ARGS__); fflush(stdout); } )
//////////////////////////////
2016-06-01 16:03:45 +00:00
internal String_Const_u8 win32_get_error_string(void);
internal void win32_output_error_string(String_Const_u8 string);
//////////////////////////////
#define WM_4coder_ANIMATE (WM_USER + 0)
2016-02-20 21:36:16 +00:00
struct Control_Keys{
b8 l_ctrl;
b8 r_ctrl;
b8 l_alt;
b8 r_alt;
};
struct Win32_Input_Chunk_Transient{
Input_List event_list;
b8 mouse_l_press;
b8 mouse_l_release;
b8 mouse_r_press;
b8 mouse_r_release;
2016-02-27 07:44:17 +00:00
b8 out_of_window;
i8 mouse_wheel;
2016-03-16 16:50:26 +00:00
b8 trying_to_kill;
2016-02-20 21:36:16 +00:00
};
struct Win32_Input_Chunk_Persistent{
2019-02-25 23:42:13 +00:00
Vec2_i32 mouse;
2016-02-20 21:36:16 +00:00
Control_Keys controls;
Input_Modifier_Set_Fixed modifiers;
b8 mouse_l;
b8 mouse_r;
2016-02-20 21:36:16 +00:00
};
struct Win32_Input_Chunk{
2016-02-20 21:36:16 +00:00
Win32_Input_Chunk_Transient trans;
Win32_Input_Chunk_Persistent pers;
};
2016-02-20 21:36:16 +00:00
////////////////////////////////
#define SLASH '\\'
#define DLL "dll"
2019-04-01 06:14:31 +00:00
#include "4coder_hash_functions.cpp"
#include "4coder_system_allocator.cpp"
#include "4coder_codepoint_map.cpp"
#include "4ed_mem.cpp"
#include "4ed_font_set.cpp"
////////////////////////////////
typedef i32 Win32_Object_Kind;
enum{
Win32ObjectKind_ERROR = 0,
Win32ObjectKind_Timer = 1,
Win32ObjectKind_Thread = 2,
Win32ObjectKind_Mutex = 3,
Win32ObjectKind_CV = 4,
};
struct Win32_Object{
Node node;
Win32_Object_Kind kind;
union{
struct{
UINT_PTR id;
} timer;
struct{
HANDLE thread;
Thread_Function *proc;
void *ptr;
} thread;
CRITICAL_SECTION mutex;
CONDITION_VARIABLE cv;
};
};
2017-06-12 21:35:06 +00:00
struct Win32_Vars{
Thread_Context *tctx;
2020-03-11 23:22:37 +00:00
Arena frame_arena;
2019-10-10 20:15:47 +00:00
Input_Event *active_key_stroke;
Input_Event *active_text_input;
Win32_Input_Chunk input_chunk;
b8 lctrl_lalt_is_altgr;
b8 got_useful_event;
Key_Mode key_mode;
2020-05-01 18:19:24 +00:00
HKL kl_universal;
b8 full_screen;
b8 do_toggle;
WINDOWPLACEMENT bordered_win_pos;
2016-09-01 20:29:07 +00:00
b32 send_exit_signal;
HCURSOR cursor_ibeam;
HCURSOR cursor_arrow;
HCURSOR cursor_leftright;
HCURSOR cursor_updown;
i32 cursor_show;
i32 prev_cursor_show;
String_Const_u8 binary_path;
2019-02-14 03:53:55 +00:00
2020-02-08 00:50:35 +00:00
b8 clip_catch_all;
DWORD clipboard_sequence;
2020-02-08 00:50:35 +00:00
Plat_Handle clip_wakeup_timer;
Arena clip_post_arena;
String_Const_u8 clip_post;
2017-11-13 22:12:04 +00:00
HWND window_handle;
2019-09-28 00:49:59 +00:00
f32 screen_scale_factor;
DWORD audio_thread_id;
void *volatile audio_mix_ctx;
Audio_Mix_Sources_Function *volatile audio_mix_sources;
Audio_Mix_Destination_Function *volatile audio_mix_destination;
2021-05-17 06:13:27 +00:00
f64 usecond_per_count;
2016-02-20 21:36:16 +00:00
b32 first;
i32 running_cli;
Node free_win32_objects;
Node timer_objects;
UINT_PTR timer_counter;
CRITICAL_SECTION thread_launch_mutex;
CONDITION_VARIABLE thread_launch_cv;
b32 waiting_for_launch;
2019-10-21 02:02:58 +00:00
System_Mutex global_frame_mutex;
2019-08-16 02:54:06 +00:00
Log_Function *log_string;
2017-06-12 21:35:06 +00:00
};
2016-02-20 21:36:16 +00:00
////////////////////////////////
global Win32_Vars win32vars;
2017-07-18 23:17:40 +00:00
global Render_Target target;
2017-07-18 17:44:54 +00:00
////////////////////////////////
internal void
2021-01-17 00:14:12 +00:00
system_error_box(char *msg){
MessageBoxA(0, msg, "Error", MB_OK);
ExitProcess(1);
}
2017-07-18 23:41:28 +00:00
////////////////////////////////
internal String_Const_u8
win32_get_error_string(void){
String_Const_u8 result = {};
2017-11-10 21:13:02 +00:00
DWORD error = GetLastError();
char *str = 0;
char *str_ptr = (char*)&str;
if (FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
0, error, 0, str_ptr, 0, 0)){
result.str = (u8*)str;
result.size = strlen(str);
2017-11-10 21:13:02 +00:00
}
return(result);
}
internal void
win32_output_error_string(String_Const_u8 error_string){
system_error_box((char*)error_string.str);
2017-11-10 21:13:02 +00:00
}
////////////////////////////////
2017-07-18 17:44:54 +00:00
internal HANDLE
handle_type(Plat_Handle h){
HANDLE result;
block_copy(&result, &h, sizeof(result));
2017-07-18 17:44:54 +00:00
return(result);
}
internal Plat_Handle
handle_type(HANDLE h){
Plat_Handle result = {};
block_copy(&result, &h, sizeof(h));
return(result);
}
internal void*
handle_type_ptr(Plat_Handle h){
void *result;
block_copy(&result, &h, sizeof(result));
return(result);
}
internal Plat_Handle
handle_type_ptr(void *ptr){
Plat_Handle result = {};
block_copy(&result, &ptr, sizeof(ptr));
2017-07-18 17:44:54 +00:00
return(result);
}
////////////////////////////////
2017-07-18 21:29:39 +00:00
#include "win32_4ed_functions.cpp"
#include "win32_audio.cpp"
////////////////////////////////
internal
system_load_library_sig(){
HMODULE lib = LoadLibrary_utf8String(scratch, file_name);
b32 result = false;
if (lib != 0){
result = true;
*out = handle_type(lib);
}
return(result);
}
internal
system_release_library_sig(){
HMODULE lib = (HMODULE)handle_type(handle);
return(FreeLibrary(lib));
}
internal
system_get_proc_sig(){
HMODULE lib = (HMODULE)handle_type(handle);
return((Void_Func*)(GetProcAddress(lib, proc_name)));
}
//-
2019-02-25 23:42:13 +00:00
internal void
2019-08-13 04:19:02 +00:00
system_schedule_step(u32 code){
PostMessage(win32vars.window_handle, WM_4coder_ANIMATE, code, 0);
}
//-
// NOTE(jack): Query win32 API to get montior refresh rate.
internal u64
win32_get_frame_rate() {
u64 frame_rate = 60;
DEVMODE device_mode = { 0 };
// memset(&device_mode, 0, sizeof(DEVMODE));
device_mode.dmSize = sizeof(DEVMODE);
device_mode.dmDriverExtra = 0;
// If the Display settings can be retrieved use the device's refresh rate
if(EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &device_mode) != 0){
frame_rate = device_mode.dmDisplayFrequency;
}
return frame_rate;
}
//-
internal void
win32_toggle_fullscreen(){
HWND win = win32vars.window_handle;
DWORD style = GetWindowLongW(win, GWL_STYLE);
2017-10-31 16:52:39 +00:00
b32 is_full = ((style & WS_OVERLAPPEDWINDOW) == 0);
if (!is_full){
MONITORINFO info = {sizeof(MONITORINFO)};
if (GetWindowPlacement(win, &win32vars.bordered_win_pos) && GetMonitorInfo(MonitorFromWindow(win, MONITOR_DEFAULTTOPRIMARY), &info)){
SetWindowLongW(win, GWL_STYLE, style & ~WS_OVERLAPPEDWINDOW);
i32 x = info.rcMonitor.left;
i32 y = info.rcMonitor.top;
i32 w = info.rcMonitor.right - info.rcMonitor.left;
i32 h = info.rcMonitor.bottom - info.rcMonitor.top;
SetWindowPos(win, HWND_TOP, x, y, w, h, SWP_NOOWNERZORDER | SWP_FRAMECHANGED | SWP_SHOWWINDOW);
win32vars.full_screen = true;
}
}
else{
SetWindowLongW(win, GWL_STYLE, style | WS_OVERLAPPEDWINDOW);
SetWindowPlacement(win, &win32vars.bordered_win_pos);
SetWindowPos(win, 0, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_NOOWNERZORDER | SWP_FRAMECHANGED);
win32vars.full_screen = false;
}
}
// TODO(allen): add a "shown but auto-hides on timer" setting here.
internal
system_show_mouse_cursor_sig(){
win32vars.cursor_show = show;
}
internal
system_set_fullscreen_sig(){
// NOTE(allen): If the new value of full_screen does not match the current value,
// set toggle to true.
win32vars.do_toggle = (win32vars.full_screen != full_screen);
b32 success = true;
return(success);
}
internal
system_is_fullscreen_sig(){
// NOTE(allen): Report the fullscreen status as it would be set at the beginning of the
// next frame. That is, take into account all fullscreen toggle requests that have come in
// already this frame. Read: "full_screen XOR do_toggle"
b32 result = (win32vars.full_screen != win32vars.do_toggle);
return(result);
}
internal
system_get_keyboard_modifiers_sig(){
return(copy_modifier_set(arena, &win32vars.input_chunk.pers.modifiers));
}
internal
system_set_key_mode_sig(){
win32vars.key_mode = mode;
}
//-
// NOTE(allen): Clipboard
2016-02-27 07:44:17 +00:00
2020-02-08 00:50:35 +00:00
internal String_Const_u8
win32_read_clipboard_contents(Thread_Context *tctx, Arena *arena){
Scratch_Block scratch(tctx, arena);
2020-02-08 00:50:35 +00:00
String_Const_u8 result = {};
2021-07-14 13:29:02 +00:00
if (OpenClipboard(win32vars.window_handle)){
b32 got_result = false;
if (!got_result){
HANDLE clip_data = GetClipboardData(CF_UNICODETEXT);
if (clip_data != 0){
u16 *clip_16_ptr = (u16*)GlobalLock(clip_data);
if (clip_16_ptr != 0){
String_Const_u16 clip_16 = SCu16(clip_16_ptr);
got_result = true;
result = string_u8_from_string_u16(arena, clip_16, StringFill_NullTerminate).string;
2020-02-08 00:50:35 +00:00
}
GlobalUnlock(clip_data);
}
2021-07-14 13:29:02 +00:00
}
if (!got_result){
HANDLE clip_data = GetClipboardData(CF_TEXT);
if (clip_data != 0){
char *clip_ascii_ptr = (char*)GlobalLock(clip_data);
if (clip_ascii_ptr != 0){
String_Const_char clip_ascii = SCchar(clip_ascii_ptr);
got_result = true;
result = string_u8_from_string_char(arena, clip_ascii, StringFill_NullTerminate).string;
2020-02-08 00:50:35 +00:00
}
GlobalUnlock(clip_data);
}
}
2021-07-14 13:29:02 +00:00
CloseClipboard();
2020-02-08 00:50:35 +00:00
}
2021-07-14 13:29:02 +00:00
2020-02-08 00:50:35 +00:00
return(result);
}
2017-11-13 22:12:04 +00:00
internal void
win32_post_clipboard(Arena *scratch, char *text, i32 len){
if (OpenClipboard(win32vars.window_handle)){
if (!EmptyClipboard()){
String_Const_u8 error_string = win32_get_error_string();
win32_output_error_string(error_string);
}
2017-11-13 22:12:04 +00:00
HANDLE memory_handle = GlobalAlloc(GMEM_MOVEABLE, len + 1);
if (memory_handle){
char *dest = (char*)GlobalLock(memory_handle);
memmove(dest, text, len);
dest[len] = 0;
GlobalUnlock(memory_handle);
SetClipboardData(CF_TEXT, memory_handle);
}
CloseClipboard();
win32vars.clipboard_sequence = GetClipboardSequenceNumber();
}
2016-02-26 05:50:19 +00:00
}
2020-02-08 00:50:35 +00:00
internal
system_get_clipboard_sig(){
String_Const_u8 result = {};
DWORD new_number = GetClipboardSequenceNumber();
if (new_number != win32vars.clipboard_sequence){
result = win32_read_clipboard_contents(win32vars.tctx, arena);
if (result.str != 0){
win32vars.clipboard_sequence = new_number;
}
2020-02-08 00:50:35 +00:00
}
return(result);
}
2017-11-13 22:12:04 +00:00
internal
system_post_clipboard_sig(){
Arena *arena = &win32vars.clip_post_arena;
if (arena->base_allocator == 0){
*arena = make_arena_system();
}
else{
linalloc_clear(arena);
}
win32vars.clip_post.str = push_array(arena, u8, str.size + 1);
if (win32vars.clip_post.str != 0){
block_copy(win32vars.clip_post.str, str.str, str.size);
win32vars.clip_post.str[str.size] = 0;
win32vars.clip_post.size = str.size;
}
else{
2021-05-17 06:13:27 +00:00
log_os("Failed to allocate buffer for clipboard post (%d)\n", (i32)str.size + 1);
}
2017-11-13 22:12:04 +00:00
}
2020-02-08 00:50:35 +00:00
internal
system_set_clipboard_catch_all_sig(){
win32vars.clip_catch_all = enabled?true:false;
2016-02-26 05:50:19 +00:00
}
2020-02-08 00:50:35 +00:00
internal
system_get_clipboard_catch_all_sig(){
return(win32vars.clip_catch_all);
}
2016-02-26 05:50:19 +00:00
2016-05-29 03:12:12 +00:00
//
// Command Line Exectuion
//
2016-02-20 21:36:16 +00:00
internal
system_cli_call_sig(){
Assert(sizeof(Plat_Handle) >= sizeof(HANDLE));
2016-02-20 21:36:16 +00:00
char cmd[] = "c:\\windows\\system32\\cmd.exe";
char *env_variables = 0;
2016-02-20 21:36:16 +00:00
Temp_Memory temp = begin_temp(scratch);
String_Const_u8 s = push_u8_stringf(scratch, "/C %s", script);
b32 success = false;
*(HANDLE*)&cli_out->proc = INVALID_HANDLE_VALUE;
*(HANDLE*)&cli_out->out_read = INVALID_HANDLE_VALUE;
*(HANDLE*)&cli_out->out_write = INVALID_HANDLE_VALUE;
*(HANDLE*)&cli_out->in_read = INVALID_HANDLE_VALUE;
*(HANDLE*)&cli_out->in_write = INVALID_HANDLE_VALUE;
SECURITY_ATTRIBUTES security_atrb = {};
security_atrb.nLength = sizeof(SECURITY_ATTRIBUTES);
security_atrb.bInheritHandle = TRUE;
HANDLE out_read = INVALID_HANDLE_VALUE;
HANDLE out_write = INVALID_HANDLE_VALUE;
if (CreatePipe(&out_read, &out_write, &security_atrb, 0)){
if (SetHandleInformation(out_read, HANDLE_FLAG_INHERIT, 0)){
STARTUPINFO startup = {};
startup.cb = sizeof(STARTUPINFO);
startup.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES;
HANDLE in_read = CreateFileA("nul", GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, &security_atrb, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
startup.hStdInput = in_read;
startup.hStdOutput = out_write;
startup.hStdError = out_write;
startup.wShowWindow = SW_HIDE;
PROCESS_INFORMATION info = {};
if (CreateProcess_utf8(scratch, (u8*)cmd, s.str, 0, 0, TRUE, 0, env_variables, (u8*)path, &startup, &info)){
success = true;
CloseHandle(info.hThread);
*(HANDLE*)&cli_out->proc = info.hProcess;
*(HANDLE*)&cli_out->out_read = out_read;
*(HANDLE*)&cli_out->out_write = out_write;
++win32vars.running_cli;
2016-02-20 21:36:16 +00:00
}
else{
2016-05-10 17:36:53 +00:00
CloseHandle(out_read);
CloseHandle(out_write);
CloseHandle(in_read);
2016-02-20 21:36:16 +00:00
}
}
else{
// TODO(allen): failed SetHandleInformation
CloseHandle(out_read);
CloseHandle(out_write);
2016-02-20 21:36:16 +00:00
}
}
else{
// TODO(allen): failed CreatePipe
}
end_temp(temp);
return(success);
2016-02-20 21:36:16 +00:00
}
struct CLI_Loop_Control{
u32 remaining_amount;
};
internal
system_cli_begin_update_sig(){
2016-02-20 21:36:16 +00:00
Assert(sizeof(cli->scratch_space) >= sizeof(CLI_Loop_Control));
CLI_Loop_Control *loop = (CLI_Loop_Control*)cli->scratch_space;
loop->remaining_amount = 0;
}
internal
system_cli_update_step_sig(){
2016-02-20 21:36:16 +00:00
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;
2016-02-20 21:36:16 +00:00
for (;;){
if (remaining == 0){
if (!PeekNamedPipe(handle, 0, 0, 0, &remaining, 0)) break;
if (remaining == 0) break;
}
2016-02-20 21:36:16 +00:00
if (remaining + pos < max){
has_more = 1;
ReadFile(handle, dest + pos, remaining, &read_amount, 0);
Assert(remaining == read_amount);
2016-02-20 21:36:16 +00:00
pos += remaining;
remaining = 0;
}
else{
has_more = 1;
ReadFile(handle, dest + pos, max - pos, &read_amount, 0);
Assert(max - pos == read_amount);
2016-02-20 21:36:16 +00:00
loop->remaining_amount = remaining - (max - pos);
pos = max;
break;
}
}
*amount = pos;
return(has_more);
2016-02-20 21:36:16 +00:00
}
internal
system_cli_end_update_sig(){
2017-11-10 18:27:39 +00:00
b32 close_me = false;
2016-02-20 21:36:16 +00:00
HANDLE proc = *(HANDLE*)&cli->proc;
DWORD result = 0;
2016-02-20 21:36:16 +00:00
if (WaitForSingleObject(proc, 0) == WAIT_OBJECT_0){
if (GetExitCodeProcess(proc, &result) == 0){
2016-03-21 03:58:34 +00:00
cli->exit = -1;
}
else{
2016-03-21 03:58:34 +00:00
cli->exit = (i32)result;
}
2017-11-10 18:27:39 +00:00
close_me = true;
2016-03-21 03:58:34 +00:00
CloseHandle(*(HANDLE*)&cli->proc);
CloseHandle(*(HANDLE*)&cli->out_read);
CloseHandle(*(HANDLE*)&cli->out_write);
if (*(HANDLE*)&cli->in_read != INVALID_HANDLE_VALUE){
CloseHandle(*(HANDLE*)&cli->in_read);
}
if (*(HANDLE*)&cli->in_write != INVALID_HANDLE_VALUE){
CloseHandle(*(HANDLE*)&cli->in_write);
}
2016-05-10 17:36:53 +00:00
--win32vars.running_cli;
2016-02-20 21:36:16 +00:00
}
2017-11-10 18:27:39 +00:00
return(close_me);
2016-02-20 21:36:16 +00:00
}
function void
os_popup_error(char *title, char *message){
MessageBoxA(0, message, title, MB_OK);
ExitProcess(1);
}
#include "4ed_font_provider_freetype.h"
#include "4ed_font_provider_freetype.cpp"
#if defined( WIN32_DX11 )
2024-02-28 17:06:53 +00:00
#include "win32_dx11.cpp"
#else
#include "win32_opengl.cpp"
#endif
internal
graphics_get_texture_sig(){
return(gl__get_texture(dim, texture_kind));
}
internal
graphics_fill_texture_sig(){
return(gl__fill_texture(texture_kind, texture, p, dim, data));
}
A user reported on the handmade network discord an issue where when you change the font size (e.g. ctrl + scroll up/down) 4coder was crashing. They were using the D3D11 renderer. The crash is caused by dereferencing a invalid pointer to a texture. The D3D11 renderer as a arbitrary limit of 32 textures (there is normally no reason to have more than 2 or 3 textures in 4coder) because it needs to keep track of a few pointer in its state, while OpenGL doesn't (it just uses the id returned by `glGenTexture`). The code that recreate the texture atlas when changing the font size, never frees the previous texture, so both DirectX and OpenGL are leaking texture. So this fix just frees the previous texture after 4coder successfully creates a new one. If for some reason the new texture can't be created, we continue using the last one. This is better than crashing as we can still use 4coder, but since we can't change font size anymore the editor might be stuck with a uncomfortable font size. Unfortunately 4coder doesn't expose a way to delete texture outside the platform layer, and the font size code is not in the platform layer. So I had to expose a `free texture` function, which lead me to understand how 4coder generates API in the `generated` folder. I updated the README to keep that information somewhere since it's not clear from the get go. The basic idea is that there are a few files that you can compile as a small standalone program and run to generate the files. For the graphics api, you need to compile `4ed_graphics_api.cpp`. I took some time to also modify a little the generator so that the generated file contains the name of the file that generated them, and added a bit of indentation to make the file a bit more readable (even if we're not supposed to modify them).
2025-01-06 17:37:44 +00:00
internal
graphics_free_texture_sig(){
gl__free_texture(texid);
}
internal
font_make_face_sig(){
return(ft__font_make_face(arena, description, scale_factor));
}
2016-05-29 03:12:12 +00:00
//
// Helpers
//
2016-05-27 02:48:20 +00:00
global Key_Code keycode_lookup_table[255];
internal void
win32_keycode_init(void){
for (u32 i = 'A'; i <= 'Z'; i += 1){
keycode_lookup_table[i] = KeyCode_A + i - 'A';
}
for (u32 i = '0'; i <= '9'; i += 1){
keycode_lookup_table[i] = KeyCode_0 + i - '0';
}
keycode_lookup_table[VK_SPACE] = KeyCode_Space;
keycode_lookup_table[VK_OEM_3] = KeyCode_Tick;
keycode_lookup_table[VK_OEM_MINUS] = KeyCode_Minus;
2020-01-02 22:37:01 +00:00
keycode_lookup_table[VK_OEM_PLUS] = KeyCode_Equal;
keycode_lookup_table[VK_OEM_4] = KeyCode_LeftBracket;
keycode_lookup_table[VK_OEM_6] = KeyCode_RightBracket;
keycode_lookup_table[VK_OEM_1] = KeyCode_Semicolon;
keycode_lookup_table[VK_OEM_7] = KeyCode_Quote;
keycode_lookup_table[VK_OEM_COMMA] = KeyCode_Comma;
keycode_lookup_table[VK_OEM_PERIOD] = KeyCode_Period;
keycode_lookup_table[VK_OEM_2] = KeyCode_ForwardSlash;
keycode_lookup_table[VK_OEM_5] = KeyCode_BackwardSlash;
keycode_lookup_table[VK_TAB] = KeyCode_Tab;
keycode_lookup_table[VK_PAUSE] = KeyCode_Pause;
keycode_lookup_table[VK_ESCAPE] = KeyCode_Escape;
keycode_lookup_table[VK_UP] = KeyCode_Up;
keycode_lookup_table[VK_DOWN] = KeyCode_Down;
keycode_lookup_table[VK_LEFT] = KeyCode_Left;
keycode_lookup_table[VK_RIGHT] = KeyCode_Right;
keycode_lookup_table[VK_BACK] = KeyCode_Backspace;
keycode_lookup_table[VK_RETURN] = KeyCode_Return;
keycode_lookup_table[VK_DELETE] = KeyCode_Delete;
keycode_lookup_table[VK_INSERT] = KeyCode_Insert;
keycode_lookup_table[VK_HOME] = KeyCode_Home;
keycode_lookup_table[VK_END] = KeyCode_End;
keycode_lookup_table[VK_PRIOR] = KeyCode_PageUp;
keycode_lookup_table[VK_NEXT] = KeyCode_PageDown;
keycode_lookup_table[VK_CAPITAL] = KeyCode_CapsLock;
keycode_lookup_table[VK_NUMLOCK] = KeyCode_NumLock;
keycode_lookup_table[VK_SCROLL] = KeyCode_ScrollLock;
keycode_lookup_table[VK_APPS] = KeyCode_Menu;
keycode_lookup_table[VK_SHIFT] = KeyCode_Shift;
keycode_lookup_table[VK_LSHIFT] = KeyCode_Shift;
keycode_lookup_table[VK_RSHIFT] = KeyCode_Shift;
keycode_lookup_table[VK_CONTROL] = KeyCode_Control;
keycode_lookup_table[VK_LCONTROL] = KeyCode_Control;
keycode_lookup_table[VK_RCONTROL] = KeyCode_Control;
keycode_lookup_table[VK_MENU] = KeyCode_Alt;
keycode_lookup_table[VK_LMENU] = KeyCode_Alt;
keycode_lookup_table[VK_RMENU] = KeyCode_Alt;
keycode_lookup_table[VK_F1] = KeyCode_F1;
keycode_lookup_table[VK_F2] = KeyCode_F2;
keycode_lookup_table[VK_F3] = KeyCode_F3;
keycode_lookup_table[VK_F4] = KeyCode_F4;
keycode_lookup_table[VK_F5] = KeyCode_F5;
keycode_lookup_table[VK_F6] = KeyCode_F6;
keycode_lookup_table[VK_F7] = KeyCode_F7;
keycode_lookup_table[VK_F8] = KeyCode_F8;
keycode_lookup_table[VK_F9] = KeyCode_F9;
keycode_lookup_table[VK_F10] = KeyCode_F10;
keycode_lookup_table[VK_F11] = KeyCode_F11;
keycode_lookup_table[VK_F12] = KeyCode_F12;
keycode_lookup_table[VK_F13] = KeyCode_F13;
keycode_lookup_table[VK_F14] = KeyCode_F14;
keycode_lookup_table[VK_F15] = KeyCode_F15;
keycode_lookup_table[VK_F16] = KeyCode_F16;
keycode_lookup_table[VK_F17] = KeyCode_F17;
keycode_lookup_table[VK_F18] = KeyCode_F18;
keycode_lookup_table[VK_F19] = KeyCode_F19;
keycode_lookup_table[VK_F20] = KeyCode_F20;
keycode_lookup_table[VK_F21] = KeyCode_F21;
keycode_lookup_table[VK_F22] = KeyCode_F22;
keycode_lookup_table[VK_F23] = KeyCode_F23;
keycode_lookup_table[VK_F24] = KeyCode_F24;
keycode_lookup_table[VK_NUMPAD0] = KeyCode_NumPad0;
keycode_lookup_table[VK_NUMPAD1] = KeyCode_NumPad1;
keycode_lookup_table[VK_NUMPAD2] = KeyCode_NumPad2;
keycode_lookup_table[VK_NUMPAD3] = KeyCode_NumPad3;
keycode_lookup_table[VK_NUMPAD4] = KeyCode_NumPad4;
keycode_lookup_table[VK_NUMPAD5] = KeyCode_NumPad5;
keycode_lookup_table[VK_NUMPAD6] = KeyCode_NumPad6;
keycode_lookup_table[VK_NUMPAD7] = KeyCode_NumPad7;
keycode_lookup_table[VK_NUMPAD8] = KeyCode_NumPad8;
keycode_lookup_table[VK_NUMPAD9] = KeyCode_NumPad9;
for (i32 i = 0; i < 30; i += 1){
keycode_lookup_table[0xDF + i] = KeyCode_Ex0 + i;
}
}
2020-05-09 22:07:31 +00:00
internal b32
keycode_physical_translation_is_wrong(u64 vk){
2020-05-09 22:07:31 +00:00
b32 result = false;
switch (vk){
case VK_UP: case VK_DOWN: case VK_LEFT: case VK_RIGHT:
case VK_DELETE:
case VK_INSERT:
case VK_HOME:
case VK_END:
case VK_PRIOR:
case VK_NEXT:
case VK_NUMPAD0:
case VK_NUMPAD1:
case VK_NUMPAD2:
case VK_NUMPAD3:
case VK_NUMPAD4:
case VK_NUMPAD5:
case VK_NUMPAD6:
case VK_NUMPAD7:
case VK_NUMPAD8:
case VK_NUMPAD9:
case VK_MULTIPLY:
case VK_ADD :
case VK_SUBTRACT:
case VK_DECIMAL :
case VK_DIVIDE :
{
result = true;
}break;
}
return(result);
}
2016-05-29 03:12:12 +00:00
internal void
win32_resize(i32 width, i32 height){
2016-05-29 03:12:12 +00:00
if (width > 0 && height > 0){
2017-07-18 23:17:40 +00:00
target.width = width;
target.height = height;
#if defined( WIN32_DX11 )
HRESULT hr = S_OK;
ID3D11Texture2D* frame_buffer = 0;
do {
if ( g_dx11.initialized ) {
if ( g_dx11.render_target_view ) {
g_dx11.render_target_view->Release( );
g_dx11.render_target_view = 0;
}
hr = g_dx11.swap_chain->ResizeBuffers( 0, 0, 0, DXGI_FORMAT_UNKNOWN, 0 );
if ( FAILED( hr ) ) {
log_os( "Failed to resize the swap chain buffers.\n" );
break;
}
hr = g_dx11.swap_chain->GetBuffer( 0, __uuidof( ID3D11Texture2D ), ( void** ) &frame_buffer );
if ( FAILED( hr ) ) {
log_os( "Failled to get the swap chain back buffer.\n" );
break;
}
D3D11_RENDER_TARGET_VIEW_DESC render_target_view_desc = { 0 };
// NOTE(simon, 28/02/24): 4coder checks for sRGB support but never actually enables
// it in the OpenGL version (never calls glEnable( GL_FRAMEBUFFER_SRGB ) ).
// Note that enabling it would require to convert collors
// passed to the shader to linear (when using sRBG back buffer, the shader values
// must be linear values). This would be more problematic than just passing linear
// values as the blending wouldn't produce the same result as with sRGB off.
// render_target_view_desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM_SRGB;
render_target_view_desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
render_target_view_desc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D;
hr = g_dx11.device->CreateRenderTargetView( ( ID3D11Resource* ) frame_buffer, &render_target_view_desc, &g_dx11.render_target_view );
if ( FAILED( hr ) ) {
log_os( "Failed to create a render target view.\n" );
break;
}
}
} while ( 0 );
if ( frame_buffer ) {
frame_buffer->Release( );
frame_buffer = 0;
}
if ( FAILED( hr ) ) {
if ( g_dx11.render_target_view ) {
g_dx11.render_target_view->Release( );
g_dx11.render_target_view = 0;
}
// NOTE(simon, 28/02/24): Failing here means no rendering possible, so we exit.
exit( 1 );
}
#endif
2016-05-29 03:12:12 +00:00
}
}
internal void
Win32SetCursorFromUpdate(Application_Mouse_Cursor cursor){
switch (cursor){
case APP_MOUSE_CURSOR_ARROW:
{
SetCursor(win32vars.cursor_arrow);
}break;
2016-05-29 03:12:12 +00:00
case APP_MOUSE_CURSOR_IBEAM:
{
SetCursor(win32vars.cursor_ibeam);
}break;
2016-05-29 03:12:12 +00:00
case APP_MOUSE_CURSOR_LEFTRIGHT:
{
SetCursor(win32vars.cursor_leftright);
}break;
2016-05-29 03:12:12 +00:00
case APP_MOUSE_CURSOR_UPDOWN:
{
SetCursor(win32vars.cursor_updown);
}break;
2016-05-29 03:12:12 +00:00
}
}
internal Win32_Object*
win32_alloc_object(Win32_Object_Kind kind){
Win32_Object *result = 0;
if (win32vars.free_win32_objects.next != &win32vars.free_win32_objects){
result = CastFromMember(Win32_Object, node, win32vars.free_win32_objects.next);
}
if (result == 0){
i32 count = 512;
Win32_Object *objects = (Win32_Object*)system_memory_allocate(count*sizeof(Win32_Object), file_name_line_number_lit_u8);
objects[0].node.prev = &win32vars.free_win32_objects;
win32vars.free_win32_objects.next = &objects[0].node;
for (i32 i = 1; i < count; i += 1){
objects[i - 1].node.next = &objects[i].node;
objects[i].node.prev = &objects[i - 1].node;
}
objects[count - 1].node.next = &win32vars.free_win32_objects;
win32vars.free_win32_objects.prev = &objects[count - 1].node;
result = CastFromMember(Win32_Object, node, win32vars.free_win32_objects.next);
}
Assert(result != 0);
dll_remove(&result->node);
block_zero_struct(result);
result->kind = kind;
return(result);
}
internal void
win32_free_object(Win32_Object *object){
if (object->node.next != 0){
dll_remove(&object->node);
}
dll_insert(&win32vars.free_win32_objects, &object->node);
}
//-
internal
system_now_time_sig(){
u64 result = 0;
LARGE_INTEGER t;
if (QueryPerformanceCounter(&t)){
2021-05-17 06:13:27 +00:00
result = (u64)(t.QuadPart*win32vars.usecond_per_count);
}
return(result);
}
internal void
date_time_from_win32_system_time(Date_Time *out, SYSTEMTIME *in){
out->year = in->wYear;
out->mon = (u8)(in->wMonth - 1);
out->day = (u8)(in->wDay - 1);
out->hour = (u8)(in->wHour);
out->min = (u8)(in->wMinute);
out->sec = (u8)(in->wSecond);
out->msec = in->wMilliseconds;
}
internal void
win32_system_time_from_date_time(SYSTEMTIME *out, Date_Time *in){
out->wYear = (WORD)(in->year);
out->wMonth = in->mon + 1;
out->wDay = in->day + 1;
out->wHour = in->hour;
out->wMinute = in->min;
out->wSecond = in->sec;
out->wMilliseconds = in->msec;
}
internal
system_now_date_time_universal_sig(){
SYSTEMTIME systime = {};
GetSystemTime(&systime);
Date_Time result = {};
date_time_from_win32_system_time(&result, &systime);
return(result);
}
internal
system_local_date_time_from_universal_sig(){
SYSTEMTIME systime = {};
win32_system_time_from_date_time(&systime, date_time);
FILETIME ftime = {};
SystemTimeToFileTime(&systime, &ftime);
FILETIME ftime_local = {};
FileTimeToLocalFileTime(&ftime, &ftime_local);
FileTimeToSystemTime(&ftime_local, &systime);
Date_Time result = {};
date_time_from_win32_system_time(&result, &systime);
return(result);
}
internal
system_universal_date_time_from_local_sig(){
SYSTEMTIME systime = {};
win32_system_time_from_date_time(&systime, date_time);
FILETIME ftime = {};
SystemTimeToFileTime(&systime, &ftime);
FILETIME ftime_local = {};
LocalFileTimeToFileTime(&ftime, &ftime_local);
FileTimeToSystemTime(&ftime_local, &systime);
Date_Time result = {};
date_time_from_win32_system_time(&result, &systime);
return(result);
}
internal
system_wake_up_timer_create_sig(){
Win32_Object *object = win32_alloc_object(Win32ObjectKind_Timer);
dll_insert(&win32vars.timer_objects, &object->node);
object->timer.id = ++win32vars.timer_counter;
return(handle_type(object));
}
internal
system_wake_up_timer_release_sig(){
Win32_Object *object = (Win32_Object*)handle_type_ptr(handle);
if (object->kind == Win32ObjectKind_Timer){
KillTimer(win32vars.window_handle, object->timer.id);
win32_free_object(object);
}
}
internal
system_wake_up_timer_set_sig(){
Win32_Object *object = (Win32_Object*)handle_type_ptr(handle);
if (object->kind == Win32ObjectKind_Timer){
object->timer.id = SetTimer(win32vars.window_handle, object->timer.id, time_milliseconds, 0);
}
}
2019-08-13 04:19:02 +00:00
internal
system_signal_step_sig(){
2019-08-13 04:19:02 +00:00
system_schedule_step(code);
}
internal
system_sleep_sig(){
2019-08-13 04:19:02 +00:00
u32 milliseconds = (u32)(microseconds/Thousand(1));
Sleep(milliseconds);
}
//-
internal DWORD CALL_CONVENTION
win32_thread_wrapper(void *ptr){
Win32_Object *object = (Win32_Object*)ptr;
Thread_Function *proc = object->thread.proc;
void *object_ptr = object->thread.ptr;
EnterCriticalSection(&win32vars.thread_launch_mutex);
win32vars.waiting_for_launch = false;
WakeConditionVariable(&win32vars.thread_launch_cv);
LeaveCriticalSection(&win32vars.thread_launch_mutex);
proc(object_ptr);
return(0);
}
internal
system_thread_launch_sig(){
Win32_Object *object = win32_alloc_object(Win32ObjectKind_Thread);
object->thread.proc = proc;
object->thread.ptr = ptr;
EnterCriticalSection(&win32vars.thread_launch_mutex);
win32vars.waiting_for_launch = true;
object->thread.thread = CreateThread(0, 0, win32_thread_wrapper, object, 0, 0);
for (;win32vars.waiting_for_launch;){
SleepConditionVariableCS(&win32vars.thread_launch_cv, &win32vars.thread_launch_mutex, INFINITE);
}
LeaveCriticalSection(&win32vars.thread_launch_mutex);
return(handle_type(object));
}
internal
system_thread_join_sig(){
Win32_Object *object = (Win32_Object*)handle_type_ptr(thread);
if (object->kind == Win32ObjectKind_Thread){
WaitForSingleObject(object->thread.thread, INFINITE);
}
}
internal
system_thread_free_sig(){
Win32_Object *object = (Win32_Object*)handle_type_ptr(thread);
if (object->kind == Win32ObjectKind_Thread){
CloseHandle(object->thread.thread);
win32_free_object(object);
}
}
2019-08-16 02:54:06 +00:00
internal
system_thread_get_id_sig(){
2019-08-16 02:54:06 +00:00
DWORD result = GetCurrentThreadId();
return((i32)result);
}
internal
system_mutex_make_sig(){
Win32_Object *object = win32_alloc_object(Win32ObjectKind_Mutex);
InitializeCriticalSection(&object->mutex);
return(handle_type(object));
}
internal
system_mutex_acquire_sig(){
Win32_Object *object = (Win32_Object*)handle_type_ptr(mutex);
if (object->kind == Win32ObjectKind_Mutex){
EnterCriticalSection(&object->mutex);
}
}
internal
system_mutex_release_sig(){
Win32_Object *object = (Win32_Object*)handle_type_ptr(mutex);
if (object->kind == Win32ObjectKind_Mutex){
LeaveCriticalSection(&object->mutex);
}
}
global i32 global_frame_mutex_state_ticker = 0;
2019-10-21 02:02:58 +00:00
internal
system_acquire_global_frame_mutex_sig(){
if (tctx->kind == ThreadKind_AsyncTasks ||
tctx->kind == ThreadKind_Main){
2019-10-21 02:02:58 +00:00
system_mutex_acquire(win32vars.global_frame_mutex);
Assert(global_frame_mutex_state_ticker == 0);
global_frame_mutex_state_ticker = 1;
2019-10-21 02:02:58 +00:00
}
}
internal
system_release_global_frame_mutex_sig(){
if (tctx->kind == ThreadKind_AsyncTasks ||
tctx->kind == ThreadKind_Main){
Assert(global_frame_mutex_state_ticker == 1);
global_frame_mutex_state_ticker = 0;
2019-10-21 02:02:58 +00:00
system_mutex_release(win32vars.global_frame_mutex);
}
}
internal
system_mutex_free_sig(){
Win32_Object *object = (Win32_Object*)handle_type_ptr(mutex);
if (object->kind == Win32ObjectKind_Mutex){
DeleteCriticalSection(&object->mutex);
win32_free_object(object);
}
}
internal
system_condition_variable_make_sig(){
Win32_Object *object = win32_alloc_object(Win32ObjectKind_CV);
InitializeConditionVariable(&object->cv);
return(handle_type(object));
}
internal
system_condition_variable_wait_sig(){
Win32_Object *object_cv = (Win32_Object*)handle_type_ptr(cv);
Win32_Object *object_mutex = (Win32_Object*)handle_type_ptr(mutex);
if (object_cv->kind == Win32ObjectKind_CV &&
object_mutex->kind == Win32ObjectKind_Mutex){
SleepConditionVariableCS(&object_cv->cv, &object_mutex->mutex, INFINITE);
}
}
internal
system_condition_variable_signal_sig(){
Win32_Object *object = (Win32_Object*)handle_type_ptr(cv);
if (object->kind == Win32ObjectKind_CV){
WakeConditionVariable(&object->cv);
}
}
internal
system_condition_variable_free_sig(){
Win32_Object *object = (Win32_Object*)handle_type_ptr(cv);
if (object->kind == Win32ObjectKind_CV){
win32_free_object(object);
}
}
//-
internal LRESULT CALL_CONVENTION
win32_proc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam){
2016-06-13 11:50:28 +00:00
LRESULT result = 0;
Scratch_Block scratch(win32vars.tctx);
2016-02-20 21:36:16 +00:00
switch (uMsg){
2019-10-30 23:27:37 +00:00
case WM_MENUCHAR:
{
result = (MNC_CLOSE << 16);
}break;
2016-03-21 03:58:34 +00:00
case WM_SYSKEYDOWN:
case WM_SYSKEYUP:
case WM_KEYDOWN:
case WM_KEYUP:
2016-02-20 21:36:16 +00:00
{
b8 release = HasFlag(lParam, bit_32);
b8 down = !release;
b8 is_right = HasFlag(lParam, bit_25);
u64 vk = wParam;
2020-05-09 22:07:31 +00:00
if (win32vars.key_mode == KeyMode_Physical &&
!keycode_physical_translation_is_wrong(vk)){
UINT scan_code = ((lParam >> 16) & bitmask_8);
vk = MapVirtualKeyEx(scan_code, MAPVK_VSC_TO_VK_EX, win32vars.kl_universal);
}
2020-05-01 18:19:24 +00:00
Input_Modifier_Set_Fixed *mods = &win32vars.input_chunk.pers.modifiers;
2019-10-12 03:41:30 +00:00
Control_Keys *controls = &win32vars.input_chunk.pers.controls;
2020-05-01 18:19:24 +00:00
switch (vk){
2016-03-21 03:58:34 +00:00
case VK_CONTROL:case VK_LCONTROL:case VK_RCONTROL:
case VK_MENU:case VK_LMENU:case VK_RMENU:
2016-02-20 21:36:16 +00:00
{
2020-05-01 19:35:43 +00:00
switch (vk){
case VK_CONTROL:case VK_LCONTROL:case VK_RCONTROL:
{
if (is_right){
controls->r_ctrl = down;
}
else{
controls->l_ctrl = down;
}
}break;
case VK_MENU:case VK_LMENU:case VK_RMENU:
{
if (is_right){
controls->r_alt = down;
}
else{
controls->l_alt = down;
}
}break;
2016-03-21 03:58:34 +00:00
}
}break;
}
2019-10-12 03:41:30 +00:00
b8 ctrl = (controls->r_ctrl || (controls->l_ctrl && !controls->r_alt));
b8 alt = (controls->l_alt || (controls->r_alt && !controls->l_ctrl));
if (win32vars.lctrl_lalt_is_altgr && controls->l_alt && controls->l_ctrl){
ctrl = false;
alt = false;
}
set_modifier(mods, KeyCode_Control, ctrl);
set_modifier(mods, KeyCode_Alt, alt);
{
b8 shift = ((GetKeyState(VK_SHIFT) & bit_16) != 0);
set_modifier(mods, KeyCode_Shift, shift);
}
2020-05-01 18:19:24 +00:00
Key_Code key = keycode_lookup_table[(u8)vk];
if (down){
if (key != 0){
add_modifier(mods, key);
2020-03-11 23:22:37 +00:00
Input_Event *event = push_input_event(&win32vars.frame_arena, &win32vars.input_chunk.trans.event_list);
2019-10-10 20:15:47 +00:00
event->kind = InputEventKind_KeyStroke;
event->key.code = key;
2020-03-11 23:22:37 +00:00
event->key.modifiers = copy_modifier_set(&win32vars.frame_arena, mods);
2019-10-10 20:15:47 +00:00
win32vars.active_key_stroke = event;
win32vars.got_useful_event = true;
}
}
2019-10-10 20:15:47 +00:00
else{
win32vars.active_key_stroke = 0;
win32vars.active_text_input = 0;
win32vars.got_useful_event = true;
if (key != 0){
2020-03-11 23:22:37 +00:00
Input_Event *event = push_input_event(&win32vars.frame_arena, &win32vars.input_chunk.trans.event_list);
event->kind = InputEventKind_KeyRelease;
event->key.code = key;
2020-03-11 23:22:37 +00:00
event->key.modifiers = copy_modifier_set(&win32vars.frame_arena, mods);
remove_modifier(mods, key);
}
2019-10-10 20:15:47 +00:00
}
2016-03-21 03:58:34 +00:00
}break;
2019-10-10 20:15:47 +00:00
case WM_CHAR:
{
2019-10-10 20:15:47 +00:00
u16 c = wParam & bitmask_16;
if (c == '\r'){
c = '\n';
}
2019-10-10 20:15:47 +00:00
if (c > 127 || (' ' <= c && c <= '~') || c == '\t' || c == '\n'){
String_Const_u16 str_16 = SCu16(&c, 1);
2020-03-11 23:22:37 +00:00
String_Const_u8 str_8 = string_u8_from_string_u16(&win32vars.frame_arena, str_16).string;
Input_Event *event = push_input_event(&win32vars.frame_arena, &win32vars.input_chunk.trans.event_list);
2019-10-10 20:15:47 +00:00
event->kind = InputEventKind_TextInsert;
event->text.string = str_8;
event->text.next_text = 0;
event->text.blocked = false;
if (win32vars.active_text_input != 0){
win32vars.active_text_input->text.next_text = event;
}
else if (win32vars.active_key_stroke != 0){
win32vars.active_key_stroke->key.first_dependent_text = event;
}
win32vars.active_text_input = event;
win32vars.got_useful_event = true;
}
2019-10-10 20:15:47 +00:00
}break;
case WM_DEADCHAR:
{
if (win32vars.active_key_stroke != 0){
AddFlag(win32vars.active_key_stroke->key.flags, KeyFlag_IsDeadKey);
}
}break;
2019-10-10 20:15:47 +00:00
case WM_UNICHAR:
{
if (wParam == UNICODE_NOCHAR){
result = true;
}
else{
u32 c = (u32)wParam;
if (c == '\r'){
c= '\n';
}
if (c > 127 || (' ' <= c && c <= '~') || c == '\t' || c == '\n'){
String_Const_u32 str_32 = SCu32(&c, 1);
2020-03-11 23:22:37 +00:00
String_Const_u8 str_8 = string_u8_from_string_u32(&win32vars.frame_arena, str_32).string;
2019-10-10 20:15:47 +00:00
Input_Event event = {};
event.kind = InputEventKind_TextInsert;
event.text.string = str_8;
2020-03-11 23:22:37 +00:00
push_input_event(&win32vars.frame_arena, &win32vars.input_chunk.trans.event_list, &event);
2019-10-10 20:15:47 +00:00
win32vars.got_useful_event = true;
}
}
}break;
2016-03-21 03:58:34 +00:00
case WM_MOUSEMOVE:
{
2019-02-25 23:42:13 +00:00
Vec2_i32 new_m = V2i32(LOWORD(lParam), HIWORD(lParam));
if (new_m != win32vars.input_chunk.pers.mouse){
win32vars.input_chunk.pers.mouse = new_m;
win32vars.got_useful_event = true;
2016-05-04 23:21:30 +00:00
}
2016-03-21 03:58:34 +00:00
}break;
2016-03-21 03:58:34 +00:00
case WM_MOUSEWHEEL:
{
win32vars.got_useful_event = true;
i32 rotation = GET_WHEEL_DELTA_WPARAM(wParam);
2016-03-21 03:58:34 +00:00
if (rotation > 0){
2017-11-11 01:21:50 +00:00
win32vars.input_chunk.trans.mouse_wheel = -100;
2016-03-21 03:58:34 +00:00
}
else{
2017-11-11 01:21:50 +00:00
win32vars.input_chunk.trans.mouse_wheel = 100;
2016-03-21 03:58:34 +00:00
}
}break;
2016-03-21 03:58:34 +00:00
case WM_LBUTTONDOWN:
{
2020-05-01 19:35:43 +00:00
SetCapture(hwnd);
win32vars.got_useful_event = true;
win32vars.input_chunk.trans.mouse_l_press = true;
win32vars.input_chunk.pers.mouse_l = true;
2016-03-21 03:58:34 +00:00
}break;
2016-03-21 03:58:34 +00:00
case WM_RBUTTONDOWN:
{
2020-05-01 19:35:43 +00:00
SetCapture(hwnd);
win32vars.got_useful_event = true;
win32vars.input_chunk.trans.mouse_r_press = true;
win32vars.input_chunk.pers.mouse_r = true;
2016-03-21 03:58:34 +00:00
}break;
2016-03-21 03:58:34 +00:00
case WM_LBUTTONUP:
{
2020-05-01 19:35:43 +00:00
ReleaseCapture();
win32vars.got_useful_event = true;
win32vars.input_chunk.trans.mouse_l_release = true;
win32vars.input_chunk.pers.mouse_l = false;
2016-03-21 03:58:34 +00:00
}break;
2016-03-21 03:58:34 +00:00
case WM_RBUTTONUP:
{
2020-05-01 19:35:43 +00:00
ReleaseCapture();
win32vars.got_useful_event = true;
win32vars.input_chunk.trans.mouse_r_release = true;
win32vars.input_chunk.pers.mouse_r = false;
2016-03-21 03:58:34 +00:00
}break;
2016-03-21 03:58:34 +00:00
case WM_KILLFOCUS:
case WM_SETFOCUS:
{
2020-05-01 19:35:43 +00:00
ReleaseCapture();
win32vars.got_useful_event = true;
win32vars.input_chunk.pers.mouse_l = false;
win32vars.input_chunk.pers.mouse_r = false;
block_zero_struct(&win32vars.input_chunk.pers.controls);
block_zero_struct(&win32vars.input_chunk.pers.modifiers);
2019-10-10 20:15:47 +00:00
win32vars.active_key_stroke = 0;
win32vars.active_text_input = 0;
2016-03-21 03:58:34 +00:00
}break;
2016-03-21 03:58:34 +00:00
case WM_SIZE:
{
win32vars.got_useful_event = true;
i32 new_width = LOWORD(lParam);
i32 new_height = HIWORD(lParam);
win32_resize(new_width, new_height);
2016-03-21 03:58:34 +00:00
}break;
case WM_DISPLAYCHANGE:
{
win32vars.got_useful_event = true;
LONG_PTR style = GetWindowLongPtr(hwnd, GWL_STYLE);
if (!(style & WS_OVERLAPPEDWINDOW)){
MONITORINFO monitor_info = {sizeof(MONITORINFO)};
if(GetMonitorInfo(MonitorFromWindow(hwnd, MONITOR_DEFAULTTOPRIMARY), &monitor_info))
{
SetWindowPos(hwnd, HWND_TOP,
monitor_info.rcMonitor.left, monitor_info.rcMonitor.top,
monitor_info.rcMonitor.right - monitor_info.rcMonitor.left,
monitor_info.rcMonitor.bottom - monitor_info.rcMonitor.top,
SWP_NOOWNERZORDER | SWP_FRAMECHANGED);
}
}
}break;
2016-03-21 03:58:34 +00:00
case WM_PAINT:
{
win32vars.got_useful_event = true;
2016-03-21 03:58:34 +00:00
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hwnd, &ps);
2017-11-10 18:27:39 +00:00
// NOTE(allen): Do nothing?
2016-03-21 03:58:34 +00:00
EndPaint(hwnd, &ps);
}break;
case WM_CLIPBOARDUPDATE:
{
2020-02-08 00:50:35 +00:00
if (win32vars.clip_catch_all){
win32vars.got_useful_event = true;
LogEventLit(win32vars.log_string(M), scratch, 0, 0, system_thread_get_id(),
"new clipboard contents");
}
}break;
2016-05-27 17:11:38 +00:00
case WM_CLOSE:
2016-03-21 03:58:34 +00:00
case WM_DESTROY:
{
win32vars.got_useful_event = true;
2017-11-07 21:35:26 +00:00
win32vars.input_chunk.trans.trying_to_kill = true;
2016-03-21 03:58:34 +00:00
}break;
case WM_TIMER:
{
UINT_PTR timer_id = (UINT_PTR)wParam;
KillTimer(win32vars.window_handle, timer_id);
win32vars.got_useful_event = true;
}break;
2016-05-04 23:21:30 +00:00
case WM_4coder_ANIMATE:
2017-02-03 00:52:39 +00:00
{
win32vars.got_useful_event = true;
2017-02-03 00:52:39 +00:00
}break;
2016-05-04 23:21:30 +00:00
2016-03-21 03:58:34 +00:00
default:
{
result = DefWindowProc(hwnd, uMsg, wParam, lParam);
}break;
}
2016-05-26 02:42:02 +00:00
return(result);
2016-02-20 21:36:16 +00:00
}
//-
//-
2017-02-25 01:53:40 +00:00
int CALL_CONVENTION
2017-02-03 00:52:39 +00:00
WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow){
2016-08-29 01:03:26 +00:00
i32 argc = __argc;
2016-05-10 17:36:53 +00:00
char **argv = __argv;
2021-05-17 06:13:27 +00:00
// NOTE(allen): someone get my shit togeth :(er for me
for (i32 i = 0; i < argc; i += 1){
String_Const_u8 arg = SCu8(argv[i]);
printf("arg[%d]: %.*s\n", i, string_expand(arg));
if (string_match(arg, str8_lit("-L"))){
log_os_enabled = true;
}
}
log_os("Logging startup...\n");
log_os("Initializing thread context...\n");
InitializeCriticalSection(&memory_tracker_mutex);
// NOTE(allen): context setup
Thread_Context _tctx = {};
2019-10-21 02:02:58 +00:00
thread_ctx_init(&_tctx, ThreadKind_Main, get_base_allocator_system(), get_base_allocator_system());
block_zero_struct(&win32vars);
win32vars.tctx = &_tctx;
2021-05-17 06:13:27 +00:00
log_os("Filling API v-tables...\n");
API_VTable_system system_vtable = {};
system_api_fill_vtable(&system_vtable);
API_VTable_graphics graphics_vtable = {};
graphics_api_fill_vtable(&graphics_vtable);
API_VTable_font font_vtable = {};
font_api_fill_vtable(&font_vtable);
2021-05-17 06:13:27 +00:00
log_os("Setting up memory management...\n");
// NOTE(allen): memory
2020-03-11 23:22:37 +00:00
win32vars.frame_arena = make_arena_system();
// TODO(allen): *arena;
target.arena = make_arena_system(KB(256));
win32vars.cursor_show = MouseCursorShow_Always;
win32vars.prev_cursor_show = MouseCursorShow_Always;
2021-05-17 06:13:27 +00:00
log_os("Setting up threading primitives...\n");
dll_init_sentinel(&win32vars.free_win32_objects);
dll_init_sentinel(&win32vars.timer_objects);
InitializeCriticalSection(&win32vars.thread_launch_mutex);
InitializeConditionVariable(&win32vars.thread_launch_cv);
2021-05-17 06:13:27 +00:00
log_os("Setting up DPI awareness...\n");
SetProcessDPIAware();
{
HDC dc = GetDC(0);
i32 x_dpi = GetDeviceCaps(dc, LOGPIXELSX);
i32 y_dpi = GetDeviceCaps(dc, LOGPIXELSY);
i32 max_dpi = max(x_dpi, y_dpi);
win32vars.screen_scale_factor = ((f32)max_dpi)/96.f;
ReleaseDC(0, dc);
2021-05-17 06:13:27 +00:00
log_os(" detected dpi %f\n", win32vars.screen_scale_factor);
}
// NOTE(allen): load core
2021-05-17 06:13:27 +00:00
log_os("Loading 4ed core...\n");
System_Library core_library = {};
App_Functions app = {};
{
App_Get_Functions *get_funcs = 0;
2020-03-11 23:22:37 +00:00
Scratch_Block scratch(win32vars.tctx);
List_String_Const_u8 search_list = {};
def_search_list_add_system_path(scratch, &search_list, SystemPath_Binary);
2021-05-17 06:13:27 +00:00
String_Const_u8 core_path =
def_search_get_full_path(scratch, &search_list, SCu8("4ed_app.dll"));
log_os(" path to core: '%.*s'\n", string_expand(core_path));
if (system_load_library(scratch, core_path, &core_library)){
get_funcs = (App_Get_Functions*)system_get_proc(core_library, "app_get_functions");
if (get_funcs != 0){
app = get_funcs();
}
else{
char msg[] = "Failed to get application code from '4ed_app.dll'.";
2021-01-17 00:14:12 +00:00
system_error_box(msg);
}
}
else{
char msg[] = "Could not load '4ed_app.dll'. This file should be in the same directory as the main '4ed' executable.";
2021-01-17 00:14:12 +00:00
system_error_box(msg);
}
}
2021-05-17 06:13:27 +00:00
log_os(" core loaded\n");
// NOTE(allen): send system vtable to core
2021-05-17 06:13:27 +00:00
log_os("Linking vtables...\n");
app.load_vtables(&system_vtable, &font_vtable, &graphics_vtable);
win32vars.log_string = app.get_logger();
// NOTE(allen): init & command line parameters
2021-05-17 06:13:27 +00:00
log_os("Parsing command line...\n");
Plat_Settings plat_settings = {};
void *base_ptr = 0;
{
2020-03-11 23:22:37 +00:00
Scratch_Block scratch(win32vars.tctx);
String_Const_u8 curdir = system_get_path(scratch, SystemPath_CurrentDirectory);
curdir = string_mod_replace_character(curdir, '\\', '/');
char **files = 0;
i32 *file_count = 0;
base_ptr = app.read_command_line(win32vars.tctx, curdir, &plat_settings, &files, &file_count, argc, argv);
{
i32 end = *file_count;
i32 i = 0, j = 0;
for (; i < end; ++i){
if (system_file_can_be_made(scratch, (u8*)files[i])){
files[j] = files[i];
++j;
}
}
*file_count = j;
}
}
// NOTE(allen): setup user directory override
2021-05-17 06:13:27 +00:00
log_os("User directory override: '%s'\n", plat_settings.user_directory);
if (plat_settings.user_directory != 0){
w32_override_user_directory = SCu8((u8*)plat_settings.user_directory);
}
// NOTE(allen): load custom layer
2021-05-17 06:13:27 +00:00
log_os("Loading custom layer...\n");
System_Library custom_library = {};
Custom_API custom = {};
{
char custom_not_found_msg[] = "Did not find a library for the custom layer.";
char custom_fail_version_msg[] = "Failed to load custom code due to missing version information or a version mismatch. Try rebuilding with buildsuper.";
2019-10-05 02:48:05 +00:00
char custom_fail_init_apis[] = "Failed to load custom code due to missing 'init_apis' symbol. Try rebuilding with buildsuper";
2020-03-11 23:22:37 +00:00
Scratch_Block scratch(win32vars.tctx);
String_Const_u8 default_file_name = string_u8_litexpr("custom_4coder.dll");
List_String_Const_u8 search_list = {};
def_search_list_add_system_path(scratch, &search_list, SystemPath_UserDirectory);
def_search_list_add_system_path(scratch, &search_list, SystemPath_Binary);
2020-11-24 06:27:33 +00:00
2021-05-17 06:13:27 +00:00
if (log_os_enabled){
log_os(" search list (paths):");
for (Node_String_Const_u8 *node = search_list.first;
node != 0;
node = node->next){
log_os("'%.*s'", string_expand(node->string));
if (node->next != 0){
log_os(", ");
}
}
log_os("\n");
}
String_Const_u8 custom_file_names[2] = {};
i32 custom_file_count = 1;
if (plat_settings.custom_dll != 0){
custom_file_names[0] = SCu8(plat_settings.custom_dll);
if (!plat_settings.custom_dll_is_strict){
custom_file_names[1] = default_file_name;
custom_file_count += 1;
}
}
else{
custom_file_names[0] = default_file_name;
}
2021-05-17 06:13:27 +00:00
log_os(" search list (file names): '%.*s', '%.*s'\n",
string_expand(custom_file_names[0]), string_expand(custom_file_names[1]));
String_Const_u8 custom_file_name = {};
for (i32 i = 0; i < custom_file_count; i += 1){
custom_file_name = def_search_get_full_path(scratch, &search_list, custom_file_names[i]);
if (custom_file_name.size > 0){
break;
}
}
2021-05-17 06:13:27 +00:00
log_os(" trying to load: '%.*s'\n", string_expand(custom_file_name));
b32 has_library = false;
if (custom_file_name.size > 0){
if (system_load_library(scratch, custom_file_name, &custom_library)){
has_library = true;
}
}
if (!has_library){
2021-01-17 00:14:12 +00:00
system_error_box(custom_not_found_msg);
}
2019-10-10 22:57:02 +00:00
custom.get_version = (_Get_Version_Type*)system_get_proc(custom_library, "get_version");
2019-10-05 02:48:05 +00:00
if (custom.get_version == 0 || custom.get_version(MAJOR, MINOR, PATCH) == 0){
2021-01-17 00:14:12 +00:00
system_error_box(custom_fail_version_msg);
}
2019-10-10 22:57:02 +00:00
custom.init_apis = (_Init_APIs_Type*)system_get_proc(custom_library, "init_apis");
2019-10-05 02:48:05 +00:00
if (custom.init_apis == 0){
2021-01-17 00:14:12 +00:00
system_error_box(custom_fail_init_apis);
2019-10-05 02:48:05 +00:00
}
}
2021-05-17 06:13:27 +00:00
log_os(" loaded successfully\n");
// NOTE(allen): Window Init
2021-05-17 06:13:27 +00:00
log_os("Initializing graphical window...\n");
log_os(" getting initial settings...\n");
RECT window_rect = {};
2017-07-18 21:19:28 +00:00
if (plat_settings.set_window_size){
window_rect.right = plat_settings.window_w;
window_rect.bottom = plat_settings.window_h;
2016-02-20 21:36:16 +00:00
}
else{
window_rect.right = 800;
window_rect.bottom = 600;
}
AdjustWindowRect(&window_rect, WS_OVERLAPPEDWINDOW, false);
i32 window_style = WS_OVERLAPPEDWINDOW;
if (!plat_settings.fullscreen_window && plat_settings.maximize_window){
window_style |= WS_MAXIMIZE;
}
2021-05-17 06:13:27 +00:00
log_os(" windowed dimensions: %d, %d\n"
" initially maximized: %d\n",
2021-05-17 06:13:27 +00:00
window_rect.right - window_rect.left,
window_rect.bottom - window_rect.top,
((window_style & WS_MAXIMIZE) != 0));
#if defined( WIN32_DX11 )
if( !win32_gl_create_window( &win32vars.window_handle, window_style, window_rect ) ) {
exit(1);
}
#else
HGLRC window_opengl_context = 0;
if (!win32_gl_create_window(&win32vars.window_handle, &window_opengl_context, window_style, window_rect)){
exit(1);
}
#endif
2021-05-17 06:13:27 +00:00
log_os(" window created successfully\n");
GetClientRect(win32vars.window_handle, &window_rect);
win32_resize(window_rect.right - window_rect.left, window_rect.bottom - window_rect.top);
// NOTE(allen): Audio Init
2021-05-17 06:13:27 +00:00
log_os("Initializing audio...\n");
win32vars.audio_thread_id = win32_audio_init();
// NOTE(allen): Misc Init
2021-05-17 06:13:27 +00:00
log_os("Initializing clipboard listener...\n");
if (!AddClipboardFormatListener(win32vars.window_handle)){
String_Const_u8 error_string = win32_get_error_string();
win32_output_error_string(error_string);
}
2020-02-08 00:50:35 +00:00
win32vars.clip_wakeup_timer = system_wake_up_timer_create();
2021-07-14 15:17:41 +00:00
win32vars.clipboard_sequence = 0;
2021-05-17 06:13:27 +00:00
log_os("Setting up keyboard layout...\n");
2020-05-01 18:19:24 +00:00
win32vars.kl_universal = LoadKeyboardLayoutW(L"00000409", 0);
win32_keycode_init();
2021-05-17 06:13:27 +00:00
log_os("Loading cursors...\n");
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);
2021-05-17 06:13:27 +00:00
log_os("Initializing performance counter...\n");
LARGE_INTEGER f;
if (QueryPerformanceFrequency(&f)){
2021-05-17 06:13:27 +00:00
win32vars.usecond_per_count = 1000000.f/(f32)f.QuadPart;
}
else{
// NOTE(allen): Just guess.
2021-05-17 06:13:27 +00:00
win32vars.usecond_per_count = 1.f;
log_os(" load failed, guessing usecond_per_count = 1\n");
}
if (win32vars.usecond_per_count <= 0.f){
win32vars.usecond_per_count = 1.f;
}
//
// App init
//
2021-05-17 06:13:27 +00:00
log_os("Initializing 4ed core...\n");
{
2020-03-11 23:22:37 +00:00
Scratch_Block scratch(win32vars.tctx);
String_Const_u8 curdir = system_get_path(scratch, SystemPath_CurrentDirectory);
curdir = string_mod_replace_character(curdir, '\\', '/');
2020-02-08 00:50:35 +00:00
app.init(win32vars.tctx, &target, base_ptr, curdir, custom);
}
//
// Main loop
//
2021-05-17 06:13:27 +00:00
log_os("Starting main loop...\n");
b32 keep_running = true;
win32vars.first = true;
timeBeginPeriod(1);
2016-05-10 17:36:53 +00:00
2017-07-18 21:19:28 +00:00
if (plat_settings.fullscreen_window){
win32_toggle_fullscreen();
2016-09-01 03:06:46 +00:00
}
SetForegroundWindow(win32vars.window_handle);
SetActiveWindow(win32vars.window_handle);
ShowWindow(win32vars.window_handle, SW_SHOW);
2016-05-10 17:36:53 +00:00
//- @Added by jack
u64 frame_rate = win32_get_frame_rate();
u64 frame_useconds = (1000000 / frame_rate);
//-
2019-10-21 02:02:58 +00:00
win32vars.global_frame_mutex = system_mutex_make();
system_acquire_global_frame_mutex(win32vars.tctx);
2019-10-21 02:02:58 +00:00
u64 timer_start = system_now_time();
2016-02-20 21:36:16 +00:00
MSG msg;
for (;keep_running;){
2020-03-11 23:22:37 +00:00
linalloc_clear(&win32vars.frame_arena);
block_zero_struct(&win32vars.input_chunk.trans);
2019-10-10 20:15:47 +00:00
win32vars.active_key_stroke = 0;
win32vars.active_text_input = 0;
2016-05-10 17:36:53 +00:00
// TODO(allen): Find a good way to wait on a pipe
// without interfering with the reading process.
// NOTE(allen): Looks like we can ReadFile with a
// size of zero in an IOCP for this effect.
if (!win32vars.first){
2017-02-03 00:52:39 +00:00
if (win32vars.running_cli == 0){
win32vars.got_useful_event = false;
}
// NOTE(allen): while we're doing this (and possibly sleeping)
// we can let async processes get there time in.
system_release_global_frame_mutex(win32vars.tctx);
b32 get_more_messages = true;
do{
2018-08-05 07:09:18 +00:00
if (win32vars.got_useful_event == 0){
get_more_messages = GetMessage(&msg, 0, 0, 0);
}
else{
get_more_messages = PeekMessage(&msg, 0, 0, 0, 1);
}
if (get_more_messages){
if (msg.message == WM_QUIT){
keep_running = false;
}
else{
b32 treat_normally = true;
if (msg.message == WM_KEYDOWN || msg.message == WM_SYSKEYDOWN){
switch (msg.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:break;
default: treat_normally = false; break;
}
}
if (treat_normally){
2019-10-10 20:15:47 +00:00
TranslateMessage(&msg);
2020-05-09 22:07:31 +00:00
DispatchMessage(&msg);
}
else{
Control_Keys *controls = &win32vars.input_chunk.pers.controls;
b8 ctrl = (controls->r_ctrl || (controls->l_ctrl && !controls->r_alt));
b8 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;
}
}
BYTE ctrl_state = 0, alt_state = 0;
BYTE state[256];
if (ctrl || alt){
GetKeyboardState(state);
if (ctrl){
ctrl_state = state[VK_CONTROL];
state[VK_CONTROL] = 0;
}
if (alt){
alt_state = state[VK_MENU];
state[VK_MENU] = 0;
}
SetKeyboardState(state);
TranslateMessage(&msg);
DispatchMessage(&msg);
if (ctrl){
state[VK_CONTROL] = ctrl_state;
}
if (alt){
state[VK_MENU] = alt_state;
}
SetKeyboardState(state);
}
else{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
2016-05-10 17:36:53 +00:00
}
}
}while (get_more_messages);
system_acquire_global_frame_mutex(win32vars.tctx);
2016-05-04 23:21:30 +00:00
}
// NOTE(allen): Mouse Out of Window Detection
POINT mouse_point;
if (GetCursorPos(&mouse_point) &&
ScreenToClient(win32vars.window_handle, &mouse_point)){
Rect_i32 screen = Ri32(0, 0, target.width, target.height);
Vec2_i32 mp = V2i32(mouse_point.x, mouse_point.y);
win32vars.input_chunk.trans.out_of_window = (!rect_contains_point(screen, mp));
win32vars.input_chunk.pers.mouse = mp;
}
else{
win32vars.input_chunk.trans.out_of_window = true;
}
// NOTE(allen): Prepare the Frame Input
// TODO(allen): CROSS REFERENCE WITH LINUX SPECIAL CODE "TIC898989"
Win32_Input_Chunk input_chunk = win32vars.input_chunk;
2020-02-08 00:50:35 +00:00
Scratch_Block scratch(win32vars.tctx);
Application_Step_Input input = {};
2018-08-05 07:09:18 +00:00
input.first_step = win32vars.first;
input.dt = frame_useconds/1000000.f;
input.events = input_chunk.trans.event_list;
2018-08-05 07:09:18 +00:00
input.mouse.out_of_window = input_chunk.trans.out_of_window;
input.mouse.l = input_chunk.pers.mouse_l;
input.mouse.press_l = input_chunk.trans.mouse_l_press;
input.mouse.release_l = input_chunk.trans.mouse_l_release;
input.mouse.r = input_chunk.pers.mouse_r;
input.mouse.press_r = input_chunk.trans.mouse_r_press;
input.mouse.release_r = input_chunk.trans.mouse_r_release;
input.mouse.wheel = input_chunk.trans.mouse_wheel;
2019-02-25 23:42:13 +00:00
input.mouse.p = input_chunk.pers.mouse;
2018-08-05 07:09:18 +00:00
input.trying_to_kill = input_chunk.trans.trying_to_kill;
// TODO(allen): Not really appropriate to round trip this all the way to the OS layer, redo this system.
// NOTE(allen): Ask the Core About Exiting if We Have an Exit Signal
if (win32vars.send_exit_signal){
input.trying_to_kill = true;
win32vars.send_exit_signal = false;
}
// NOTE(allen): Frame Clipboard Input
2020-02-08 00:50:35 +00:00
if (win32vars.clip_catch_all){
input.clipboard = system_get_clipboard(scratch, 0);
}
win32vars.clip_post.size = 0;
2017-11-13 22:12:04 +00:00
2016-09-01 20:29:07 +00:00
// NOTE(allen): Application Core Update
2020-02-08 00:50:35 +00:00
Application_Step_Result result = app.step(win32vars.tctx, &target, base_ptr, &input);
// NOTE(allen): Finish the Loop
if (result.perform_kill){
keep_running = false;
}
2017-11-13 22:12:04 +00:00
// NOTE(allen): Post New Clipboard Content
if (win32vars.clip_post.size > 0){
win32_post_clipboard(scratch, (char*)win32vars.clip_post.str, (i32)win32vars.clip_post.size);
2017-11-13 22:12:04 +00:00
}
// NOTE(allen): Switch to New Title
if (result.has_new_title){
SetWindowText_utf8(scratch, win32vars.window_handle, (u8*)result.title_string);
}
// NOTE(allen): Switch to New Cursor
Win32SetCursorFromUpdate(result.mouse_cursor_type);
if (win32vars.cursor_show != win32vars.prev_cursor_show){
win32vars.prev_cursor_show = win32vars.cursor_show;
switch (win32vars.cursor_show){
case MouseCursorShow_Never:
{
i32 counter = 0;
do{
counter = ShowCursor(false);
}while(counter >= 0);
}break;
case MouseCursorShow_Always:
{
i32 counter = 0;
do{
counter = ShowCursor(true);
}while(counter <= 0);
}break;
// TODO(allen): MouseCursorShow_HideWhenStill
}
}
// NOTE(allen): update lctrl_lalt_is_altgr status
win32vars.lctrl_lalt_is_altgr = (b8)result.lctrl_lalt_is_altgr;
// NOTE(allen): render
#if defined( WIN32_DX11 )
gl_render(&target);
g_dx11.swap_chain->Present( 1, 0 );
#else
HDC hdc = GetDC(win32vars.window_handle);
gl_render(&target);
2017-11-10 18:27:39 +00:00
SwapBuffers(hdc);
ReleaseDC(win32vars.window_handle, hdc);
#endif
2016-07-19 23:47:27 +00:00
// NOTE(allen): toggle full screen
if (win32vars.do_toggle){
win32_toggle_fullscreen();
win32vars.do_toggle = false;
}
// NOTE(allen): schedule another step if needed
if (result.animating){
2019-08-13 04:19:02 +00:00
system_schedule_step(0);
}
2020-02-08 00:50:35 +00:00
else if (win32vars.clip_catch_all){
system_wake_up_timer_set(win32vars.clip_wakeup_timer, 250);
}
// NOTE(allen): sleep a bit to cool off :)
system_release_global_frame_mutex(win32vars.tctx);
2019-10-21 02:02:58 +00:00
u64 timer_end = system_now_time();
u64 end_target = timer_start + frame_useconds;
for (;timer_end < end_target;){
DWORD samount = (DWORD)((end_target - timer_end)/1000);
if (samount > 0){
Sleep(samount);
}
timer_end = system_now_time();
}
timer_start = system_now_time();
system_acquire_global_frame_mutex(win32vars.tctx);
2019-10-21 02:02:58 +00:00
win32vars.first = false;
2016-02-20 21:36:16 +00:00
}
2016-05-27 17:11:38 +00:00
#if defined( WIN32_DX11 ) && !SHIP_MODE
win32_gl_cleanup( );
#endif
return(0);
2016-02-20 21:36:16 +00:00
}
#include "win32_utf8.cpp"
2016-05-29 03:12:12 +00:00
#if 0
// NOTE(allen): In case I want to switch back to a console application at some point.
2016-05-29 03:12:12 +00:00
int main(int argc, char **argv){
HINSTANCE hInstance = GetModuleHandle(0);
}
2016-05-29 03:12:12 +00:00
#endif
// BOTTOM