ref: 41399234f6694133bbd64910b86ff61bce67367a
dir: /src/platform_sdl.c/
#include <SDL2/SDL.h> #include "platform.h" #include "input.h" #include "system.h" static uint64_t perf_freq = 0; static bool wants_to_exit = false; static SDL_Window *window; static SDL_AudioDeviceID audio_device; static SDL_GameController *gamepad; static void (*audio_callback)(float *buffer, uint32_t len) = NULL; uint8_t platform_sdl_gamepad_map[] = { [SDL_CONTROLLER_BUTTON_A] = INPUT_GAMEPAD_A, [SDL_CONTROLLER_BUTTON_B] = INPUT_GAMEPAD_B, [SDL_CONTROLLER_BUTTON_X] = INPUT_GAMEPAD_X, [SDL_CONTROLLER_BUTTON_Y] = INPUT_GAMEPAD_Y, [SDL_CONTROLLER_BUTTON_BACK] = INPUT_GAMEPAD_SELECT, [SDL_CONTROLLER_BUTTON_GUIDE] = INPUT_GAMEPAD_HOME, [SDL_CONTROLLER_BUTTON_START] = INPUT_GAMEPAD_START, [SDL_CONTROLLER_BUTTON_LEFTSTICK] = INPUT_GAMEPAD_L_STICK_PRESS, [SDL_CONTROLLER_BUTTON_RIGHTSTICK] = INPUT_GAMEPAD_R_STICK_PRESS, [SDL_CONTROLLER_BUTTON_LEFTSHOULDER] = INPUT_GAMEPAD_L_SHOULDER, [SDL_CONTROLLER_BUTTON_RIGHTSHOULDER] = INPUT_GAMEPAD_R_SHOULDER, [SDL_CONTROLLER_BUTTON_DPAD_UP] = INPUT_GAMEPAD_DPAD_UP, [SDL_CONTROLLER_BUTTON_DPAD_DOWN] = INPUT_GAMEPAD_DPAD_DOWN, [SDL_CONTROLLER_BUTTON_DPAD_LEFT] = INPUT_GAMEPAD_DPAD_LEFT, [SDL_CONTROLLER_BUTTON_DPAD_RIGHT] = INPUT_GAMEPAD_DPAD_RIGHT, [SDL_CONTROLLER_BUTTON_MAX] = INPUT_INVALID }; uint8_t platform_sdl_axis_map[] = { [SDL_CONTROLLER_AXIS_LEFTX] = INPUT_GAMEPAD_L_STICK_LEFT, [SDL_CONTROLLER_AXIS_LEFTY] = INPUT_GAMEPAD_L_STICK_UP, [SDL_CONTROLLER_AXIS_RIGHTX] = INPUT_GAMEPAD_R_STICK_LEFT, [SDL_CONTROLLER_AXIS_RIGHTY] = INPUT_GAMEPAD_R_STICK_UP, [SDL_CONTROLLER_AXIS_TRIGGERLEFT] = INPUT_GAMEPAD_L_TRIGGER, [SDL_CONTROLLER_AXIS_TRIGGERRIGHT] = INPUT_GAMEPAD_R_TRIGGER, [SDL_CONTROLLER_AXIS_MAX] = INPUT_INVALID }; void platform_exit() { wants_to_exit = true; } SDL_GameController *platform_find_gamepad() { for (int i = 0; i < SDL_NumJoysticks(); i++) { if (SDL_IsGameController(i)) { return SDL_GameControllerOpen(i); } } return NULL; } void platform_pump_events() { SDL_Event ev; while (SDL_PollEvent(&ev)) { // Input Keyboard if (ev.type == SDL_KEYDOWN || ev.type == SDL_KEYUP) { int code = ev.key.keysym.scancode; float state = ev.type == SDL_KEYDOWN ? 1.0 : 0.0; if (code >= SDL_SCANCODE_LCTRL && code <= SDL_SCANCODE_RALT) { int code_internal = code - SDL_SCANCODE_LCTRL + INPUT_KEY_LCTRL; input_set_button_state(code_internal, state); } else if (code > 0 && code < INPUT_KEY_MAX) { input_set_button_state(code, state); } } else if (ev.type == SDL_TEXTINPUT) { input_textinput(ev.text.text[0]); } // Gamepads connect/disconnect else if (ev.type == SDL_CONTROLLERDEVICEADDED) { gamepad = SDL_GameControllerOpen(ev.cdevice.which); } else if (ev.type == SDL_CONTROLLERDEVICEREMOVED) { if (gamepad && ev.cdevice.which == SDL_JoystickInstanceID(SDL_GameControllerGetJoystick(gamepad))) { SDL_GameControllerClose(gamepad); gamepad = platform_find_gamepad(); } } // Input Gamepad Buttons else if ( ev.type == SDL_CONTROLLERBUTTONDOWN || ev.type == SDL_CONTROLLERBUTTONUP ) { if (ev.cbutton.button < SDL_CONTROLLER_BUTTON_MAX) { button_t button = platform_sdl_gamepad_map[ev.cbutton.button]; if (button != INPUT_INVALID) { float state = ev.type == SDL_CONTROLLERBUTTONDOWN ? 1.0 : 0.0; input_set_button_state(button, state); } } } // Input Gamepad Axis else if (ev.type == SDL_CONTROLLERAXISMOTION) { float state = (float)ev.caxis.value / 32767.0; if (ev.caxis.axis < SDL_CONTROLLER_AXIS_MAX) { int code = platform_sdl_axis_map[ev.caxis.axis]; if ( code == INPUT_GAMEPAD_L_TRIGGER || code == INPUT_GAMEPAD_R_TRIGGER ) { input_set_button_state(code, state); } else if (state > 0) { input_set_button_state(code, 0.0); input_set_button_state(code+1, state); } else { input_set_button_state(code, -state); input_set_button_state(code+1, 0.0); } } } // Mouse buttons else if ( ev.type == SDL_MOUSEBUTTONDOWN || ev.type == SDL_MOUSEBUTTONUP ) { button_t button = INPUT_BUTTON_NONE; switch (ev.button.button) { case SDL_BUTTON_LEFT: button = INPUT_MOUSE_LEFT; break; case SDL_BUTTON_MIDDLE: button = INPUT_MOUSE_MIDDLE; break; case SDL_BUTTON_RIGHT: button = INPUT_MOUSE_RIGHT; break; default: break; } if (button != INPUT_BUTTON_NONE) { float state = ev.type == SDL_MOUSEBUTTONDOWN ? 1.0 : 0.0; input_set_button_state(button, state); } } // Mouse wheel else if (ev.type == SDL_MOUSEWHEEL) { button_t button = ev.wheel.y > 0 ? INPUT_MOUSE_WHEEL_UP : INPUT_MOUSE_WHEEL_DOWN; input_set_button_state(button, 1.0); input_set_button_state(button, 0.0); } // Mouse move else if (ev.type == SDL_MOUSEMOTION) { input_set_mouse_pos(ev.motion.x, ev.motion.y); } // Window Events if (ev.type == SDL_QUIT) { wants_to_exit = true; } else if ( ev.type == SDL_WINDOWEVENT && ( ev.window.event == SDL_WINDOWEVENT_SIZE_CHANGED || ev.window.event == SDL_WINDOWEVENT_RESIZED ) ) { system_resize(platform_screen_size()); } } } double platform_now() { uint64_t perf_counter = SDL_GetPerformanceCounter(); return (double)perf_counter / (double)perf_freq; } void platform_set_fullscreen(bool fullscreen) { if (fullscreen) { int32_t display = SDL_GetWindowDisplayIndex(window); SDL_DisplayMode mode; SDL_GetDesktopDisplayMode(display, &mode); SDL_SetWindowDisplayMode(window, &mode); SDL_SetWindowFullscreen(window, SDL_WINDOW_FULLSCREEN); SDL_ShowCursor(SDL_DISABLE); } else { SDL_SetWindowFullscreen(window, 0); SDL_ShowCursor(SDL_ENABLE); } } void platform_audio_callback(void* userdata, uint8_t* stream, int len) { if (audio_callback) { audio_callback((float *)stream, len/sizeof(float)); } else { memset(stream, 0, len); } } void platform_set_audio_mix_cb(void (*cb)(float *buffer, uint32_t len)) { audio_callback = cb; SDL_PauseAudioDevice(audio_device, 0); } #if defined(RENDERER_GL) // ---------------------------------------------------- #define PLATFORM_WINDOW_FLAGS SDL_WINDOW_OPENGL SDL_GLContext platform_gl; void platform_video_init() { #if defined(USE_GLES2) SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES); SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2); SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 1); #endif platform_gl = SDL_GL_CreateContext(window); SDL_GL_SetSwapInterval(1); } void platform_prepare_frame() { // nothing } void platform_video_cleanup() { SDL_GL_DeleteContext(platform_gl); } void platform_end_frame() { SDL_GL_SwapWindow(window); } vec2i_t platform_screen_size() { int width, height; SDL_GL_GetDrawableSize(window, &width, &height); return vec2i(width, height); } #elif defined(RENDERER_SOFTWARE) // ---------------------------------------------- #define PLATFORM_WINDOW_FLAGS 0 static SDL_Renderer *renderer; static SDL_Texture *screenbuffer = NULL; static void *screenbuffer_pixels = NULL; static int screenbuffer_pitch; static vec2i_t screenbuffer_size = vec2i(0, 0); static vec2i_t screen_size = vec2i(0, 0); void platform_video_init() { renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED); } void platform_video_cleanup() { } void platform_prepare_frame() { if (screen_size.x != screenbuffer_size.x || screen_size.y != screenbuffer_size.y) { if (screenbuffer) { SDL_DestroyTexture(screenbuffer); } screenbuffer = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_ABGR8888, SDL_TEXTUREACCESS_STREAMING, screen_size.x, screen_size.y); screenbuffer_size = screen_size; } SDL_LockTexture(screenbuffer, NULL, &screenbuffer_pixels, &screenbuffer_pitch); } void platform_end_frame() { screenbuffer_pixels = NULL; SDL_UnlockTexture(screenbuffer); SDL_RenderCopy(renderer, screenbuffer, NULL, NULL); SDL_RenderPresent(renderer); } rgba_t *platform_get_screenbuffer(int32_t *pitch) { *pitch = screenbuffer_pitch; return screenbuffer_pixels; } vec2i_t platform_screen_size() { int width, height; SDL_GetWindowSize(window, &width, &height); // float aspect = (float)width / (float)height; // screen_size = vec2i(240 * aspect, 240); screen_size = vec2i(width, height); return screen_size; } #else #error "Unsupported renderer for platform SDL" #endif int main(int argc, char *argv[]) { SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_JOYSTICK | SDL_INIT_GAMECONTROLLER); int gcdb_res = SDL_GameControllerAddMappingsFromFile("gamecontrollerdb.txt"); if (gcdb_res < 0) { printf("Failed to load gamecontrollerdb.txt\n"); } else { printf("load gamecontrollerdb.txt\n"); } audio_device = SDL_OpenAudioDevice(NULL, 0, &(SDL_AudioSpec){ .freq = 44100, .format = AUDIO_F32, .channels = 2, .samples = 1024, .callback = platform_audio_callback }, NULL, 0); gamepad = platform_find_gamepad(); perf_freq = SDL_GetPerformanceFrequency(); window = SDL_CreateWindow( SYSTEM_WINDOW_NAME, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, SYSTEM_WINDOW_WIDTH, SYSTEM_WINDOW_HEIGHT, SDL_WINDOW_SHOWN | SDL_WINDOW_RESIZABLE | PLATFORM_WINDOW_FLAGS | SDL_WINDOW_ALLOW_HIGHDPI ); platform_video_init(); system_init(); while (!wants_to_exit) { platform_pump_events(); platform_prepare_frame(); system_update(); platform_end_frame(); } system_cleanup(); platform_video_cleanup(); SDL_CloseAudioDevice(audio_device); SDL_Quit(); return 0; }