#include #include #include #include #include // Analog camera movement by Pathétique (github.com/vrmiguel), y0shin and Mors // Contribute or communicate bugs at github.com/vrmiguel/sm64-analog-camera #include #include "controller_api.h" extern int16_t rightx; extern int16_t righty; #ifdef BETTERCAMERA int mouse_x; int mouse_y; extern u8 newcam_mouse; #endif static bool init_ok; static SDL_GameController *sdl_cntrl; static void controller_sdl_init(void) { if (SDL_Init(SDL_INIT_GAMECONTROLLER | SDL_INIT_EVENTS) != 0) { fprintf(stderr, "SDL init error: %s\n", SDL_GetError()); return; } #ifdef BETTERCAMERA if (newcam_mouse == 1) SDL_SetRelativeMouseMode(SDL_TRUE); SDL_GetRelativeMouseState(&mouse_x, &mouse_y); #endif init_ok = true; } static void controller_sdl_read(OSContPad *pad) { if (!init_ok) { return; } #ifdef BETTERCAMERA if (newcam_mouse == 1) SDL_SetRelativeMouseMode(SDL_TRUE); else SDL_SetRelativeMouseMode(SDL_FALSE); SDL_GetRelativeMouseState(&mouse_x, &mouse_y); #endif SDL_GameControllerUpdate(); if (sdl_cntrl != NULL && !SDL_GameControllerGetAttached(sdl_cntrl)) { SDL_GameControllerClose(sdl_cntrl); sdl_cntrl = NULL; } if (sdl_cntrl == NULL) { for (int i = 0; i < SDL_NumJoysticks(); i++) { if (SDL_IsGameController(i)) { sdl_cntrl = SDL_GameControllerOpen(i); if (sdl_cntrl != NULL) { break; } } } if (sdl_cntrl == NULL) { return; } } if (SDL_GameControllerGetButton(sdl_cntrl, SDL_CONTROLLER_BUTTON_START)) pad->button |= START_BUTTON; if (SDL_GameControllerGetButton(sdl_cntrl, SDL_CONTROLLER_BUTTON_LEFTSHOULDER)) pad->button |= Z_TRIG; if (SDL_GameControllerGetButton(sdl_cntrl, SDL_CONTROLLER_BUTTON_RIGHTSHOULDER)) pad->button |= R_TRIG; if (SDL_GameControllerGetButton(sdl_cntrl, SDL_CONTROLLER_BUTTON_A)) pad->button |= A_BUTTON; if (SDL_GameControllerGetButton(sdl_cntrl, SDL_CONTROLLER_BUTTON_X)) pad->button |= B_BUTTON; int16_t leftx = SDL_GameControllerGetAxis(sdl_cntrl, SDL_CONTROLLER_AXIS_LEFTX); int16_t lefty = SDL_GameControllerGetAxis(sdl_cntrl, SDL_CONTROLLER_AXIS_LEFTY); rightx = SDL_GameControllerGetAxis(sdl_cntrl, SDL_CONTROLLER_AXIS_RIGHTX); righty = SDL_GameControllerGetAxis(sdl_cntrl, SDL_CONTROLLER_AXIS_RIGHTY); int16_t ltrig = SDL_GameControllerGetAxis(sdl_cntrl, SDL_CONTROLLER_AXIS_TRIGGERLEFT); int16_t rtrig = SDL_GameControllerGetAxis(sdl_cntrl, SDL_CONTROLLER_AXIS_TRIGGERRIGHT); #ifdef TARGET_WEB // Firefox has a bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1606562 // It sets down y to 32768.0f / 32767.0f, which is greater than the allowed 1.0f, // which SDL then converts to a int16_t by multiplying by 32767.0f, which overflows into -32768. // Maximum up will hence never become -32768 with the current version of SDL2, // so this workaround should be safe in compliant browsers. if (lefty == -32768) { lefty = 32767; } if (righty == -32768) { righty = 32767; } #endif if (rightx < -0x4000) pad->button |= L_CBUTTONS; if (rightx > 0x4000) pad->button |= R_CBUTTONS; if (righty < -0x4000) pad->button |= U_CBUTTONS; if (righty > 0x4000) pad->button |= D_CBUTTONS; if (ltrig > 30 * 256) pad->button |= Z_TRIG; if (rtrig > 30 * 256) pad->button |= R_TRIG; uint32_t magnitude_sq = (uint32_t)(leftx * leftx) + (uint32_t)(lefty * lefty); if (magnitude_sq > (uint32_t)(DEADZONE * DEADZONE)) { pad->stick_x = leftx / 0x100; int stick_y = -lefty / 0x100; pad->stick_y = stick_y == 128 ? 127 : stick_y; } } struct ControllerAPI controller_sdl = { controller_sdl_init, controller_sdl_read };