rtengine/src/runtime/app.c
2023-12-10 23:09:19 +01:00

273 lines
7.7 KiB
C

#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 <Windows.h>
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 <X11/Xlib.h>
#include <assert.h>
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