ref: e218b68df7d26a9394f27252ff34c1d96c38e35f
dir: /src/Backends/Platform/SDL2.cpp/
// Released under the MIT licence. // See LICENCE.txt for details. #include "../Misc.h" #include <stdarg.h> #include <stddef.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <string> #include "SDL.h" #include "../Rendering.h" #include "../Shared/SDL.h" #include "../../Attributes.h" #define DO_KEY(SDL_KEY, BACKEND_KEY) \ case SDL_KEY: \ keyboard_state[BACKEND_KEY] = event.key.type == SDL_KEYDOWN; \ break; static bool keyboard_state[BACKEND_KEYBOARD_TOTAL]; static unsigned char *cursor_surface_pixels; static SDL_Surface *cursor_surface; static SDL_Cursor *cursor; static void (*drag_and_drop_callback)(const char *path); static void (*window_focus_callback)(bool focus); bool Backend_Init(void (*drag_and_drop_callback_param)(const char *path), void (*window_focus_callback_param)(bool focus)) { drag_and_drop_callback = drag_and_drop_callback_param; window_focus_callback = window_focus_callback_param; if (SDL_Init(SDL_INIT_EVENTS) == 0) { if (SDL_InitSubSystem(SDL_INIT_VIDEO) == 0) { Backend_PrintInfo("Available SDL video drivers:"); for (int i = 0; i < SDL_GetNumVideoDrivers(); ++i) Backend_PrintInfo("%s", SDL_GetVideoDriver(i)); const char *driver = SDL_GetCurrentVideoDriver(); if (driver != NULL) { Backend_PrintInfo("Selected SDL video driver: %s", driver); return true; } else { Backend_PrintError("No SDL video driver initialized!"); } } else { std::string error_message = std::string("Could not initialise SDL video subsystem: ") + SDL_GetError(); Backend_ShowMessageBox("Fatal error", error_message.c_str()); } SDL_Quit(); } else { std::string error_message = std::string("Could not initialise SDL: ") + SDL_GetError(); Backend_ShowMessageBox("Fatal error", error_message.c_str()); } return false; } void Backend_Deinit(void) { if (cursor != NULL) SDL_FreeCursor(cursor); if (cursor_surface != NULL) SDL_FreeSurface(cursor_surface); free(cursor_surface_pixels); SDL_Quit(); } void Backend_PostWindowCreation(void) { } bool Backend_GetPaths(std::string *module_path, std::string *data_path) { #ifdef _WIN32 // SDL_GetBasePath returns a UTF-8 string, but Windows' fopen uses (extended?) ASCII. // This is apparently a problem for accented characters, as they will make fopen fail. // So, instead, we rely on argv[0], as that will put the accented characters in a // format Windows will understand. (void)module_path; (void)data_path; return false; #else char *base_path = SDL_GetBasePath(); if (base_path == NULL) return false; // Trim the trailing '/' size_t base_path_length = strlen(base_path); base_path[base_path_length - 1] = '\0'; *module_path = base_path; SDL_free(base_path); *data_path = *module_path + "/data"; return true; #endif } void Backend_HideMouse(void) { SDL_ShowCursor(SDL_DISABLE); } void Backend_SetWindowIcon(const unsigned char *rgb_pixels, size_t width, size_t height) { SDL_Surface *surface = SDL_CreateRGBSurfaceWithFormatFrom((void*)rgb_pixels, width, height, 0, width * 3, SDL_PIXELFORMAT_RGB24); if (surface != NULL) { SDL_SetWindowIcon(window, surface); SDL_FreeSurface(surface); } else { Backend_PrintError("Couldn't create RGB surface for window icon: %s", SDL_GetError()); } } void Backend_SetCursor(const unsigned char *rgba_pixels, size_t width, size_t height) { cursor_surface_pixels = (unsigned char*)malloc(width * height * 4); if (cursor_surface_pixels != NULL) { memcpy(cursor_surface_pixels, rgba_pixels, width * height * 4); cursor_surface = SDL_CreateRGBSurfaceWithFormatFrom(cursor_surface_pixels, width, height, 0, width * 4, SDL_PIXELFORMAT_RGBA32); if (cursor_surface != NULL) { cursor = SDL_CreateColorCursor(cursor_surface, 0, 0); if (cursor != NULL) SDL_SetCursor(cursor); } } else { Backend_PrintError("Failed to allocate memory for cursor surface"); } } void Backend_EnableDragAndDrop(void) { SDL_EventState(SDL_DROPFILE, SDL_ENABLE); } bool Backend_SystemTask(bool active) { if (!active) if (!SDL_WaitEvent(NULL)) return false; SDL_Event event; while (SDL_PollEvent(&event)) { switch (event.type) { case SDL_KEYUP: case SDL_KEYDOWN: switch (event.key.keysym.sym) { DO_KEY(SDLK_a, BACKEND_KEYBOARD_A) DO_KEY(SDLK_b, BACKEND_KEYBOARD_B) DO_KEY(SDLK_c, BACKEND_KEYBOARD_C) DO_KEY(SDLK_d, BACKEND_KEYBOARD_D) DO_KEY(SDLK_e, BACKEND_KEYBOARD_E) DO_KEY(SDLK_f, BACKEND_KEYBOARD_F) DO_KEY(SDLK_g, BACKEND_KEYBOARD_G) DO_KEY(SDLK_h, BACKEND_KEYBOARD_H) DO_KEY(SDLK_i, BACKEND_KEYBOARD_I) DO_KEY(SDLK_j, BACKEND_KEYBOARD_J) DO_KEY(SDLK_k, BACKEND_KEYBOARD_K) DO_KEY(SDLK_l, BACKEND_KEYBOARD_L) DO_KEY(SDLK_m, BACKEND_KEYBOARD_M) DO_KEY(SDLK_n, BACKEND_KEYBOARD_N) DO_KEY(SDLK_o, BACKEND_KEYBOARD_O) DO_KEY(SDLK_p, BACKEND_KEYBOARD_P) DO_KEY(SDLK_q, BACKEND_KEYBOARD_Q) DO_KEY(SDLK_r, BACKEND_KEYBOARD_R) DO_KEY(SDLK_s, BACKEND_KEYBOARD_S) DO_KEY(SDLK_t, BACKEND_KEYBOARD_T) DO_KEY(SDLK_u, BACKEND_KEYBOARD_U) DO_KEY(SDLK_v, BACKEND_KEYBOARD_V) DO_KEY(SDLK_w, BACKEND_KEYBOARD_W) DO_KEY(SDLK_x, BACKEND_KEYBOARD_X) DO_KEY(SDLK_y, BACKEND_KEYBOARD_Y) DO_KEY(SDLK_z, BACKEND_KEYBOARD_Z) DO_KEY(SDLK_0, BACKEND_KEYBOARD_0) DO_KEY(SDLK_1, BACKEND_KEYBOARD_1) DO_KEY(SDLK_2, BACKEND_KEYBOARD_2) DO_KEY(SDLK_3, BACKEND_KEYBOARD_3) DO_KEY(SDLK_4, BACKEND_KEYBOARD_4) DO_KEY(SDLK_5, BACKEND_KEYBOARD_5) DO_KEY(SDLK_6, BACKEND_KEYBOARD_6) DO_KEY(SDLK_7, BACKEND_KEYBOARD_7) DO_KEY(SDLK_8, BACKEND_KEYBOARD_8) DO_KEY(SDLK_9, BACKEND_KEYBOARD_9) DO_KEY(SDLK_F1, BACKEND_KEYBOARD_F1) DO_KEY(SDLK_F2, BACKEND_KEYBOARD_F2) DO_KEY(SDLK_F3, BACKEND_KEYBOARD_F3) DO_KEY(SDLK_F4, BACKEND_KEYBOARD_F4) DO_KEY(SDLK_F5, BACKEND_KEYBOARD_F5) DO_KEY(SDLK_F6, BACKEND_KEYBOARD_F6) DO_KEY(SDLK_F7, BACKEND_KEYBOARD_F7) DO_KEY(SDLK_F8, BACKEND_KEYBOARD_F8) DO_KEY(SDLK_F9, BACKEND_KEYBOARD_F9) DO_KEY(SDLK_F10, BACKEND_KEYBOARD_F10) DO_KEY(SDLK_F11, BACKEND_KEYBOARD_F11) DO_KEY(SDLK_F12, BACKEND_KEYBOARD_F12) DO_KEY(SDLK_UP, BACKEND_KEYBOARD_UP) DO_KEY(SDLK_DOWN, BACKEND_KEYBOARD_DOWN) DO_KEY(SDLK_LEFT, BACKEND_KEYBOARD_LEFT) DO_KEY(SDLK_RIGHT, BACKEND_KEYBOARD_RIGHT) DO_KEY(SDLK_ESCAPE, BACKEND_KEYBOARD_ESCAPE) DO_KEY(SDLK_BACKQUOTE, BACKEND_KEYBOARD_BACK_QUOTE) DO_KEY(SDLK_TAB, BACKEND_KEYBOARD_TAB) DO_KEY(SDLK_CAPSLOCK, BACKEND_KEYBOARD_CAPS_LOCK) DO_KEY(SDLK_LSHIFT, BACKEND_KEYBOARD_LEFT_SHIFT) DO_KEY(SDLK_LCTRL, BACKEND_KEYBOARD_LEFT_CTRL) DO_KEY(SDLK_LALT, BACKEND_KEYBOARD_LEFT_ALT) DO_KEY(SDLK_SPACE, BACKEND_KEYBOARD_SPACE) DO_KEY(SDLK_RALT, BACKEND_KEYBOARD_RIGHT_ALT) DO_KEY(SDLK_RCTRL, BACKEND_KEYBOARD_RIGHT_CTRL) DO_KEY(SDLK_RSHIFT, BACKEND_KEYBOARD_RIGHT_SHIFT) DO_KEY(SDLK_RETURN, BACKEND_KEYBOARD_ENTER) DO_KEY(SDLK_BACKSPACE, BACKEND_KEYBOARD_BACKSPACE) DO_KEY(SDLK_MINUS, BACKEND_KEYBOARD_MINUS) DO_KEY(SDLK_EQUALS, BACKEND_KEYBOARD_EQUALS) DO_KEY(SDLK_LEFTBRACKET, BACKEND_KEYBOARD_LEFT_BRACKET) DO_KEY(SDLK_RIGHTBRACKET, BACKEND_KEYBOARD_RIGHT_BRACKET) DO_KEY(SDLK_BACKSLASH, BACKEND_KEYBOARD_BACK_SLASH) DO_KEY(SDLK_SEMICOLON, BACKEND_KEYBOARD_SEMICOLON) DO_KEY(SDLK_QUOTE, BACKEND_KEYBOARD_APOSTROPHE) DO_KEY(SDLK_COMMA, BACKEND_KEYBOARD_COMMA) DO_KEY(SDLK_PERIOD, BACKEND_KEYBOARD_PERIOD) DO_KEY(SDLK_SLASH, BACKEND_KEYBOARD_FORWARD_SLASH) default: break; } break; case SDL_JOYDEVICEADDED: ControllerBackend_JoystickConnect(event.jdevice.which); break; case SDL_JOYDEVICEREMOVED: ControllerBackend_JoystickDisconnect(event.jdevice.which); break; case SDL_DROPFILE: drag_and_drop_callback(event.drop.file); SDL_free(event.drop.file); break; case SDL_WINDOWEVENT: switch (event.window.event) { case SDL_WINDOWEVENT_FOCUS_LOST: window_focus_callback(false); break; case SDL_WINDOWEVENT_FOCUS_GAINED: window_focus_callback(true); break; case SDL_WINDOWEVENT_RESIZED: case SDL_WINDOWEVENT_SIZE_CHANGED: RenderBackend_HandleWindowResize(event.window.data1, event.window.data2); break; } break; case SDL_QUIT: return false; case SDL_RENDER_TARGETS_RESET: RenderBackend_HandleRenderTargetLoss(); break; } } return true; } void Backend_GetKeyboardState(bool *out_keyboard_state) { memcpy(out_keyboard_state, keyboard_state, sizeof(keyboard_state)); } void Backend_ShowMessageBox(const char *title, const char *message) { Backend_PrintInfo("ShowMessageBox - '%s' - '%s'\n", title, message); if (SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, title, message, window) != 0) Backend_PrintError("Was also unable to display a message box containing the error: %s", SDL_GetError()); } ATTRIBUTE_FORMAT_PRINTF(1, 2) void Backend_PrintError(const char *format, ...) { va_list argumentList; va_start(argumentList, format); fputs("ERROR: ", stderr); vfprintf(stderr, format, argumentList); fputc('\n', stderr); va_end(argumentList); } ATTRIBUTE_FORMAT_PRINTF(1, 2) void Backend_PrintInfo(const char *format, ...) { va_list argumentList; va_start(argumentList, format); fputs("INFO: ", stdout); vfprintf(stdout, format, argumentList); fputc('\n', stdout); va_end(argumentList); } unsigned long Backend_GetTicks(void) { return SDL_GetTicks(); } void Backend_Delay(unsigned int ticks) { SDL_Delay(ticks); }