#include "app.h" #include "aio.h" #include "buffer_manager.h" #include "config.h" #include "gfx.h" #include "renderer_api.h" extern void __RegisterRuntimeCVars(void); VY_CVAR_I(rt_Fullscreen, "Show window in fullscreen mode. [0/1] Default: 0", 0); VY_CVAR_I(rt_WindowWidth, "Window width. Default: 1024", 1024); VY_CVAR_I(rt_WindowHeight, "Window height. Default: 768", 768); #ifdef _WIN32 #define WIN32_LEAN_AND_MEAN #include static LRESULT CALLBACK win32WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { switch (uMsg) { case WM_CLOSE: PostQuitMessage(0); return 0; default: return DefWindowProcW(hWnd, uMsg, wParam, lParam); } } VY_DLLEXPORT int vyWin32Entry(HINSTANCE hInstance, HINSTANCE hPrevInstance, PWSTR pCmdLine, int nCmdShow) { __RegisterRuntimeCVars(); vyRegisterRendererCVars(); /* TODO: Parse the cvar config file */ if (vyInitBufferManager() != VY_SUCCESS) { vyReportError("BUFFERMGR", "Init failed."); return 1; } if (vyInitFileTab(1024) != VY_SUCCESS) { vyReportError("FTAB", "Init failed."); return 1; } if (vyInitAIO(0) != VY_SUCCESS) { vyReportError("AIO", "Init failed."); return 1; } WNDCLASSEXW wndclass = { .cbSize = sizeof(wndclass), .hInstance = hInstance, .lpszClassName = L"vyWndClass", .style = CS_OWNDC, .lpfnWndProc = win32WndProc, }; if (!RegisterClassExW(&wndclass)) { vyReportError("CORE", "RegisterClassEx failed: %u", GetLastError()); return 1; } HWND wnd = NULL; if (rt_Fullscreen.i) { /* Fullscreen window */ int w = GetSystemMetrics(SM_CXSCREEN); int h = GetSystemMetrics(SM_CYSCREEN); wnd = CreateWindowExW(WS_EX_APPWINDOW, L"vyWndClass", L"Voyage", WS_POPUP, 0, 0, w, h, NULL, NULL, hInstance, NULL); ShowWindow(wnd, SW_SHOW); } else { /* Windowed mode */ int w = rt_WindowWidth.i; int h = rt_WindowHeight.i; wnd = CreateWindowExW(WS_EX_APPWINDOW, L"vyWndClass", L"Voyage", WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU, CW_USEDEFAULT, CW_USEDEFAULT, w, h, NULL, NULL, hInstance, NULL); ShowWindow(wnd, SW_SHOW); } if (!wnd) { vyReportError("CORE", "Failed to create the game window: %u", GetLastError()); return 1; } vy_renderer_init_info renderer_info = {.hWnd = wnd, .hInstance = hInstance}; if (!vyInitGFX(&renderer_info)) { vyReportError("GFX", "Init failed."); return 1; } /* Main Loop */ bool keep_running = true; while (keep_running) { MSG msg; while (PeekMessageW(&msg, NULL, 0, 0, PM_REMOVE)) { if (msg.message == WM_QUIT) { keep_running = false; } else { TranslateMessage(&msg); DispatchMessageW(&msg); } } } vyShutdownGFX(); DestroyWindow(wnd); UnregisterClassW(L"vyWndClass", hInstance); vyShutdownAIO(); vyShutdownAIO(); vyShutdownFileTab(); vyShutdownBufferManager(); return 0; } #elif defined(VY_USE_XLIB) #include #include static void xlibSetFullscreen(Display *dpy, int screen, Window window, bool enable) { Atom wm_state = XInternAtom(dpy, "_NET_W_STATE", False); Atom wm_fullscreen = XInternAtom(dpy, "_NET_WM_STATE_FULLSCREEN", False); if (wm_state == None || wm_fullscreen == None) { vyLog("CORE", "Window manager does not support fullscreen mode."); return; } #define _NET_WM_STATE_REMOVE 0 #define _NET_WM_STATE_ADD 1 #define EVENT_SOURCE_APPLICATION 1 XEvent ev; ev.type = ClientMessage; ev.xclient.display = dpy; ev.xclient.window = window; ev.xclient.message_type = wm_state; ev.xclient.format = 32; ev.xclient.data.l[0] = (enable) ? _NET_WM_STATE_ADD : _NET_WM_STATE_REMOVE; ev.xclient.data.l[1] = wm_fullscreen; ev.xclient.data.l[2] = 0; ev.xclient.data.l[3] = EVENT_SOURCE_APPLICATION; ev.xclient.data.l[4] = 0; Window root_window = XRootWindow(dpy, screen); long ev_mask = SubstructureRedirectMask; if (!XSendEvent(dpy, root_window, False, ev_mask, &ev)) { vyReportError("CORE", "Failed to send x11 fullscreen event."); } #undef _NET_WM_STATE_ADD #undef _NET_WM_STATE_REMOVE #undef EVENT_SOURCE_APPLICATION } VY_DLLEXPORT int vyXlibEntry(int argc, char **argv) { __RegisterRuntimeCVars(); vyRegisterRendererCVars(); if (vyInitBufferManager() != VY_SUCCESS) { vyReportError("BUFFERMGR", "Init failed."); return 1; } if (vyInitFileTab(1024) != VY_SUCCESS) { vyReportError("FTAB", "Init failed."); return 1; } if (vyInitAIO(0) != VY_SUCCESS) { vyReportError("AIO", "Init failed."); return 1; } Display *dpy = XOpenDisplay(NULL); if (!dpy) { vyReportError("CORE", "Failed to open default display"); return 1; } int screen = DefaultScreen(dpy); Window window; int w = rt_WindowWidth.i; int h = rt_WindowHeight.i; window = XCreateSimpleWindow(dpy, RootWindow(dpy, screen), 10, 10, w, h, 1, BlackPixel(dpy, screen), WhitePixel(dpy, screen)); XSelectInput(dpy, window, KeyPressMask); XMapWindow(dpy, window); XStoreName(dpy, window, "Voyage"); Atom wm_close = XInternAtom(dpy, "WM_DELETE_WINDOW", False); if (!wm_close) { vyReportError("CORE", "Failed to find WM_DELETE_WINDOW atom."); XDestroyWindow(dpy, window); XCloseDisplay(dpy); return 1; } XSetWMProtocols(dpy, window, &wm_close, 1); if (rt_Fullscreen.i) xlibSetFullscreen(dpy, screen, window, true); vy_renderer_init_info renderer_info = {.display = dpy, .window = window}; if (!vyInitGFX(&renderer_info)) { vyReportError("GFX", "Init failed."); return 1; } /* Main Loop */ bool keep_running = true; while (keep_running) { while (XEventsQueued(dpy, QueuedAlready) > 0) { XEvent event; XNextEvent(dpy, &event); switch (event.type) { case KeyPress: break; case ButtonPressMask: /* Mouse down */ break; case PointerMotionMask: /* Mouse movement */ break; case ClientMessage: if (event.xclient.data.l[0] == (long)wm_close) { vyLog("CORE", "Received WM_DELETE_WINDOW"); keep_running = false; } break; } } } vyShutdownGFX(); XDestroyWindow(dpy, window); XCloseDisplay(dpy); vyShutdownAIO(); vyShutdownFileTab(); vyShutdownBufferManager(); return 0; } #endif