273 lines
8.1 KiB
C
273 lines
8.1 KiB
C
#include "app.h"
|
|
#include "main_loop.h"
|
|
|
|
#include "runtime/aio.h"
|
|
#include "runtime/buffer_manager.h"
|
|
#include "runtime/config.h"
|
|
|
|
#include "renderer/common/renderer_api.h"
|
|
|
|
#include <stdbool.h>
|
|
|
|
RT_CVAR_I(rt_Fullscreen, "Show window in fullscreen mode. [0/1] Default: 0", 1);
|
|
RT_CVAR_I(rt_WindowWidth, "Window width. Default: 1024", 1024);
|
|
RT_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);
|
|
}
|
|
}
|
|
|
|
RT_DLLEXPORT int rtWin32Entry(HINSTANCE hInstance,
|
|
HINSTANCE hPrevInstance,
|
|
PWSTR pCmdLine,
|
|
int nCmdShow,
|
|
rt_app_callbacks app_callbacks) {
|
|
if (rtInitRuntime() != RT_SUCCESS)
|
|
return 1;
|
|
|
|
rtRegisterCVAR(&rt_Fullscreen);
|
|
rtRegisterCVAR(&rt_WindowWidth);
|
|
rtRegisterCVAR(&rt_WindowHeight);
|
|
|
|
if (app_callbacks.RegisterCVars)
|
|
app_callbacks.RegisterCVars();
|
|
|
|
WNDCLASSEXW wndclass = {
|
|
.cbSize = sizeof(wndclass),
|
|
.hInstance = hInstance,
|
|
.lpszClassName = L"rtWndClass",
|
|
.style = CS_OWNDC,
|
|
.lpfnWndProc = win32WndProc,
|
|
};
|
|
if (!RegisterClassExW(&wndclass)) {
|
|
rtReportError("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"rtWndClass",
|
|
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"rtWndClass",
|
|
L"Voyage",
|
|
WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU,
|
|
CW_USEDEFAULT,
|
|
CW_USEDEFAULT,
|
|
w,
|
|
h,
|
|
NULL,
|
|
NULL,
|
|
hInstance,
|
|
NULL);
|
|
ShowWindow(wnd, SW_SHOW);
|
|
}
|
|
|
|
if (!wnd) {
|
|
rtReportError("CORE", "Failed to create the game window: %u", GetLastError());
|
|
return 1;
|
|
}
|
|
|
|
unsigned int window_width, window_height;
|
|
{
|
|
RECT r;
|
|
GetClientRect(wnd, &r);
|
|
window_width = r.right;
|
|
window_height = r.bottom;
|
|
}
|
|
rt_renderer_init_info renderer_info = {.hWnd = wnd,
|
|
.hInstance = hInstance,
|
|
.width = window_width,
|
|
.height = window_height,
|
|
.is_fullscreen = rt_Fullscreen.i};
|
|
if (rtLoadRenderer() != RT_SUCCESS) {
|
|
return 1;
|
|
}
|
|
if (g_renderer.Init(&renderer_info) != RT_SUCCESS) {
|
|
return 1;
|
|
}
|
|
|
|
app_callbacks.Init();
|
|
|
|
if (rtInitMainLoop(app_callbacks.Update, app_callbacks.Render) != RT_SUCCESS) {
|
|
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);
|
|
}
|
|
}
|
|
}
|
|
|
|
app_callbacks.Shutdown();
|
|
rtShutdownMainLoop();
|
|
g_renderer.Shutdown();
|
|
DestroyWindow(wnd);
|
|
UnregisterClassW(L"rtWndClass", hInstance);
|
|
|
|
rtShutdownRuntime();
|
|
|
|
return 0;
|
|
}
|
|
|
|
#elif defined(RT_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) {
|
|
rtLog("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)) {
|
|
rtReportError("CORE", "Failed to send x11 fullscreen event.");
|
|
}
|
|
|
|
#undef _NET_WM_STATE_ADD
|
|
#undef _NET_WM_STATE_REMOVE
|
|
#undef EVENT_SOURCE_APPLICATION
|
|
}
|
|
|
|
RT_DLLEXPORT int rtXlibEntry(int argc, char **argv, rt_app_callbacks app_callbacks) {
|
|
if (rtInitRuntime() != RT_SUCCESS)
|
|
return 1;
|
|
|
|
if (app_callbacks.RegisterCVars)
|
|
app_callbacks.RegisterCVars();
|
|
|
|
Display *dpy = XOpenDisplay(NULL);
|
|
if (!dpy) {
|
|
rtReportError("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) {
|
|
rtReportError("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);
|
|
|
|
rt_renderer_init_info renderer_info = {.display = dpy, .window = window};
|
|
if (!rtInitGFX(&renderer_info)) {
|
|
rtReportError("GFX", "Init failed.");
|
|
return 1;
|
|
}
|
|
|
|
app_callbacks.Init();
|
|
|
|
/* 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) {
|
|
rtLog("CORE", "Received WM_DELETE_WINDOW");
|
|
keep_running = false;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
app_callbacks.Shutdown();
|
|
|
|
XDestroyWindow(dpy, window);
|
|
XCloseDisplay(dpy);
|
|
rtShutdownRuntime();
|
|
|
|
return 0;
|
|
}
|
|
|
|
#endif
|