void Controls_JoyRumble(float power, int time) { // JoyRumble is a simple wrapper for SDL's haptic rumble play. if(sdl_haptic) SDL_HapticRumblePlay(sdl_haptic, power, time); }
void JoystickControl::JoyPressed(){ //X axis motion if(evento->type == SDL_JOYAXISMOTION){ if( evento->jaxis.axis == 0 ){ //Left of dead zone if( evento->jaxis.value < -JOYSTICK_DEAD_ZONE ){ personaje->CaminarIzquierda(); } //Right of dead zone else if( evento->jaxis.value > JOYSTICK_DEAD_ZONE ){ personaje->CaminarDerecha(); } else{ //NO SE } } //Y axis motion else if( evento->jaxis.axis == 1 ){ //arriba if( evento->jaxis.value < -JOYSTICK_DEAD_ZONE ){ personaje->Saltar(); } //abajo else if( evento->jaxis.value > JOYSTICK_DEAD_ZONE){ personaje->Agachar(); } else{ //NADA } } } //Boton else if (evento->type == SDL_JOYBUTTONUP){ int boton = evento->jbutton.button; if (boton == comandos->operator[](PATADA_BAJA) ) personaje->pinaBaja(); else if( boton == comandos->operator [](PINA_ALTA)){ personaje->pinaAlta(); if (SDL_JoystickGetAxis(joystick,1) > JOYSTICK_DEAD_ZONE ) if (joystickHaptic != NULL) SDL_HapticRumblePlay( joystickHaptic, 0.75, 700 ); } else if ( boton == comandos->operator [](PATADA_BAJA)){ personaje->patadaBaja(); } else if ( boton == comandos->operator [](PATADA_ALTA)){ personaje->patadaAlta(); } else if ( boton == comandos->operator [](CUBRIRSE)){ personaje->cubrirse(); } else if ( boton == comandos->operator [](LANZAR_ARMA)){ //personaje->lanzarObjeto(); } else if ( boton == JOY_START){ pausa = !pausa; } } }
/****** Start haptic force-feedback on joypad ******/ void DMG_GamePad::start_rumble() { if((jstick != NULL) && (rumble != NULL) && (is_rumbling == false)) { SDL_HapticRumblePlay(rumble, 1, -1); is_rumbling = true; } }
void SDL2EventHandler::hapticInsert( const CIHapticEvent& e, C_UNUSED(c_cptr data)) { if(getSDL2Context()) SDL_HapticRumblePlay( getSDL2Context()->haptics[e.rumble_input.index], e.rumble_input.strength, e.rumble_input.duration); }
void setControllerVibration(u32 controllerIndex, f32 amount, Time duration) { if (g_rumbleHandles[controllerIndex]) { SDL_HapticRumblePlay(g_rumbleHandles[controllerIndex], Math::clamp<f32>(amount, 0, 1), duration.asMilliseconds()); } }
void setControllerVibration(u32 controllerIndex, f32 amount) { if (g_rumbleHandles[controllerIndex]) { SDL_HapticRumblePlay(g_rumbleHandles[controllerIndex], Math::clamp<f32>(amount, 0, 1), SDL_HAPTIC_INFINITY); } }
bool SDLFrontend::rumble (float strength, int lengthMillis) { if (!_haptic) { return false; } if (SDL_HapticRumblePlay(_haptic, strength, lengthMillis) != 0) { sdlCheckError(); return false; } return true; }
void JoystickInfo::TestForce() { #if SDL_MAJOR_VERSION >= 2 // This code just use standard rumble to check that SDL handles the pad correctly! --3kinox if(haptic == NULL) return; // Otherwise, core dump! SDL_HapticRumbleInit( haptic ); // Make the haptic pad rumble 60% strength for half a second, shoudld be enough for user to see if it works or not if( SDL_HapticRumblePlay( haptic, 0.60, 400 ) != 0) { fprintf(stderr,"ERROR: Rumble is not working! %s\n",SDL_GetError()); } #endif }
void I_GamepadVibration(int strength) { if (haptic && (lasteventtype == ev_gamepad || lasteventtype == ev_none)) { static int currentstrength; if (strength >= currentstrength || strength == idlevibrationstrength) { currentstrength = MIN(strength, UINT16_MAX); SDL_HapticRumblePlay(haptic, (float)strength / MAXVIBRATIONSTRENGTH, 600000); } } }
int main( int argc, char* args[] ) { //Start up SDL and create window if( !init() ) { printf( "Failed to initialize!\n" ); } else { //Load media if( !loadMedia() ) { printf( "Failed to load media!\n" ); } else { //Main loop flag bool quit = false; //Event handler SDL_Event e; //While application is running while( !quit ) { //Handle events on queue while( SDL_PollEvent( &e ) != 0 ) { //User requests quit if( e.type == SDL_QUIT ) { quit = true; } //Joystick button press else if( e.type == SDL_JOYBUTTONDOWN ) { //Play rumble at 75% strenght for 500 milliseconds if( SDL_HapticRumblePlay( gControllerHaptic, 0.75, 500 ) != 0 ) { printf( "Warning: Unable to play rumble! %s\n", SDL_GetError() ); } } } //Clear screen SDL_SetRenderDrawColor( gRenderer, 0xFF, 0xFF, 0xFF, 0xFF ); SDL_RenderClear( gRenderer ); //Render splash image gSplashTexture.render( 0, 0 ); //Update screen SDL_RenderPresent( gRenderer ); } } } //Free resources and close SDL close(); return 0; }
// Checks throttle to see if we should accelerate or decelerate the vehicle void checkAccel() { float rate = MAX_SPEED / (ACCEL_RATE * 100); // Updated every 10 ms if(currentTime > lastAccel + 10) { if(throttle < 0) { current_speed -= rate; if(current_speed < 1) current_speed = 0; } else if(throttle > 0) { current_speed += rate; if(current_speed > MAX_SPEED) { // Limiter current_speed = MAX_SPEED; if(gHaptic != NULL) {SDL_HapticRumblePlay( gHaptic, 0.5, 1000); printf("DEBUG HAPTIC\n"); } } } send_speed(); lastAccel = currentTime; } }
int JoyHapticRumble(int pad, uint32_t low, uint32_t high) { #if 0 float mag; if (g.PadState[pad].haptic) { /* Stop the effect if it was playing. */ SDL_HapticRumbleStop(g.PadState[pad].haptic); mag = ((high * 2 + low) / 6) / 127.5; //printf("low: %d high: %d mag: %f\n", low, high, mag); if (SDL_HapticRumblePlay(g.PadState[pad].haptic, mag, 500) != 0) { printf("\nFailed to play rumble: %s\n", SDL_GetError()); return 1; } } #endif return 0; }
bool DEV_Joystick::RumblePlay(float strength, int duration) { #ifdef WITH_SDL if (m_private->m_haptic == NULL) { return false; } // Initialize simple rumble if (SDL_HapticRumbleInit(m_private->m_haptic) != 0) { return false; } // Play effect at strength for m_duration milliseconds if (SDL_HapticRumblePlay(m_private->m_haptic, strength, duration) != 0) { return false; } return true; #endif // WITH_SDL return false; }
void test_rumble(int joy_idx) { SDL_Joystick* joy = SDL_JoystickOpen(joy_idx); if (!joy) { fprintf(stderr, "Unable to open joystick %d\n", joy_idx); } else { SDL_Haptic* haptic = SDL_HapticOpenFromJoystick(joy); if (!haptic) { fprintf(stderr, "Unable to open haptic on joystick %d\n", joy_idx); fprintf(stderr, "SDL_Error: %s\n", SDL_GetError()); } else { if (!SDL_HapticRumbleSupported(haptic)) { fprintf(stderr, "rumble not supported on joystick %d\n", joy_idx); } else { if (SDL_HapticRumbleInit(haptic) != 0) { fprintf(stderr, "failed to init rumble\n"); } else { SDL_HapticRumblePlay(haptic, 1.0, 3000); SDL_Delay(3000); } } SDL_HapticClose(haptic); } SDL_JoystickClose(joy); } }
int main(int argc, char *argv[]) { SDL_Joystick *joystick = NULL; SDL_Haptic *haptic = NULL; SDL_JoystickID instance = -1; SDL_bool keepGoing = SDL_TRUE; int i; SDL_bool enable_haptic = SDL_TRUE; Uint32 init_subsystems = SDL_INIT_VIDEO | SDL_INIT_JOYSTICK; for (i = 1; i < argc; ++i) { if (SDL_strcasecmp(argv[i], "--nohaptic") == 0) { enable_haptic = SDL_FALSE; } } if(enable_haptic) { init_subsystems |= SDL_INIT_HAPTIC; } /* Enable standard application logging */ SDL_LogSetPriority(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_INFO); SDL_SetHint(SDL_HINT_JOYSTICK_ALLOW_BACKGROUND_EVENTS, "1"); /* Initialize SDL (Note: video is required to start event loop) */ if (SDL_Init(init_subsystems) < 0) { SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't initialize SDL: %s\n", SDL_GetError()); exit(1); } //SDL_CreateWindow("Dummy", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 128, 128, 0); SDL_Log("There are %d joysticks at startup\n", SDL_NumJoysticks()); if (enable_haptic) SDL_Log("There are %d haptic devices at startup\n", SDL_NumHaptics()); while(keepGoing) { SDL_Event event; while(SDL_PollEvent(&event)) { switch(event.type) { case SDL_QUIT: keepGoing = SDL_FALSE; break; case SDL_JOYDEVICEADDED: if (joystick != NULL) { SDL_Log("Only one joystick supported by this test\n"); } else { joystick = SDL_JoystickOpen(event.jdevice.which); instance = SDL_JoystickInstanceID(joystick); SDL_Log("Joy Added : %d : %s\n", event.jdevice.which, SDL_JoystickName(joystick)); if (enable_haptic) { if (SDL_JoystickIsHaptic(joystick)) { haptic = SDL_HapticOpenFromJoystick(joystick); if (haptic) { SDL_Log("Joy Haptic Opened\n"); if (SDL_HapticRumbleInit( haptic ) != 0) { SDL_Log("Could not init Rumble!: %s\n", SDL_GetError()); SDL_HapticClose(haptic); haptic = NULL; } } else { SDL_Log("Joy haptic open FAILED!: %s\n", SDL_GetError()); } } else { SDL_Log("No haptic found\n"); } } } break; case SDL_JOYDEVICEREMOVED: if (instance == event.jdevice.which) { SDL_Log("Joy Removed: %d\n", event.jdevice.which); instance = -1; if(enable_haptic && haptic) { SDL_HapticClose(haptic); haptic = NULL; } SDL_JoystickClose(joystick); joystick = NULL; } else { SDL_Log("Unknown joystick diconnected\n"); } break; case SDL_JOYAXISMOTION: // SDL_Log("Axis Move: %d\n", event.jaxis.axis); if (enable_haptic) SDL_HapticRumblePlay(haptic, 0.25, 250); break; case SDL_JOYBUTTONDOWN: SDL_Log("Button Press: %d\n", event.jbutton.button); if(enable_haptic && haptic) { SDL_HapticRumblePlay(haptic, 0.25, 250); } if (event.jbutton.button == 0) { SDL_Log("Exiting due to button press of button 0\n"); keepGoing = SDL_FALSE; } break; case SDL_JOYBUTTONUP: SDL_Log("Button Release: %d\n", event.jbutton.button); break; } } } SDL_Quit(); return 0; }
s32 proc() { #if _WIN32 SetProcessDPIAware(); #endif #if defined(__APPLE__) SDL_SetHint(SDL_HINT_MOUSE_RELATIVE_MODE_WARP, "1"); #endif // Initialize SDL if (SDL_Init( SDL_INIT_VIDEO | SDL_INIT_EVENTS | SDL_INIT_GAMECONTROLLER | SDL_INIT_HAPTIC | SDL_INIT_TIMER | SDL_INIT_JOYSTICK ) < 0) { fprintf(stderr, "Failed to initialize SDL: %s\n", SDL_GetError()); return -1; } Loader::data_directory = SDL_GetPrefPath("HelveticaScenario", "Yearning"); SDL_GameControllerAddMappingsFromFile("gamecontrollerdb.txt"); SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE); SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 4); SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 1); SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 0); { SDL_DisplayMode display; SDL_GetDesktopDisplayMode(0, &display); Loader::settings_load(display.w, display.h); } if (SDL_SetRelativeMouseMode(SDL_TRUE) != 0) { fprintf(stderr, "Failed to set relative mouse mode: %s\n", SDL_GetError()); return -1; } window = SDL_CreateWindow ( "The Yearning", 0, 0, Settings::width, Settings::height, SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN | SDL_WINDOW_INPUT_GRABBED | SDL_WINDOW_INPUT_FOCUS | SDL_WINDOW_MOUSE_FOCUS | SDL_WINDOW_MOUSE_CAPTURE | SDL_WINDOW_ALLOW_HIGHDPI | (Settings::fullscreen ? SDL_WINDOW_FULLSCREEN : SDL_WINDOW_BORDERLESS) ); #if defined(__APPLE__) SDL_SetWindowGrab(window, SDL_TRUE); #endif // Open a window and create its OpenGL context if (!window) { fprintf(stderr, "Failed to open SDL window. Most likely your GPU is out of date! %s\n", SDL_GetError()); SDL_Quit(); return -1; } SDL_GLContext context = SDL_GL_CreateContext(window); if (!context) { fprintf(stderr, "Failed to create GL context: %s\n", SDL_GetError()); return -1; } if (SDL_GL_SetSwapInterval(Settings::vsync ? 1 : 0) != 0) { fprintf(stderr, "Failed to set OpenGL swap interval: %s\n", SDL_GetError()); return -1; } { glewExperimental = true; // Needed for core profile GLenum glew_result = glewInit(); if (glew_result != GLEW_OK) { fprintf(stderr, "Failed to initialize GLEW: %s\n", glewGetErrorString(glew_result)); return -1; } } glGetError(); // Clear initial error caused by GLEW render_init(); // Launch threads Sync<LoopSync> render_sync; LoopSwapper swapper_render_update = render_sync.swapper(0); LoopSwapper swapper_render = render_sync.swapper(1); Sync<PhysicsSync, 1> physics_sync; PhysicsSwapper swapper_physics = physics_sync.swapper(); PhysicsSwapper swapper_physics_update = physics_sync.swapper(); std::thread thread_physics(Physics::loop, &swapper_physics); std::thread thread_update(Loop::loop, &swapper_render_update, &swapper_physics_update); std::thread thread_ai(AI::loop); LoopSync* sync = swapper_render.get(); r64 last_time = SDL_GetTicks() / 1000.0; b8 has_focus = true; SDL_PumpEvents(); const u8* sdl_keys = SDL_GetKeyboardState(0); refresh_controllers(); while (true) { render(sync); // Swap buffers SDL_GL_SwapWindow(window); SDL_PumpEvents(); memcpy(sync->input.keys, sdl_keys, sizeof(sync->input.keys)); sync->input.keys[(s32)KeyCode::MouseWheelDown] = false; sync->input.keys[(s32)KeyCode::MouseWheelUp] = false; SDL_Event sdl_event; while (SDL_PollEvent(&sdl_event)) { if (sdl_event.type == SDL_QUIT) sync->quit = true; else if (sdl_event.type == SDL_MOUSEWHEEL) { b8 up = sdl_event.wheel.y > 0; if (sdl_event.wheel.direction == SDL_MOUSEWHEEL_FLIPPED) up = !up; if (up) sync->input.keys[(s32)KeyCode::MouseWheelUp] = true; else sync->input.keys[(s32)KeyCode::MouseWheelDown] = true; } else if (sdl_event.type == SDL_JOYDEVICEADDED || sdl_event.type == SDL_JOYDEVICEREMOVED) refresh_controllers(); else if (sdl_event.type == SDL_WINDOWEVENT) { if (sdl_event.window.event == SDL_WINDOWEVENT_FOCUS_GAINED) has_focus = true; else if (sdl_event.window.event == SDL_WINDOWEVENT_FOCUS_LOST) has_focus = false; } } sync->input.focus = has_focus; s32 mouse_buttons = SDL_GetRelativeMouseState(&sync->input.cursor_x, &sync->input.cursor_y); sync->input.keys[(s32)KeyCode::MouseLeft] = mouse_buttons & (1 << 0); sync->input.keys[(s32)KeyCode::MouseMiddle] = mouse_buttons & (1 << 1); sync->input.keys[(s32)KeyCode::MouseRight] = mouse_buttons & (1 << 2); s32 active_gamepads = 0; for (s32 i = 0; i < MAX_GAMEPADS; i++) { SDL_GameController* controller = controllers[i]; Gamepad* gamepad = &sync->input.gamepads[i]; gamepad->active = controller != 0; gamepad->btns = 0; if (gamepad->active) { gamepad->left_x = (r32)SDL_GameControllerGetAxis(controller, SDL_CONTROLLER_AXIS_LEFTX) / 32767.0f; gamepad->left_y = (r32)SDL_GameControllerGetAxis(controller, SDL_CONTROLLER_AXIS_LEFTY) / 32767.0f; gamepad->right_x = (r32)SDL_GameControllerGetAxis(controller, SDL_CONTROLLER_AXIS_RIGHTX) / 32767.0f; gamepad->right_y = (r32)SDL_GameControllerGetAxis(controller, SDL_CONTROLLER_AXIS_RIGHTY) / 32767.0f; gamepad->left_trigger = (r32)SDL_GameControllerGetAxis(controller, SDL_CONTROLLER_AXIS_TRIGGERLEFT) / 32767.0f; gamepad->right_trigger = (r32)SDL_GameControllerGetAxis(controller, SDL_CONTROLLER_AXIS_TRIGGERRIGHT) / 32767.0f; if (gamepad->left_trigger > 0.5f) gamepad->btns |= Gamepad::Btn::LeftTrigger; if (gamepad->right_trigger > 0.5f) gamepad->btns |= Gamepad::Btn::RightTrigger; if (SDL_GameControllerGetButton(controller, SDL_CONTROLLER_BUTTON_LEFTSHOULDER)) gamepad->btns |= Gamepad::Btn::LeftShoulder; if (SDL_GameControllerGetButton(controller, SDL_CONTROLLER_BUTTON_RIGHTSHOULDER)) gamepad->btns |= Gamepad::Btn::RightShoulder; if (SDL_GameControllerGetButton(controller, SDL_CONTROLLER_BUTTON_LEFTSTICK)) gamepad->btns |= Gamepad::Btn::LeftClick; if (SDL_GameControllerGetButton(controller, SDL_CONTROLLER_BUTTON_RIGHTSTICK)) gamepad->btns |= Gamepad::Btn::RightClick; if (SDL_GameControllerGetButton(controller, SDL_CONTROLLER_BUTTON_A)) gamepad->btns |= Gamepad::Btn::A; if (SDL_GameControllerGetButton(controller, SDL_CONTROLLER_BUTTON_B)) gamepad->btns |= Gamepad::Btn::B; if (SDL_GameControllerGetButton(controller, SDL_CONTROLLER_BUTTON_X)) gamepad->btns |= Gamepad::Btn::X; if (SDL_GameControllerGetButton(controller, SDL_CONTROLLER_BUTTON_Y)) gamepad->btns |= Gamepad::Btn::Y; if (SDL_GameControllerGetButton(controller, SDL_CONTROLLER_BUTTON_BACK)) gamepad->btns |= Gamepad::Btn::Back; if (SDL_GameControllerGetButton(controller, SDL_CONTROLLER_BUTTON_START)) gamepad->btns |= Gamepad::Btn::Start; if (SDL_GameControllerGetButton(controller, SDL_CONTROLLER_BUTTON_DPAD_UP)) gamepad->btns |= Gamepad::Btn::DUp; if (SDL_GameControllerGetButton(controller, SDL_CONTROLLER_BUTTON_DPAD_DOWN)) gamepad->btns |= Gamepad::Btn::DDown; if (SDL_GameControllerGetButton(controller, SDL_CONTROLLER_BUTTON_DPAD_LEFT)) gamepad->btns |= Gamepad::Btn::DLeft; if (SDL_GameControllerGetButton(controller, SDL_CONTROLLER_BUTTON_DPAD_RIGHT)) gamepad->btns |= Gamepad::Btn::DRight; if (gamepad->rumble > 0.0f) SDL_HapticRumblePlay(haptics[i], gamepad->rumble, 33); gamepad->rumble = 0.0f; active_gamepads++; } else { gamepad->left_x = 0.0f; gamepad->left_y = 0.0f; gamepad->right_x = 0.0f; gamepad->right_y = 0.0f; gamepad->left_trigger = 0.0f; gamepad->right_trigger = 0.0f; gamepad->rumble = 0.0f; } } SDL_GetWindowSize(window, &sync->input.width, &sync->input.height); r64 time = (SDL_GetTicks() / 1000.0); sync->time.total = (r32)time; sync->time.delta = vi_min((r32)(time - last_time), 0.25f); last_time = time; b8 quit = sync->quit; sync = swapper_render.swap<SwapType_Read>(); if (quit || sync->quit) break; } AI::quit(); thread_update.join(); thread_physics.join(); thread_ai.join(); SDL_GL_DeleteContext(context); SDL_DestroyWindow(window); // SDL sucks for (s32 i = 0; i < MAX_GAMEPADS; i++) { if (haptics[i]) SDL_HapticClose(haptics[i]); } SDL_Quit(); return 0; }
void LibretroRunner::commandIn( Command command, QVariant data, qint64 timeStamp ) { // Command is not relayed to children automatically switch( command ) { case Command::Play: { // Make sure we're only connecting LibretroCore to this node if it's a command that only shows up when // emulation is active (in other words, never during loading) if( !connectedToCore ) { connectedToCore = true; qDebug() << "LibretroRunner will now emit signals from LibretroCore"; connect( &libretroCore, &LibretroCore::dataOut, this, &LibretroRunner::dataOut ); connect( &libretroCore, &LibretroCore::commandOut, this, &LibretroRunner::commandOut ); } qCDebug( phxCore ) << command; libretroCore.state = State::Playing; emit commandOut( Command::Play, QVariant(), nodeCurrentTime() ); break; } case Command::Pause: { if( !connectedToCore ) { connectedToCore = true; qDebug() << "LibretroRunner will now emit signals from LibretroCore"; connect( &libretroCore, &LibretroCore::dataOut, this, &LibretroRunner::dataOut ); connect( &libretroCore, &LibretroCore::commandOut, this, &LibretroRunner::commandOut ); } qCDebug( phxCore ) << command; libretroCore.state = State::Paused; emit commandOut( Command::Pause, QVariant(), nodeCurrentTime() ); break; } case Command::Stop: { if( !connectedToCore ) { connectedToCore = true; qDebug() << "LibretroRunner will now emit signals from LibretroCore"; connect( &libretroCore, &LibretroCore::dataOut, this, &LibretroRunner::dataOut ); connect( &libretroCore, &LibretroCore::commandOut, this, &LibretroRunner::commandOut ); } qCDebug( phxCore ) << command; libretroCore.state = State::Unloading; emit commandOut( Command::Unload, QVariant(), nodeCurrentTime() ); // Write SRAM qCInfo( phxCore ) << "=======Saving game...======="; LibretroCoreStoreSaveData(); qCInfo( phxCore ) << "============================"; // Unload core { // symbols.retro_api_version is reasonably expected to be defined if the core is loaded if( libretroCore.symbols.retro_api_version ) { libretroCore.symbols.retro_unload_game(); libretroCore.symbols.retro_deinit(); libretroCore.symbols.clear(); libretroCore.coreFile.unload(); qCDebug( phxCore ) << "Unloaded core successfully"; } else { qCCritical( phxCore ) << "stop() called on an unloaded core!"; } } // Unload game (if we've read its contents into a buffer) { libretroCore.gameData.clear(); } // Disconnect LibretroCore from the rest of the pipeline disconnect( &libretroCore, &LibretroCore::dataOut, this, &LibretroRunner::dataOut ); disconnect( &libretroCore, &LibretroCore::commandOut, this, &LibretroRunner::commandOut ); connectedToCore = false; // Delete the FBO { if( libretroCore.fbo ) { delete libretroCore.fbo; } libretroCore.fbo = nullptr; } // Reset video mode to 2D (will be set to 3D if the next core asks for it) libretroCore.videoFormat.videoMode = SOFTWARERENDER; libretroCore.state = State::Stopped; emit commandOut( Command::Stop, QVariant(), nodeCurrentTime() ); break; } case Command::Heartbeat: { // Drop any heartbeats from too far in the past if( nodeCurrentTime() - timeStamp > 50 ) { return; } emit commandOut( command, data, timeStamp ); if( libretroCore.state == State::Playing ) { // If in 3D mode, lock the mutex before emulating then activate our context and FBO // This is because we're not sure exactly when the core will render to the texture. So, we'll just lock the // mutex for the *entire* frame to be safe and not just from the start of the frame until the video callback // In 2D mode it's simpler: We know that the data will come in a buffer which we can quickly copy within // the video callback. if( libretroCore.videoFormat.videoMode == HARDWARERENDER ) { libretroCore.videoMutex.lock(); //qDebug() << "LibretroRunner lock"; libretroCore.context->makeCurrent( libretroCore.surface ); libretroCore.fbo->bind(); } // Invoke libretro core libretroCore.symbols.retro_run(); // Update rumble state // TODO: Apply per-controller for( GamepadState &gamepad : libretroCore.gamepads ) { if( gamepad.instanceID == -1 || !gamepad.haptic ) { //qDebug() << gamepad.instanceID << ( !gamepad.haptic ) << ( gamepad.hapticID < 0 ); continue; } else if( libretroCore.fallbackRumbleCurrentStrength[ gamepad.instanceID ] != gamepad.fallbackRumbleRequestedStrength ) { //qDebug() << "from" << core.fallbackRumbleCurrentStrength[ gamepad.instanceID ] << "to" << gamepad.fallbackRumbleRequestedStrength; libretroCore.fallbackRumbleCurrentStrength[ gamepad.instanceID ] = gamepad.fallbackRumbleRequestedStrength; SDL_HapticRumbleStop( gamepad.haptic ); if( SDL_HapticRumblePlay( gamepad.haptic, libretroCore.fallbackRumbleCurrentStrength[ gamepad.instanceID ], SDL_HAPTIC_INFINITY ) != 0 ) { qWarning() << gamepad.friendlyName << SDL_GetError(); qWarning().nospace() << gamepad.friendlyName << ": SDL_HapticRumblePlay( " << gamepad.haptic << ", " << libretroCore.fallbackRumbleCurrentStrength << ", SDL_HAPTIC_INFINITY ) != 0, rumble not available"; qWarning() << "SDL:" << SDL_GetError(); } // Reset the requested strength // Implicitly reset by incoming Gamepads overwriting the value set by us with the default of 0.0 // gamepad.fallbackRumbleRequestedStrength = 0.0; } } if( libretroCore.videoFormat.videoMode == HARDWARERENDER ) { libretroCore.context->makeCurrent( libretroCore.surface ); libretroCore.context->functions()->glFlush(); libretroCore.context->doneCurrent(); //qDebug() << "LibretroRunner unlock"; libretroCore.videoMutex.unlock(); } // Flush stderr, some cores may still write to it despite having RETRO_LOG fflush( stderr ); } break; } case Command::SetWindowGeometry: { emit commandOut( command, data, timeStamp ); libretroCore.windowGeometry = data.toRect(); emit commandOut( command, data, timeStamp ); break; } case Command::SetAspectRatioMode: { libretroCore.aspectMode = data.toInt(); emit commandOut( command, data, timeStamp ); break; } case Command::SetLibretroVariable: { LibretroVariable var = data.value<LibretroVariable>(); libretroCore.variables.insert( var.key(), var ); libretroCore.variablesAreDirty = true; emit commandOut( command, data, timeStamp ); break; } case Command::AddController: { if( !connectedToCore ) { connectedToCore = true; qDebug() << "LibretroRunner will now emit signals from LibretroCore"; connect( &libretroCore, &LibretroCore::dataOut, this, &LibretroRunner::dataOut ); connect( &libretroCore, &LibretroCore::commandOut, this, &LibretroRunner::commandOut ); } GamepadState gamepad = data.value<GamepadState>(); int instanceID = gamepad.instanceID; libretroCore.fallbackRumbleCurrentStrength[ instanceID ] = 0.0; emit commandOut( command, data, timeStamp ); break; } case Command::RemoveController: { if( !connectedToCore ) { connectedToCore = true; qDebug() << "LibretroRunner will now emit signals from LibretroCore"; connect( &libretroCore, &LibretroCore::dataOut, this, &LibretroRunner::dataOut ); connect( &libretroCore, &LibretroCore::commandOut, this, &LibretroRunner::commandOut ); } GamepadState gamepad = data.value<GamepadState>(); int instanceID = gamepad.instanceID; libretroCore.gamepads.remove( instanceID ); emit commandOut( command, data, timeStamp ); break; } default: { emit commandOut( command, data, timeStamp ); break; } } }
// First time (lazy) initialization. void gfctrlJoyInit(void) { #ifndef SDL_JOYSTICK gfctrlJoyPresent = GFCTRL_JOY_NONE; for (int index = 0; index < GFCTRL_JOY_NUMBER; index++) { if (!Joysticks[index]) { Joysticks[index] = new jsJoystick(index); } // Don't configure the joystick if it doesn't work if (Joysticks[index]->notWorking()) { delete Joysticks[index]; Joysticks[index] = 0; } else { gfctrlJoyPresent = GFCTRL_JOY_PRESENT; } } #else #if SDL_MAJOR_VERSION >= 2 memset(&cfx, 0, sizeof(cfx)); if (SDL_InitSubSystem(SDL_INIT_JOYSTICK | SDL_INIT_HAPTIC) < 0) { #else if (SDL_Init(SDL_INIT_JOYSTICK) < 0) { #endif GfLogError("Couldn't initialize SDL: %s\n", SDL_GetError()); gfctrlJoyPresent = GFCTRL_JOY_UNTESTED; return; } #if SDL_MAJOR_VERSION >= 2 // Ignore the joystick events, we will poll directly as it is faster SDL_JoystickEventState(SDL_IGNORE); #endif gfctrlJoyPresent = SDL_NumJoysticks(); if (gfctrlJoyPresent > GFCTRL_JOY_NUMBER) gfctrlJoyPresent = GFCTRL_JOY_NUMBER; for (int index = 0; index < gfctrlJoyPresent; index++) { if (!Joysticks[index]) { Joysticks[index] = SDL_JoystickOpen(index); } // Don't configure the joystick if it doesn't work if (Joysticks[index] == NULL) { GfLogError("Couldn't open joystick %d: %s\n", index, SDL_GetError()); #if SDL_MAJOR_VERSION >= 2 } else { cfx_timeout[index] = 0; rfx_timeout[index] = 0; // Find which Haptic device relates to this joystick Haptics[index] = SDL_HapticOpenFromJoystick(Joysticks[index]); if (!Haptics[index]) { GfLogInfo("Joystick %d does not support haptic\n", index); break; #if 0 } else { // add an CF effect on startup gfctrlJoyConstantForce(index, 50000, 9000); #endif } // Check for Rumble capability if (SDL_HapticRumbleSupported(Haptics[index]) == SDL_TRUE) { if (SDL_HapticRumbleInit(Haptics[index]) != 0) GfLogError("Couldn't init rumble on joystick %d: %s\n", index, SDL_GetError()); #if 0 else gfctrlJoyRumble(index, 0.5); #endif } #endif } } #endif } #if SDL_JOYSTICK void gfctrlJoyConstantForce(int index, unsigned int level, int dir) { #if SDL_MAJOR_VERSION >= 2 if (!Haptics[index]) return; if ((SDL_HapticQuery(Haptics[index]) & SDL_HAPTIC_CONSTANT) == 0) return; cfx[index].type = SDL_HAPTIC_CONSTANT; cfx[index].constant.direction.type = SDL_HAPTIC_POLAR; cfx[index].constant.direction.dir[0] = dir; cfx[index].constant.length = 1000; cfx[index].constant.level = level; cfx[index].constant.attack_length = 0; cfx[index].constant.fade_length = 1000; #if __WIN32__ if (SDL_HapticGetEffectStatus(Haptics[index], id[index]) == SDL_TRUE) #else // Linux SDL doesn't support checking status at the moment :-( if (cfx_timeout[index] > SDL_GetTicks()) #endif SDL_HapticUpdateEffect(Haptics[index], id[index], &cfx[index]); else { SDL_HapticDestroyEffect(Haptics[index], id[index]); id[index] = SDL_HapticNewEffect(Haptics[index], &cfx[index]); SDL_HapticRunEffect(Haptics[index], id[index], 1); } cfx_timeout[index] = SDL_GetTicks() + cfx[index].constant.length; #endif } void gfctrlJoyRumble(int index, float level) { #if SDL_MAJOR_VERSION >= 2 if (!Haptics[index]) return; if (SDL_HapticRumbleSupported(Haptics[index]) != SDL_TRUE) return; // we have to stop the rumble before updating if (rfx_timeout[index] > SDL_GetTicks()) { if (SDL_HapticRumbleStop(Haptics[index]) != 0) GfLogError("Failed to stop rumble: %s\n", SDL_GetError() ); } if (SDL_HapticRumblePlay(Haptics[index], level, 100) != 0) GfLogError("Failed to play rumble: %s\n", SDL_GetError() ); rfx_timeout[index] = SDL_GetTicks() + 100; #endif } #endif // Shutdown time. void gfctrlJoyShutdown(void) { if (gfctrlJoyPresent != GFCTRL_JOY_UNTESTED) #ifndef SDL_JOYSTICK for (int index = 0; index < GFCTRL_JOY_NUMBER; index++) delete Joysticks[index]; #else for (int index = 0; index < gfctrlJoyPresent; index++) { SDL_JoystickClose(Joysticks[index]); Joysticks[index] = NULL; #if SDL_MAJOR_VERSION >= 2 if (Haptics[index]) { SDL_HapticClose(Haptics[index]); Haptics[index] = NULL; } #endif } #endif gfctrlJoyPresent = GFCTRL_JOY_UNTESTED; } /** Create the joystick control @ingroup ctrl @return pointer on a tCtrlJoyInfo structure <br>0 .. if no joystick present @note call GfctrlJoyRelease to free the tCtrlJoyInfo structure @see GfctrlJoyRelease @see tCtrlJoyInfo */ tCtrlJoyInfo * GfctrlJoyCreate(void) { if (gfctrlJoyPresent == GFCTRL_JOY_UNTESTED) gfctrlJoyInit(); tCtrlJoyInfo* joyInfo = (tCtrlJoyInfo *)calloc(1, sizeof(tCtrlJoyInfo)); #if SDL_JOYSTICK joyInfoCopy = joyInfo; #endif return joyInfo; } /** Release the tCtrlJoyInfo structure @ingroup ctrl @param joyInfo joystick structure @return none */ void GfctrlJoyRelease(tCtrlJoyInfo *joyInfo) { freez(joyInfo); }
/** * @brief The entry point of this force feedback demo. * @param[in] argc Number of arguments. * @param[in] argv Array of argc arguments. */ int main(int argc, char **argv) { int i; char *name; int index; SDL_HapticEffect efx[5]; int id[5]; int nefx; unsigned int supported; name = NULL; index = -1; if (argc > 1) { name = argv[1]; if ((strcmp(name, "--help") == 0) || (strcmp(name, "-h") == 0)) { printf("USAGE: %s [device]\n" "If device is a two-digit number it'll use it as an index, otherwise\n" "it'll use it as if it were part of the device's name.\n", argv[0]); return 0; } i = strlen(name); if ((i < 3) && isdigit(name[0]) && ((i == 1) || isdigit(name[1]))) { index = atoi(name); name = NULL; } } /* Initialize the force feedbackness */ SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER | SDL_INIT_JOYSTICK | SDL_INIT_HAPTIC); printf("%d Haptic devices detected.\n", SDL_NumHaptics()); if (SDL_NumHaptics() > 0) { /* We'll just use index or the first force feedback device found */ if (name == NULL) { i = (index != -1) ? index : 0; } /* Try to find matching device */ else { for (i = 0; i < SDL_NumHaptics(); i++) { if (strstr(SDL_HapticName(i), name) != NULL) break; } if (i >= SDL_NumHaptics()) { printf("Unable to find device matching '%s', aborting.\n", name); return 1; } } haptic = SDL_HapticOpen(i); if (haptic == NULL) { printf("Unable to create the haptic device: %s\n", SDL_GetError()); return 1; } printf("Device: %s\n", SDL_HapticName(i)); } else { printf("No Haptic devices found!\n"); return 1; } /* We only want force feedback errors. */ SDL_ClearError(); if (SDL_HapticRumbleSupported(haptic) == SDL_FALSE) { printf("\nRumble not supported!\n"); return 1; } if (SDL_HapticRumbleInit(haptic) != 0) { printf("\nFailed to initialize rumble: %s\n", SDL_GetError()); return 1; } printf("Playing 2 second rumble at 0.5 magnitude.\n"); if (SDL_HapticRumblePlay(haptic, 0.5, 5000) != 0) { printf("\nFailed to play rumble: %s\n", SDL_GetError() ); return 1; } SDL_Delay(2000); printf("Stopping rumble.\n"); SDL_HapticRumbleStop(haptic); SDL_Delay(2000); printf("Playing 2 second rumble at 0.3 magnitude.\n"); if (SDL_HapticRumblePlay(haptic, 0.3, 5000) != 0) { printf("\nFailed to play rumble: %s\n", SDL_GetError() ); return 1; } SDL_Delay(2000); /* Quit */ if (haptic != NULL) SDL_HapticClose(haptic); SDL_Quit(); return 0; }
void SDLPlayRumble(real32 Strength, int Delay) { SDL_HapticRumblePlay(RumbleHandle, Strength, Delay); }
void Engine_InitSDLControls() { int NumJoysticks; Uint32 init_flags = SDL_INIT_VIDEO | SDL_INIT_EVENTS; // These flags are used in any case. if(control_mapper.use_joy == 1) { init_flags |= SDL_INIT_GAMECONTROLLER; // Update init flags for joystick. if(control_mapper.joy_rumble) { init_flags |= SDL_INIT_HAPTIC; // Update init flags for force feedback. } SDL_Init(init_flags); NumJoysticks = SDL_NumJoysticks(); if((NumJoysticks < 1) || ((NumJoysticks - 1) < control_mapper.joy_number)) { Sys_DebugLog(LOG_FILENAME, "Error: there is no joystick #%d present.", control_mapper.joy_number); return; } if(SDL_IsGameController(control_mapper.joy_number)) // If joystick has mapping (e.g. X360 controller) { SDL_GameControllerEventState(SDL_ENABLE); // Use GameController API sdl_controller = SDL_GameControllerOpen(control_mapper.joy_number); if(!sdl_controller) { Sys_DebugLog(LOG_FILENAME, "Error: can't open game controller #%d.", control_mapper.joy_number); SDL_GameControllerEventState(SDL_DISABLE); // If controller init failed, close state. control_mapper.use_joy = 0; } else if(control_mapper.joy_rumble) // Create force feedback interface. { sdl_haptic = SDL_HapticOpenFromJoystick(SDL_GameControllerGetJoystick(sdl_controller)); if(!sdl_haptic) { Sys_DebugLog(LOG_FILENAME, "Error: can't initialize haptic from game controller #%d.", control_mapper.joy_number); } } } else { SDL_JoystickEventState(SDL_ENABLE); // If joystick isn't mapped, use generic API. sdl_joystick = SDL_JoystickOpen(control_mapper.joy_number); if(!sdl_joystick) { Sys_DebugLog(LOG_FILENAME, "Error: can't open joystick #%d.", control_mapper.joy_number); SDL_JoystickEventState(SDL_DISABLE); // If joystick init failed, close state. control_mapper.use_joy = 0; } else if(control_mapper.joy_rumble) // Create force feedback interface. { sdl_haptic = SDL_HapticOpenFromJoystick(sdl_joystick); if(!sdl_haptic) { Sys_DebugLog(LOG_FILENAME, "Error: can't initialize haptic from joystick #%d.", control_mapper.joy_number); } } } if(sdl_haptic) // To check if force feedback is working or not. { SDL_HapticRumbleInit(sdl_haptic); SDL_HapticRumblePlay(sdl_haptic, 1.0, 300); } } else { SDL_Init(init_flags); } }
void Controller::rumble(float strength, int duration){ //Strength parameter is a float between 0 and 1 to determine how strong //the vibration is. Duration is time in milliseconds to vibrate controller. if (rumbleSupport)SDL_HapticRumblePlay(haptic, strength, duration); else std::cout << "rumble not supported" << std::endl; }
void rumble(float str, uint32_t len) { if (haptic != NULL && settings->rumble) SDL_HapticRumblePlay(haptic, str, len); }
/** * @brief The entry point of this force feedback demo. * @param[in] argc Number of arguments. * @param[in] argv Array of argc arguments. */ int main(int argc, char **argv) { int i; char *name; int index; /* Enable standard application logging */ SDL_LogSetPriority(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_INFO); name = NULL; index = -1; if (argc > 1) { size_t l; name = argv[1]; if ((strcmp(name, "--help") == 0) || (strcmp(name, "-h") == 0)) { SDL_Log("USAGE: %s [device]\n" "If device is a two-digit number it'll use it as an index, otherwise\n" "it'll use it as if it were part of the device's name.\n", argv[0]); return 0; } l = SDL_strlen(name); if ((l < 3) && SDL_isdigit(name[0]) && ((l == 1) || SDL_isdigit(name[1]))) { index = SDL_atoi(name); name = NULL; } } /* Initialize the force feedbackness */ SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER | SDL_INIT_JOYSTICK | SDL_INIT_HAPTIC); SDL_Log("%d Haptic devices detected.\n", SDL_NumHaptics()); if (SDL_NumHaptics() > 0) { /* We'll just use index or the first force feedback device found */ if (name == NULL) { i = (index != -1) ? index : 0; } /* Try to find matching device */ else { for (i = 0; i < SDL_NumHaptics(); i++) { if (strstr(SDL_HapticName(i), name) != NULL) break; } if (i >= SDL_NumHaptics()) { SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Unable to find device matching '%s', aborting.\n", name); return 1; } } haptic = SDL_HapticOpen(i); if (haptic == NULL) { SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Unable to create the haptic device: %s\n", SDL_GetError()); return 1; } SDL_Log("Device: %s\n", SDL_HapticName(i)); } else { SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "No Haptic devices found!\n"); return 1; } /* We only want force feedback errors. */ SDL_ClearError(); if (SDL_HapticRumbleSupported(haptic) == SDL_FALSE) { SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Rumble not supported!\n"); return 1; } if (SDL_HapticRumbleInit(haptic) != 0) { SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to initialize rumble: %s\n", SDL_GetError()); return 1; } SDL_Log("Playing 2 second rumble at 0.5 magnitude.\n"); if (SDL_HapticRumblePlay(haptic, 0.5, 5000) != 0) { SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to play rumble: %s\n", SDL_GetError() ); return 1; } SDL_Delay(2000); SDL_Log("Stopping rumble.\n"); SDL_HapticRumbleStop(haptic); SDL_Delay(2000); SDL_Log("Playing 2 second rumble at 0.3 magnitude.\n"); if (SDL_HapticRumblePlay(haptic, 0.3f, 5000) != 0) { SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to play rumble: %s\n", SDL_GetError() ); return 1; } SDL_Delay(2000); /* Quit */ if (haptic != NULL) SDL_HapticClose(haptic); SDL_Quit(); return 0; }
void C4GamePadOpener::PlayRumble(float strength, uint32_t length) { if (SDL_HapticRumbleSupported(haptic)) SDL_HapticRumblePlay(haptic, strength, length); }