eigsol_gpu/src/os/win32/os_gfx_win32.c
2024-10-09 09:23:43 +02:00

328 lines
9.7 KiB
C

#pragma comment(lib, "gdi32")
#define OS_W32_GraphicalWindowClassName L"ApplicationWindowClass"
root_function OS_InitGfxReceipt
OS_gfx_init(OS_InitReceipt os_init_receipt)
{
if (is_main_thread() && os_g_w32_gfx_state == 0)
{
{
// Global state
Arena *arena = m_make_arena_reserve(Gigabytes(1));
os_g_w32_gfx_state = PushArray(arena, OS_W32_Gfx_State, 1);
os_g_w32_gfx_state->arena = arena;
os_g_w32_gfx_state->window_arena = m_make_arena_reserve(Gigabytes(1));
}
// TODO(antonl) DPI awareness
// Register window class
{
/* WNDCLASSW window_class = { 0 }; */
/* window_class.style = CS_HREDRAW | CS_VREDRAW; */
/* window_class.lpfnWndProc = OS_W32_WindowProc; */
/* window_class.hInstance = g_os_w32_hinstance; */
/* window_class.lpszClassName = OS_W32_GraphicalWindowClassName; */
/* window_class.hCursor = LoadCursor(0, IDC_ARROW); */
/* RegisterClassW(&window_class); */
WNDCLASSEXW window_class = {0};
window_class.cbSize = sizeof(WNDCLASSEXW);
window_class.lpfnWndProc = OS_W32_window_proc;
window_class.hInstance = os_g_w32_hinstance;
window_class.lpszClassName = OS_W32_GraphicalWindowClassName;
if(!RegisterClassExW(&window_class))
{
break_debugger();
}
}
// Rjf makes a "global invisible window", but why?
{
os_g_w32_gfx_state->global_hwnd = CreateWindowExW(0,
OS_W32_GraphicalWindowClassName,
L"",
WS_OVERLAPPEDWINDOW,
100,100,
0,0,
0,0,
os_g_w32_hinstance, 0);
os_g_w32_gfx_state->global_hdc = GetDC(os_g_w32_gfx_state->global_hwnd);
}
}
OS_InitGfxReceipt out;
out.u64[0] = 1;
return out;
}
root_function OS_Handle
OS_W32_handle_from_window(OS_W32_Window *window)
{
OS_Handle handle = { 0 };
handle.u64[0] = (U64)window;
return handle;
}
root_function OS_W32_Window*
OS_W32_window_from_handle(OS_Handle handle)
{
OS_W32_Window *window = (OS_W32_Window *)handle.u64[0];
return window;
}
root_function OS_Handle
OS_window_open(OS_Window_Flags flags, Vec2_S64 size, String8 title)
{
OS_Handle handle = { 0 };
{
// Window allocation
OS_W32_Window *window = os_g_w32_gfx_state->free_window;
{
// Windows are stored in a stack on the gfx state
if (window != 0)
{
StackPop(os_g_w32_gfx_state->free_window);
}
else
{
window = PushArray(os_g_w32_gfx_state->window_arena, OS_W32_Window, 1);
}
MemoryZeroStruct(window);
DLLPushBack(os_g_w32_gfx_state->first_window, os_g_w32_gfx_state->last_window, window);
}
// Open window
HWND hwnd = 0;
HDC hdc = 0;
{
ArenaTemp scratch = scratch_get(0, 0);
String16 title16 = str16_from8(scratch.arena, title);
hwnd = CreateWindowExW(0,
OS_W32_GraphicalWindowClassName, (LPCWSTR)title16.str,
WS_OVERLAPPEDWINDOW | WS_VISIBLE,
100, 100,
size.x, size.y, 0, 0, os_g_w32_hinstance, 0);
hdc = GetDC(hwnd);
SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)window);
scratch_release(scratch);
}
{
window->hwnd = hwnd;
window->hdc = hdc;
}
handle = OS_W32_handle_from_window(window);
}
return handle;
}
function LRESULT
OS_W32_window_proc(HWND hwnd, UINT message, WPARAM w_param, LPARAM l_param)
{
LRESULT result = 0;
OS_Event *event = 0;
OS_W32_Window *window = (OS_W32_Window *)GetWindowLongPtr(hwnd, GWLP_USERDATA);
OS_Handle window_handle = OS_W32_handle_from_window(window);
ArenaTemp scratch = scratch_get(&os_w32_tl_events_arena, 1);
OS_EventList fallback_event_list = {0};
if(os_w32_tl_events_arena == 0)
{
os_w32_tl_events_arena = scratch.arena;
os_w32_tl_events_list = &fallback_event_list;
}
B32 is_release = 0;
Axis2 scroll_axis = Axis2_Y;
switch(message)
{
default:
{
result = DefWindowProcW(hwnd, message, w_param, l_param);
} break;
//- General window events
case WM_CLOSE:
{
event = PushArray(os_w32_tl_events_arena, OS_Event, 1);
event->kind = OS_EventKind_WindowClose;
event->window = window_handle;
} break;
//- Mouse buttons
case WM_LBUTTONUP:
case WM_MBUTTONUP:
case WM_RBUTTONUP:
{
ReleaseCapture();
is_release = 1;
} fallthrough;
case WM_LBUTTONDOWN:
case WM_MBUTTONDOWN:
case WM_RBUTTONDOWN:
{
if(is_release == 0)
{
SetCapture(hwnd);
}
OS_EventKind kind = is_release ? OS_EventKind_Release : OS_EventKind_Press;
OS_Key key = OS_Key_MouseLeft;
switch(message)
{
case WM_MBUTTONUP: case WM_MBUTTONDOWN: key = OS_Key_MouseMiddle; break;
case WM_RBUTTONUP: case WM_RBUTTONDOWN: key = OS_Key_MouseRight; break;
}
event = PushArray(os_w32_tl_events_arena, OS_Event, 1);
event->kind = kind;
event->window = window_handle;
event->key = key;
event->position = OS_mouse_from_window(window_handle);
} break;
//- Keyboard events
case WM_SYSKEYDOWN: case WM_SYSKEYUP:
{
result = DefWindowProcW(hwnd, message, w_param, l_param);
} fallthrough;
case WM_KEYDOWN:
case WM_KEYUP:
{
// TODO(anton): Just check this thing with was down, is down.., WINAPI crap
B32 was_down = !!(l_param & (1 << 30));
B32 is_down = !(l_param & (1 << 31));
OS_EventKind kind = is_down ? OS_EventKind_Press : OS_EventKind_Release;
// TODO(anton): Here we use statics but maybe we should not...
// Could just move this out and pre-init or generate it and include or whatever...
// probably should just be in some meta header.
local_persist OS_Key key_table[256] = {0};
local_persist B32 key_table_initialised = 0;
if(!key_table_initialised)
{
key_table_initialised = 1;
for (U32 i = 'A', j = OS_Key_A; i <= 'Z'; i += 1, j += 1)
{
key_table[i] = (OS_Key)j;
}
for (U32 i = '0', j = OS_Key_0; i <= '9'; i += 1, j += 1)
{
key_table[i] = (OS_Key)j;
}
for (U32 i = VK_F1, j = OS_Key_F1; i <= VK_F24; i += 1, j += 1)
{
key_table[i] = (OS_Key)j;
}
key_table[VK_ESCAPE] = OS_Key_Esc;
key_table[VK_OEM_3] = OS_Key_GraveAccent;
key_table[VK_OEM_MINUS] = OS_Key_Minus;
key_table[VK_OEM_PLUS] = OS_Key_Equal;
key_table[VK_BACK] = OS_Key_Backspace;
key_table[VK_TAB] = OS_Key_Tab;
key_table[VK_SPACE] = OS_Key_Space;
key_table[VK_RETURN] = OS_Key_Enter;
key_table[VK_CONTROL] = OS_Key_Ctrl;
key_table[VK_SHIFT] = OS_Key_Shift;
key_table[VK_MENU] = OS_Key_Alt;
key_table[VK_UP] = OS_Key_Up;
key_table[VK_LEFT] = OS_Key_Left;
key_table[VK_DOWN] = OS_Key_Down;
key_table[VK_RIGHT] = OS_Key_Right;
key_table[VK_DELETE] = OS_Key_Delete;
key_table[VK_PRIOR] = OS_Key_PageUp;
key_table[VK_NEXT] = OS_Key_PageDown;
key_table[VK_HOME] = OS_Key_Home;
key_table[VK_END] = OS_Key_End;
key_table[VK_OEM_2] = OS_Key_ForwardSlash;
key_table[VK_OEM_PERIOD] = OS_Key_Period;
key_table[VK_OEM_COMMA] = OS_Key_Comma;
key_table[VK_OEM_7] = OS_Key_Quote;
key_table[VK_OEM_4] = OS_Key_LeftBracket;
key_table[VK_OEM_6] = OS_Key_RightBracket;
key_table[VK_INSERT] = OS_Key_Insert;
key_table[VK_OEM_1] = OS_Key_Semicolon;
}
OS_Key key = OS_Key_Null;
if(w_param < ArrayCount(key_table))
{
key = key_table[w_param];
}
event = PushArray(os_w32_tl_events_arena, OS_Event, 1);
event->kind = kind;
event->window = window_handle;
event->key = key;
} break;
}
// If we registered an event we push it to the event list.
if(event)
{
DLLPushBack(os_w32_tl_events_list->first, os_w32_tl_events_list->last, event);
os_w32_tl_events_list->count += 1;
}
scratch_release(scratch);
return result;
}
root_function Vec2_F32
OS_mouse_from_window(OS_Handle handle)
{
Vec2_F32 result = vec2_F32(-100, -100);
OS_W32_Window *window = OS_W32_window_from_handle(handle);
if(window != 0)
{
POINT point;
if(GetCursorPos(&point))
{
if(ScreenToClient(window->hwnd, &point))
{
result = vec2_F32(point.x, point.y);
}
}
}
return result;
}
root_function OS_EventList
OS_get_events(Arena* arena)
{
OS_EventList list = {0};
os_w32_tl_events_arena = arena;
os_w32_tl_events_list = &list;
for(MSG message; PeekMessage(&message, 0, 0, 0, PM_REMOVE);)
{
TranslateMessage(&message);
DispatchMessage(&message);
}
os_w32_tl_events_arena = 0;
os_w32_tl_events_list = 0;
return list;
}
root_function void
OS_consume_event(OS_EventList *events, OS_Event *event)
{
DLLRemove(events->first, events->last, event);
events->count -= 1;
event->kind = OS_EventKind_Null;
}
root_function void
OS_window_first_paint(OS_Handle handle)
{
ArenaTemp scratch = scratch_get(0,0);
OS_W32_Window *window = OS_W32_window_from_handle(handle);
ShowWindow(window->hwnd, SW_SHOW);
UpdateWindow(window->hwnd);
scratch_release(scratch);
}