#include <@APP_INCLUDE@> #include #include "gfx_vulkan.hpp" #include "platform.hpp" #include #include #include #include #include #include #include #include #include @APP_CLASS@* app = nullptr; GFX* interface = nullptr; Display *dpy = nullptr; int mouse_x = -1, mouse_y = -1; bool mouse_down[2] = {false, false}; xcb_connection_t* connection = nullptr; xcb_screen_t* screen = nullptr; struct WindowConnection { xcb_connection_t* connection; xcb_window_t window; }; std::vector window_connections; xcb_intern_atom_reply_t *atom_wm_delete_window; static std::map inputToKeyCode = { { {InputButton::A, 38}, {InputButton::W, 25}, {InputButton::S, 39}, {InputButton::D, 40}, {InputButton::Q, 24} }}; /* * Platform functions" */ const char* platform::get_name() { return "Linux"; } static inline xcb_intern_atom_reply_t* intern_atom_helper(xcb_connection_t *conn, bool only_if_exists, const char *str) { xcb_intern_atom_cookie_t cookie = xcb_intern_atom(conn, only_if_exists, strlen(str), str); return xcb_intern_atom_reply(conn, cookie, NULL); } int platform::open_window(const std::string_view title, const prism::Rectangle rect, const WindowFlags flags) { auto& win = window_connections.emplace_back(); win.connection = connection; uint32_t mask; uint32_t values[32]; xcb_void_cookie_t cookie; mask = XCB_CW_BACK_PIXEL | XCB_CW_EVENT_MASK; values[0] = screen->black_pixel; values[1] = XCB_EVENT_MASK_KEY_RELEASE | XCB_EVENT_MASK_KEY_PRESS | XCB_EVENT_MASK_EXPOSURE | XCB_EVENT_MASK_STRUCTURE_NOTIFY | XCB_EVENT_MASK_POINTER_MOTION | XCB_EVENT_MASK_BUTTON_PRESS | XCB_EVENT_MASK_BUTTON_RELEASE; win.window = xcb_generate_id(connection); cookie = xcb_create_window(win.connection, XCB_COPY_FROM_PARENT, win.window, screen->root, rect.offset.x, rect.offset.y, rect.extent.width, rect.extent.height, 0, XCB_WINDOW_CLASS_INPUT_OUTPUT, screen->root_visual, mask, values); /* Magic code that will send notification when window is destroyed */ xcb_intern_atom_reply_t* reply = intern_atom_helper(connection, true, "WM_PROTOCOLS"); atom_wm_delete_window = intern_atom_helper(connection, false, "WM_DELETE_WINDOW"); xcb_change_property(connection, XCB_PROP_MODE_REPLACE, win.window, (*reply).atom, 4, 32, 1, &(*atom_wm_delete_window).atom); xcb_change_property(connection, XCB_PROP_MODE_REPLACE, win.window, XCB_ATOM_WM_NAME, XCB_ATOM_STRING, 8, title.size(), title.data()); xcb_map_window(connection, win.window); xcb_flush(connection); engine->add_window((void*)&win, 0, rect.extent); app->initialize_render(); return window_connections.size() - 1; } void platform::close_window(const int index) { } void platform::force_quit() { } float platform::get_window_dpi(const int index) { return 1.0; } float platform::get_monitor_dpi() { return 1.0; } prism::Rectangle platform::get_monitor_resolution() { } prism::Rectangle platform::get_monitor_work_area() { } prism::Offset platform::get_window_position(const int index) { } prism::Extent platform::get_window_size(const int index) { } prism::Extent platform::get_window_drawable_size(const int index) { } bool platform::is_window_focused(const int index) { } void platform::set_window_focused(const int index) { } void platform::set_window_position(const int index, const prism::Offset offset) { } void platform::set_window_size(const int index, const prism::Extent extent) { } void platform::set_window_title(const int index, const std::string_view title) { xcb_change_property(connection, XCB_PROP_MODE_REPLACE, window_connections[index].window, XCB_ATOM_WM_NAME, XCB_ATOM_STRING, 8, title.size(), title.data()); } bool platform::get_key_down(const InputButton key) { int keycode = inputToKeyCode[key]; char keys[32]; XQueryKeymap(dpy, keys); return keys[keycode/8]&(0x1<<(keycode%8)); } int platform::get_keycode(const InputButton key) { return inputToKeyCode[key]; } prism::Offset platform::get_cursor_position() { return {mouse_x, mouse_y}; } prism::Offset platform::get_screen_cursor_position() { return {mouse_x, mouse_y}; } bool platform::get_mouse_button_down(const int button) { return mouse_down[button]; } std::tuple platform::get_wheel_delta() { } std::tuple platform::get_right_stick_position() { } std::tuple platform::get_left_stick_position() { } void platform::capture_mouse(const bool capture) { } void platform::open_dialog(const bool existing, std::function returnFunction, bool openDirectory) { } void platform::save_dialog(std::function returnFunction) { } char* platform::translate_keycode(const unsigned int keycode) { char* array = new char[2]; XKeyEvent event; memset(&event, 0, sizeof(event)); event.type = 2; event.display = dpy; event.keycode = keycode; int count = XLookupString(&event, array, 1, nullptr, 0); array[1] = '\0'; return array; } int stdout_copy; int stderr_copy; void platform::mute_output() { stdout_copy = dup(STDOUT_FILENO); stderr_copy = dup(STDERR_FILENO); freopen("/dev/null", "a", stdout); freopen("/dev/null", "a", stderr); } void platform::unmute_output() { dup2(stdout_copy, STDOUT_FILENO); dup2(stderr_copy, STDERR_FILENO); close(stdout_copy); close(stderr_copy); } int main(int argc, char* argv[]) { dpy = XOpenDisplay(nullptr); const xcb_setup_t *setup; xcb_screen_iterator_t iter; int scr; connection = xcb_connect(NULL, &scr); setup = xcb_get_setup(connection); iter = xcb_setup_roots_iterator(setup); while (scr-- > 0) xcb_screen_next(&iter); screen = iter.data; engine = new Engine(argc, argv); app = new @APP_CLASS@(); engine->set_app(app); GFXCreateInfo info = {}; interface = new GFXVulkan(); if(interface->initialize(info)) { engine->set_gfx(interface); } else { return -1; } app_main(engine); while(1) { xcb_generic_event_t* event = nullptr; while((event = xcb_poll_for_event (connection))) { switch(event->response_type & 0x7f) { case XCB_CLIENT_MESSAGE: { if ((*(xcb_client_message_event_t*)event).data.data32[0] == (*atom_wm_delete_window).atom) { engine->quit(); } } break; case XCB_MOTION_NOTIFY: { auto ev = (xcb_motion_notify_event_t *)event; //engine->process_mouse_move(ev->event_x, ev->event_y); mouse_x = ev->event_x; mouse_y = ev->event_y; } break; case XCB_BUTTON_PRESS: { xcb_button_press_event_t *press = (xcb_button_press_event_t *)event; int index = 0; if(press->detail == 3) index = 1; //engine->process_mouse(index, press->event_x, press->event_y); mouse_down[index] = true; mouse_x = press->event_x; mouse_y = press->event_y; } break; case XCB_BUTTON_RELEASE: { xcb_button_press_event_t *press = (xcb_button_press_event_t *)event; int index = 0; if(press->detail == 3) index = 1; //engine->process_mouse_released(index); mouse_down[index] = false; } break; case XCB_CONFIGURE_NOTIFY: { const xcb_configure_notify_event_t *cfgEvent = (const xcb_configure_notify_event_t *)event; engine->resize(0, {cfgEvent->width, cfgEvent->height}); } break; case XCB_KEY_PRESS: { const xcb_key_release_event_t *keyEvent = (const xcb_key_release_event_t *)event; //engine->process_key(keyEvent->detail); } break; case XCB_KEY_RELEASE: { const xcb_key_release_event_t *keyEvent = (const xcb_key_release_event_t *)event; //engine->process_key_up(keyEvent->detail); } break; } free(event); } if(engine->is_quitting()) break; engine->update(1.0 / 60.0); engine->begin_frame(1.0 / 60.0); engine->render(0); } return 0; } PlatformTheme platform::get_theme() { return PlatformTheme::Light; }