#include "app.hpp" extern "C" { #include "memory.h" #include "plat.h" extern App* entrypoint(Arena* mem); } #ifdef plat_x11 #include #include #include Key key_from_xkey(unsigned key) { switch (key) { case 0x61: return key_A; case 0x62: return key_B; case 0x63: return key_C; case 0x64: return key_D; case 0x65: return key_E; case 0x66: return key_F; case 0x67: return key_G; case 0x68: return key_H; case 0x69: return key_I; case 0x6A: return key_J; case 0x6B: return key_K; case 0x6C: return key_L; case 0x6D: return key_M; case 0x6E: return key_N; case 0x6F: return key_O; case 0x70: return key_P; case 0x71: return key_Q; case 0x72: return key_R; case 0x73: return key_S; case 0x74: return key_T; case 0x75: return key_U; case 0x76: return key_V; case 0x77: return key_W; case 0x78: return key_X; case 0x79: return key_Y; case 0x7A: return key_Z; case XK_F1: return key_f1; case XK_F2: return key_f2; case XK_F3: return key_f3; case XK_F4: return key_f4; case XK_F5: return key_f5; case XK_F6: return key_f6; case XK_F7: return key_f7; case XK_F8: return key_f8; case XK_F9: return key_f9; case XK_F10: return key_f10; case XK_F11: return key_f11; case XK_F12: return key_f12; case XK_Down: return key_down; case XK_Left: return key_left; case XK_Right: return key_right; case XK_Up: return key_up; case XK_Escape: return key_escape; case XK_Return: return key_return; case XK_BackSpace: return key_backspace; case XK_Linefeed: return key_return; case XK_Tab: return key_tab; case XK_Delete: return key_delete; case XK_Home: return key_home; case XK_End: return key_end; case XK_Page_Up: return key_page_up; case XK_Page_Down: return key_page_down; case XK_Insert: return key_insert; case XK_Shift_L: return key_shift; case XK_Shift_R: return key_shift; case XK_Control_L: return key_control; case XK_Control_R: return key_control; case XK_Super_L: return key_super; case XK_Super_R: return key_super; case XK_Alt_L: return key_alt; case XK_Alt_R: return key_alt; case XK_space: return key_space; case XK_period: return key_period; case XK_0: return key_0; case XK_1: return key_1; case XK_2: return key_2; case XK_3: return key_3; case XK_4: return key_4; case XK_5: return key_5; case XK_6: return key_6; case XK_7: return key_7; case XK_8: return key_8; case XK_9: return key_9; default: return key_unknown; } } struct App_Internal { Display* d; Window wi; Atom wm_delete; void init(App* app, const char* name) { const int default_w = 1920; const int default_h = 1080; XWindowAttributes wa; XSetWindowAttributes attribs{}; attribs.event_mask = ExposureMask | KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask | PointerMotionMask ; Window root; Visual* v; d = XOpenDisplay(0); wm_delete = XInternAtom( d, "WM_DELETE_WINDOW", 0 ); root = DefaultRootWindow(d); v = XDefaultVisual(d, 0); wi = XCreateWindow( d, root, 0, 0, default_w, default_h, 0, 0, InputOutput, v, CWEventMask, &attribs ); XSetWMProtocols(d, wi, &wm_delete, 1); XStoreName(d, wi, name); XMapRaised(d, wi); XGetWindowAttributes(d, wi, &wa); app->w = wa.width; app->h = wa.height; } void begin(App* app) { while (XPending(d)) { XEvent e; XWindowAttributes wa; KeySym sym; Key key; int btn; XNextEvent(d, &e); switch (e.type) { case ClientMessage: if ( (Atom)e.xclient.data.l[0] == wm_delete ) { app->running = 0; } break; case Expose: XGetWindowAttributes(d, wi, &wa); if (app->w != wa.width || app->h != wa.height) { app->w = wa.width; app->h = wa.height; app->on_resize(); } break; case MotionNotify: app->mx = e.xmotion.x; app->my = e.xmotion.y; break; case ButtonPress: switch (e.xbutton.button) { case 1: case 2: case 3: app->mbtn_states[e.xbutton.button - 1] |= key_state_pressed | key_state_just_pressed; break; case 4: app->scrolly++; break; case 5: app->scrolly--; break; case 6: app->scrollx++; break; case 7: app->scrollx--; break; } break; case ButtonRelease: switch (e.xbutton.button) { case 1: case 2: case 3: btn = e.xbutton.button - 1; app->mbtn_states[btn] &= ~key_state_pressed; app->mbtn_states[btn] |= key_state_just_released; break; case 4: app->scrolly++; break; case 5: app->scrolly--; break; case 6: app->scrollx++; break; case 7: app->scrollx--; break; } break; case KeyPress: sym = XLookupKeysym(&e.xkey, 0); key = key_from_xkey(sym); app->key_states[key] |= key_state_pressed | key_state_just_pressed; break; case KeyRelease: sym = XLookupKeysym(&e.xkey, 0); key = key_from_xkey(sym); app->key_states[key] &= ~key_state_pressed; app->key_states[key] |= key_state_just_released; break; } } } void end(App* app) { (void)app; } }; extern "C" { #define GLAD_VULKAN_IMPLEMENTATION #define VK_USE_PLATFORM_XLIB_KHR #include "glad_vk.h" VkSurfaceKHR app_create_vk_surface(App* app, VkInstance inst) { App_Internal* i; VkSurfaceKHR s; VkXlibSurfaceCreateInfoKHR ci{}; VkResult r; i = app->internal; ci.sType = VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR; ci.dpy = i->d; ci.window = i->wi; r = vkCreateXlibSurfaceKHR(inst, &ci, 0, &s); if (r != VK_SUCCESS) { print_err("Failed to create a Vulkan surface."); pbreak(r); } return s; } void app_destroy_vk_surface( App* app, VkInstance inst, VkSurfaceKHR surf ) { (void)app; vkDestroySurfaceKHR(inst, surf, 0); } } int main() { char* mem = (char*)malloc(app_memory_size); Arena* arena = (Arena*)mem; App* a; mem += sizeof *arena; init_arena(arena, mem, app_memory_size - sizeof *arena); a = entrypoint(arena); a->arena = arena; a->on_init(); while (a->running) { a->begin(); a->on_update(); a->end(); } a->on_destroy(); a->destroy(); return 0; } #endif #ifdef plat_win #define WIN32_LEAN_AND_MEAN #include #include Key key_from_vk(unsigned key) { switch (key) { case 0x00: return key_unknown; case 0x41: return key_A; case 0x42: return key_B; case 0x43: return key_C; case 0x44: return key_D; case 0x45: return key_E; case 0x46: return key_F; case 0x47: return key_G; case 0x48: return key_H; case 0x49: return key_I; case 0x4a: return key_J; case 0x4b: return key_K; case 0x4c: return key_L; case 0x4d: return key_M; case 0x4e: return key_N; case 0x4f: return key_O; case 0x50: return key_P; case 0x51: return key_Q; case 0x52: return key_R; case 0x53: return key_S; case 0x54: return key_T; case 0x55: return key_U; case 0x56: return key_V; case 0x57: return key_W; case 0x58: return key_X; case 0x59: return key_Y; case 0x5a: return key_Z; case VK_F1: return key_f1; case VK_F2: return key_f2; case VK_F3: return key_f3; case VK_F4: return key_f4; case VK_F5: return key_f5; case VK_F6: return key_f6; case VK_F7: return key_f7; case VK_F8: return key_f8; case VK_F9: return key_f9; case VK_F10: return key_f10; case VK_F11: return key_f11; case VK_F12: return key_f12; case VK_DOWN: return key_down; case VK_LEFT: return key_left; case VK_RIGHT: return key_right; case VK_UP: return key_up; case VK_ESCAPE: return key_escape; case VK_BACK: return key_backspace; case VK_RETURN: return key_return; case VK_TAB: return key_tab; case VK_DELETE: return key_delete; case VK_HOME: return key_home; case VK_END: return key_end; case VK_PRIOR: return key_page_up; case VK_NEXT: return key_page_down; case VK_INSERT: return key_insert; case 16: return key_shift; case 17: return key_control; case 91: return key_super; case VK_LMENU: return key_alt; case VK_RMENU: return key_alt; case VK_SPACE: return key_space; case 0x30: return key_0; case 0x31: return key_1; case 0x32: return key_2; case 0x33: return key_3; case 0x34: return key_4; case 0x35: return key_5; case 0x36: return key_6; case 0x37: return key_7; case 0x38: return key_8; case 0x39: return key_9; } return key_unknown; } static LRESULT CALLBACK win32_event_callback(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam); struct App_Internal { HWND window; RECT rect; void init(App* app, const char* name) { const int default_w = 1920; const int default_h = 1080; int create_w, create_h; const DWORD dw_ex_style = WS_EX_APPWINDOW | WS_EX_WINDOWEDGE; const DWORD dw_style = WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | WS_VISIBLE | WS_THICKFRAME | WS_MAXIMIZEBOX; RECT win_rect = { 0, 0, default_w, default_h }; WNDCLASSA wc{}; wc.hIcon = LoadIcon(0, IDI_APPLICATION); wc.hCursor = LoadCursor(0, IDC_ARROW); wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC; wc.hInstance = GetModuleHandle(0); wc.lpfnWndProc = win32_event_callback; wc.lpszClassName = "corrosion_2"; RegisterClassA(&wc); AdjustWindowRectEx(&win_rect, dw_style, FALSE, dw_ex_style); create_w = win_rect.right - win_rect.left; create_h = win_rect.bottom - win_rect.top; window = CreateWindowExA(dw_ex_style, "corrosion_2", name, dw_style, 100, 100, create_w, create_h, 0, 0, GetModuleHandle(0), 0); assert(window != 0); app->w = create_w; app->h = create_h; SetWindowLongPtr(window, GWLP_USERDATA, (LONG_PTR)app); } void begin(App* app) { MSG msg; while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) { TranslateMessage(&msg); DispatchMessage(&msg); } } void end(App* app) { (void)app; } }; static void win32_on_resize(HWND window, UINT msg, UINT_PTR timer, DWORD time) { RECT rect; int nw, nh; App* app = (App*)GetWindowLongPtr(window, GWLP_USERDATA); if (!app) return; GetClientRect(window, &rect); nw = rect.right - rect.left; nh = rect.bottom - rect.top; if (nw != app->w && nh != app->h) app->on_resize(); app->end(); app->begin(); app->on_update(); } static LRESULT CALLBACK win32_event_callback(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) { RECT rect; App* app = (App*)GetWindowLongPtr(hwnd, GWLP_USERDATA); if (!app) return DefWindowProc(hwnd, msg, wparam, lparam); switch (msg) { case WM_CLOSE: app->running = 0; return 0; case WM_SIZE: app->w = lparam & 0xffff; app->h = (lparam >> 16) & 0xffff; app->on_resize(); return 0; case WM_ENTERSIZEMOVE: SetTimer(hwnd, 0, 10, win32_on_resize); return 0; case WM_EXITSIZEMOVE: KillTimer(hwnd, 0); app->end(); return 0; case WM_MOUSEMOVE: app->mx = lparam & 0xffff; app->my = (lparam >> 16) & 0xffff; return 0; case WM_LBUTTONDOWN: app->mbtn_states[mbtn_left] |= key_state_pressed | key_state_just_pressed; return 0; case WM_MBUTTONDOWN: app->mbtn_states[mbtn_middle] |= key_state_pressed | key_state_just_pressed; return 0; case WM_RBUTTONDOWN: app->mbtn_states[mbtn_right] |= key_state_pressed | key_state_just_pressed; return 0; case WM_LBUTTONUP: app->mbtn_states[mbtn_left] &= ~key_state_pressed; app->mbtn_states[mbtn_left] |= key_state_just_released; return 0; case WM_MBUTTONUP: app->mbtn_states[mbtn_middle] &= ~key_state_pressed; app->mbtn_states[mbtn_middle] |= key_state_just_released; return 0; case WM_RBUTTONUP: app->mbtn_states[mbtn_right] &= ~key_state_pressed; app->mbtn_states[mbtn_right] |= key_state_just_released; return 0; case WM_MOUSEWHEEL: app->scrolly += GET_WHEEL_DELTA_WPARAM(wparam) > 1 ? 1 : -1; return 0; case WM_KEYDOWN: { Key key = key_from_vk((unsigned)wparam); app->key_states[key] |= key_state_pressed | key_state_just_pressed; } return 0; case WM_KEYUP: { Key key = key_from_vk((unsigned)wparam); app->key_states[key] &= ~key_state_pressed; app->key_states[key] |= key_state_just_released; } return 0; } return DefWindowProc(hwnd, msg, wparam, lparam); } HINSTANCE g_instance; extern "C" { #define GLAD_VULKAN_IMPLEMENTATION #define VK_USE_PLATFORM_WIN32_KHR #include "glad_vk.h" VkSurfaceKHR app_create_vk_surface(App* app, VkInstance inst) { App_Internal* i; VkSurfaceKHR s; VkWin32SurfaceCreateInfoKHR ci{}; VkResult r; i = app->internal; ci.sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR; ci.hwnd = i->window; ci.hinstance = g_instance; r = vkCreateWin32SurfaceKHR(inst, &ci, 0, &s); if (r != VK_SUCCESS) { print_err("Failed to create a Vulkan surface."); pbreak(r); } return s; } void app_destroy_vk_surface( App* app, VkInstance inst, VkSurfaceKHR surf ) { (void)app; vkDestroySurfaceKHR(inst, surf, 0); } } int WinMain( HINSTANCE instance, HINSTANCE pinstance, LPSTR argv, int show_cmd ) { (void)pinstance; (void)argv; (void)show_cmd; g_instance = instance; SetProcessDPIAware(); char* mem = (char*)malloc(app_memory_size); Arena* arena = (Arena*)mem; App* a; mem += sizeof * arena; init_arena(arena, mem, app_memory_size - sizeof * arena); a = entrypoint(arena); a->arena = arena; a->on_init(); while (a->running) { a->begin(); a->on_update(); a->end(); } a->on_destroy(); a->destroy(); return 0; } #endif void App::init(const char* name, Arena* a) { dt = 0.0f; arena = a; internal = (App_Internal*)arena_alloc( arena, sizeof *internal ); internal->init(this, name); } void App::destroy() { free(arena); } void App::begin() { int j; begin_t = get_time(); for (j = 0; j < key_count; j++) key_states[j] &= ~( key_state_just_pressed | key_state_just_released ); for (j = 0; j < mbtn_count; j++) mbtn_states[j] &= ~( key_state_just_pressed | key_state_just_released ); internal->begin(this); } void App::end() { end_t = get_time(); dt = (float)((double)(end_t - begin_t) / 1000000000.0); internal->end(this); } Key_State App::ks(Key k)const { return (Key_State)key_states[k]; } Key_State App::ms(Mbtn k) const { return (Key_State)mbtn_states[k]; } bool App::kp(Key k)const { return key_states[k] & key_state_pressed; } bool App::kjp(Key k) const { return key_states[k] & key_state_just_pressed; } bool App::kjr(Key k) const { return key_states[k] & key_state_just_released; } bool App::mp(Mbtn b) const { return mbtn_states[b] & key_state_pressed; } bool App::mjp(Mbtn b) const { return mbtn_states[b] & key_state_just_pressed; } bool App::mjr(Mbtn b) const { return mbtn_states[b] & key_state_just_released; } void App::get_vk_exts(const char** exts, int& count) { exts[count++] = "VK_KHR_surface"; #if defined(plat_x11) exts[count++] = "VK_KHR_xlib_surface"; #elif defined(plat_win) exts[count++] = "VK_KHR_win32_surface"; #else #error #endif }