bool SdlRumbleEffect::play(int num_repeats) { if (isActive()) { if (num_repeats == -1) { return (SDL_HapticRunEffect(mHaptic, mId, SDL_HAPTIC_INFINITY) == 0); } else { return (SDL_HapticRunEffect(mHaptic, mId, num_repeats) == 0); } } return false; }
void ForceFeedback::update( float force, float /*dt*/, std::ostream & error_output) { if (!enabled || !haptic || (effect_id == -1)) return; // Clamp force. force = Clamp(force, -1.0f, 1.0f); // Low pass filter. lastforce = (lastforce + force) * 0.5f; // Update effect. effect.constant.level = Sint16(lastforce * 32767); int new_effect_id = SDL_HapticUpdateEffect(haptic, effect_id, &effect); if (new_effect_id == -1) { error_output << "Failed to update force feedback effect: " << SDL_GetError(); return; } else { effect_id = new_effect_id; } // Run effect. if (SDL_HapticRunEffect(haptic, effect_id, 1) == -1) { error_output << "Failed to run force feedback effect: " << SDL_GetError(); return; } }
bool CSDLPad::SetForceFeedback(IFFParams params) { #if defined(SDL_USE_HAPTIC_FEEDBACK) if (!m_connected) return false; // only submit new one when current has finished if (m_supportsFeedback && m_curHapticEffect <0) { if ( params.strengthA == 0 || params.strengthB == 0) return true; SDL_HapticEffect effect; memset(&effect, 0, sizeof(effect)); effect.type = SDL_HAPTIC_LEFTRIGHT; effect.leftright.large_magnitude = (uint16)(clamp_tpl(params.strengthB,0.0f,1.0f) * 65536.0f); effect.leftright.small_magnitude = (uint16)(clamp_tpl(params.strengthA,0.0f,1.0f) * 65536.0f); effect.leftright.length = (params.timeInSeconds == 0.0f) ? 1000 : (Uint32)(params.timeInSeconds * 1000.0f); m_curHapticEffect = SDL_HapticNewEffect(m_pHapticDevice, &effect); if (m_curHapticEffect < 0) { gEnv->pLog->LogError("CSDLPad - Gamepad [%d] failed to create feedback effect: %s", m_deviceNo, SDL_GetError()); return false; } gEnv->pLog->Log("CSDLPad - Gamepad [%d] submitting create feedback effect (%d,%d,%d)", m_deviceNo, effect.leftright.large_magnitude, effect.leftright.small_magnitude, effect.leftright.length); SDL_HapticRunEffect(m_pHapticDevice, m_curHapticEffect, 1); m_vibrateTime=params.timeInSeconds; } #endif return true; }
bool SDL2FFBDevice::startEffect(const int idx, const FFBEffectTypes type, std::shared_ptr<FFBEffectParameters> parameters) { std::shared_ptr<SDL2FFBEffect> sdlEff; Uint32 repeat; CHECK_EFFECT_IDX(idx); if (m_effects[idx]->status() == FFBEffect::FFBEffectStatus::NOT_LOADED) { if (!uploadEffect(idx, type, parameters)) return false; } if (m_effects[idx]->status() == FFBEffect::FFBEffectStatus::PLAYING) return true; sdlEff = std::static_pointer_cast<SDL2FFBEffect>(m_effects[idx]); if (sdlEff->parameters()->repeat == 0) { if (sdlEff->parameters()->replayLength > 0) repeat = SDL_HAPTIC_INFINITY; else repeat = 1; } else repeat = sdlEff->parameters()->repeat; if (SDL_HapticRunEffect(c_haptic, sdlEff->internalIdx(), repeat) < 0) { QMessageBox::warning(nullptr, SDL2DEV_ERR_CAPTION, QString("Unable to start the effect:\n%1").arg(SDL_GetError())); return false; } sdlEff->setStatus(FFBEffect::FFBEffectStatus::PLAYING); return true; }
/* * Runs simple rumble on a haptic device */ int SDL_HapticRumblePlay(SDL_Haptic * haptic, float strength, Uint32 length) { int ret; SDL_HapticPeriodic *efx; if (!ValidHaptic(haptic)) { return -1; } if (haptic->rumble_id < 0) { SDL_SetError("Haptic: Rumble effect not initialized on haptic device"); return -1; } /* Clamp strength. */ if (strength > 1.0f) { strength = 1.0f; } else if (strength < 0.0f) { strength = 0.0f; } /* New effect. */ efx = &haptic->rumble_effect.periodic; efx->magnitude = (Sint16)(32767.0f*strength); efx->length = length; ret = SDL_HapticUpdateEffect(haptic, haptic->rumble_id, &haptic->rumble_effect); return SDL_HapticRunEffect(haptic, haptic->rumble_id, 1); }
void SdlManager::SdlController::RunHapticLeftRight(float left, float right) { CriticalCode criticalCode(criticalSection); if(!haptic) return; hapticEffect.leftright.length = SDL_HAPTIC_INFINITY; hapticEffect.leftright.large_magnitude = uint16_t(left * 0xffff); hapticEffect.leftright.small_magnitude = uint16_t(right * 0xffff); if(hapticEffectIndex >= 0 && hapticEffect.type == SDL_HAPTIC_LEFTRIGHT) { SDL_HapticStopEffect(haptic, hapticEffectIndex); SDL_HapticUpdateEffect(haptic, hapticEffectIndex, &hapticEffect); } else { if(hapticEffectIndex >= 0) { SDL_HapticStopEffect(haptic, hapticEffectIndex); SDL_HapticDestroyEffect(haptic, hapticEffectIndex); } hapticEffect.type = SDL_HAPTIC_LEFTRIGHT; hapticEffectIndex = SDL_HapticNewEffect(haptic, &hapticEffect); } SDL_HapticRunEffect(haptic, hapticEffectIndex, 1); }
bool Joystick::UpdateOutput() { #ifdef USE_SDL_HAPTIC std::list<EffectIDState>::iterator i = m_state_out.begin(), e = m_state_out.end(); for ( ; i != e; ++i) { if (i->changed) // if SetState was called on this output { if (-1 == i->id) // effect isn't currently uploaded { if (i->effect.type) // if outputstate is >0 this would be true if ((i->id = SDL_HapticNewEffect( m_haptic, &i->effect )) > -1) // upload the effect SDL_HapticRunEffect(m_haptic, i->id, 1); // run the effect } else // effect is already uploaded { if (i->effect.type) // if ouputstate >0 SDL_HapticUpdateEffect(m_haptic, i->id, &i->effect); // update the effect else { SDL_HapticStopEffect(m_haptic, i->id); // else, stop and remove the effect SDL_HapticDestroyEffect(m_haptic, i->id); i->id = -1; // mark it as not uploaded } } i->changed = false; } } #endif return true; }
JNIEXPORT jint JNICALL Java_at_wisch_joystick_FFJoystick_playEffectNative(JNIEnv *env, jclass, jint hapticDeviceIndex, jint effectIndex, jint iterations){ if (iterations == at_wisch_joystick_Joystick_INFINITE_TIMES){ iterations = SDL_HAPTIC_INFINITY; } int num = SDL_HapticRunEffect(ffjoysticks[hapticDeviceIndex], effectIndex, iterations); if (num < 0) { throwException(env, SDL_GetError()); return -22; } return num; }
static bool sdl_joypad_set_rumble(unsigned pad, enum retro_rumble_effect effect, uint16_t strength) { SDL_HapticEffect efx; sdl_joypad_t *joypad = (sdl_joypad_t*)&sdl_pads[pad]; memset(&efx, 0, sizeof(efx)); if (!joypad->joypad || !joypad->haptic) return false; efx.type = SDL_HAPTIC_LEFTRIGHT; efx.leftright.type = SDL_HAPTIC_LEFTRIGHT; efx.leftright.length = 5000; switch (effect) { case RETRO_RUMBLE_STRONG: efx.leftright.large_magnitude = strength; break; case RETRO_RUMBLE_WEAK: efx.leftright.small_magnitude = strength; break; default: return false; } if (joypad->rumble_effect == -1) { joypad->rumble_effect = SDL_HapticNewEffect(sdl_pads[pad].haptic, &efx); if (joypad->rumble_effect < 0) { RARCH_WARN("[SDL]: Failed to create rumble effect for joypad %u: %s\n", pad, SDL_GetError()); joypad->rumble_effect = -2; return false; } } else if (joypad->rumble_effect >= 0) SDL_HapticUpdateEffect(joypad->haptic, joypad->rumble_effect, &efx); if (joypad->rumble_effect < 0) return false; if (SDL_HapticRunEffect(joypad->haptic, joypad->rumble_effect, 1) < 0) { RARCH_WARN("[SDL]: Failed to set rumble effect on joypad %u: %s\n", pad, SDL_GetError()); return false; } return true; }
bool Joystick::runVibrationEffect() { if (vibration.id != -1) { if (SDL_HapticUpdateEffect(haptic, vibration.id, &vibration.effect) == 0) { if (SDL_HapticRunEffect(haptic, vibration.id, 1) == 0) return true; } // If the effect fails to update, we should destroy and re-create it. SDL_HapticDestroyEffect(haptic, vibration.id); vibration.id = -1; } vibration.id = SDL_HapticNewEffect(haptic, &vibration.effect); if (vibration.id != -1 && SDL_HapticRunEffect(haptic, vibration.id, 1) == 0) return true; return false; }
void JoystickInfo::Rumble(int type, int pad) { if (type > 1) return; if ( !(conf->pad_options[pad].forcefeedback) ) return; #if SDL_MAJOR_VERSION >= 2 if (haptic == NULL) return; if(first) { // If done multiple times, device memory will be filled first = 0; GenerateDefaultEffect(); /** Sine and triangle are quite probably the best, don't change that lightly and if you do * keep effects ordered by type **/ /** Effect for small motor **/ /** Sine seems to be the only effect making little motor from DS3/4 react * Intensity has pretty much no effect either(which is coherent with what is explain in hid_sony driver **/ effects[0].type = SDL_HAPTIC_SINE; effects_id[0] = SDL_HapticNewEffect(haptic, &effects[0]); if(effects_id[0] < 0) { fprintf(stderr,"ERROR: Effect is not uploaded! %s, id is %d\n",SDL_GetError(),effects_id[0]); } /** Effect for big motor **/ effects[1].type = SDL_HAPTIC_TRIANGLE; effects_id[1] = SDL_HapticNewEffect(haptic, &effects[1]); if(effects_id[1] < 0) { fprintf(stderr,"ERROR: Effect is not uploaded! %s, id is %d\n",SDL_GetError(),effects_id[1]); } } int id; id = effects_id[type]; if(SDL_HapticRunEffect(haptic, id, 1) != 0) { fprintf(stderr,"ERROR: Effect is not working! %s, id is %d\n",SDL_GetError(),id); } #endif }
void Joystick::HapticEffect::Update() { if (m_id == -1 && m_effect.type > 0) { m_id = SDL_HapticNewEffect(m_haptic, &m_effect); if (m_id > -1) SDL_HapticRunEffect(m_haptic, m_id, 1); } else if (m_id > -1 && m_effect.type == 0) { SDL_HapticStopEffect(m_haptic, m_id); SDL_HapticDestroyEffect(m_haptic, m_id); m_id = -1; } else if (m_id > -1) { SDL_HapticUpdateEffect(m_haptic, m_id, &m_effect); } }
void JoystickInfo::DoHapticEffect(int type, int pad, int force) { if (type > 1) return; if ( !(conf->options & (PADOPTION_FORCEFEEDBACK << 16 * pad)) ) return; #if SDL_MAJOR_VERSION >= 2 int joyid = conf->get_joyid(pad); if (!JoystickIdWithinBounds(joyid)) return; JoystickInfo* pjoy = s_vjoysticks[joyid]; if (pjoy->haptic == NULL) return; if (pjoy->haptic_effect_id[type] < 0) return; // FIXME: might need to multiply force pjoy->haptic_effect_data[type].periodic.magnitude = force * conf->ff_intensity ; // force/32767 strength // Upload the new effect SDL_HapticUpdateEffect(pjoy->haptic, pjoy->haptic_effect_id[type], &pjoy->haptic_effect_data[type]); // run the effect once SDL_HapticRunEffect( pjoy->haptic, pjoy->haptic_effect_id[type], 1 ); #endif }
/* * Runs simple rumble on a haptic device */ int SDL_HapticRumblePlay(SDL_Haptic * haptic, float strength, Uint32 length) { SDL_HapticEffect *efx; Sint16 magnitude; if (!ValidHaptic(haptic)) { return -1; } if (haptic->rumble_id < 0) { return SDL_SetError("Haptic: Rumble effect not initialized on haptic device"); } /* Clamp strength. */ if (strength > 1.0f) { strength = 1.0f; } else if (strength < 0.0f) { strength = 0.0f; } magnitude = (Sint16)(32767.0f*strength); efx = &haptic->rumble_effect; if (efx->type == SDL_HAPTIC_SINE) { efx->periodic.magnitude = magnitude; efx->periodic.length = length; } else if (efx->type == SDL_HAPTIC_LEFTRIGHT) { efx->leftright.small_magnitude = efx->leftright.large_magnitude = magnitude; efx->leftright.length = length; } else { SDL_assert(0 && "This should have been caught elsewhere"); } if (SDL_HapticUpdateEffect(haptic, haptic->rumble_id, &haptic->rumble_effect) < 0) { return -1; } return SDL_HapticRunEffect(haptic, haptic->rumble_id, 1); }
/** * @brief Runs a rumble effect. * * @brief Current modifier being added. */ static void spfx_hapticRumble( double mod ) { #if SDL_VERSION_ATLEAST(1,3,0) SDL_HapticEffect *efx; double len, mag; if (haptic_rumble >= 0) { /* Not time to update yet. */ if ((haptic_lastUpdate > 0.) || shake_off || (mod > SHAKE_MAX/3.)) return; /* Stop the effect if it was playing. */ SDL_HapticStopEffect( haptic, haptic_rumble ); /* Get length and magnitude. */ len = 1000. * shake_rad / SHAKE_DECAY; mag = 32767. * (shake_rad / SHAKE_MAX); /* Update the effect. */ efx = &haptic_rumbleEffect; efx->periodic.magnitude = (uint32_t)mag;; efx->periodic.length = (uint32_t)len; efx->periodic.fade_length = MIN( efx->periodic.length, 1000 ); if (SDL_HapticUpdateEffect( haptic, haptic_rumble, &haptic_rumbleEffect ) < 0) { WARN("Failed to update haptic effect: %s.", SDL_GetError()); return; } /* Run the new effect. */ SDL_HapticRunEffect( haptic, haptic_rumble, 1 ); /* Set timer again. */ haptic_lastUpdate = HAPTIC_UPDATE_INTERVAL; } #else /* SDL_VERSION_ATLEAST(1,3,0) */ (void) mod; #endif /* SDL_VERSION_ATLEAST(1,3,0) */ }
bool Joystick::UpdateOutput() { #ifdef USE_SDL_HAPTIC for (auto &i : m_state_out) { if (i.changed) // if SetState was called on this output { if (-1 == i.id) // effect isn't currently uploaded { if (i.effect.type) // if outputstate is >0 this would be true { if ((i.id = SDL_HapticNewEffect(m_haptic, &i.effect)) > -1) // upload the effect { SDL_HapticRunEffect(m_haptic, i.id, 1); // run the effect } } } else // effect is already uploaded { if (i.effect.type) // if ouputstate >0 { SDL_HapticUpdateEffect(m_haptic, i.id, &i.effect); // update the effect } else { SDL_HapticStopEffect(m_haptic, i.id); // else, stop and remove the effect SDL_HapticDestroyEffect(m_haptic, i.id); i.id = -1; // mark it as not uploaded } } i.changed = false; } } #endif return true; }
/** * @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[9]; int id[9]; int nefx; unsigned int supported; /* Enable standard application logging */ SDL_LogSetPriority(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_INFO); name = NULL; index = -1; if (argc > 1) { 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; } 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); 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)); HapticPrintSupported(haptic); } else { SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "No Haptic devices found!\n"); return 1; } /* We only want force feedback errors. */ SDL_ClearError(); /* Create effects. */ memset(&efx, 0, sizeof(efx)); nefx = 0; supported = SDL_HapticQuery(haptic); SDL_Log("\nUploading effects\n"); /* First we'll try a SINE effect. */ if (supported & SDL_HAPTIC_SINE) { SDL_Log(" effect %d: Sine Wave\n", nefx); efx[nefx].type = SDL_HAPTIC_SINE; efx[nefx].periodic.period = 1000; efx[nefx].periodic.magnitude = -0x2000; /* Negative magnitude and ... */ efx[nefx].periodic.phase = 18000; /* ... 180 degrees phase shift => cancel eachother */ efx[nefx].periodic.length = 5000; efx[nefx].periodic.attack_length = 1000; efx[nefx].periodic.fade_length = 1000; id[nefx] = SDL_HapticNewEffect(haptic, &efx[nefx]); if (id[nefx] < 0) { SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "UPLOADING EFFECT ERROR: %s\n", SDL_GetError()); abort_execution(); } nefx++; } /* Now we'll try a SAWTOOTHUP */ if (supported & SDL_HAPTIC_SAWTOOTHUP) { SDL_Log(" effect %d: Sawtooth Up\n", nefx); efx[nefx].type = SDL_HAPTIC_SAWTOOTHUP; efx[nefx].periodic.period = 500; efx[nefx].periodic.magnitude = 0x5000; efx[nefx].periodic.length = 5000; efx[nefx].periodic.attack_length = 1000; efx[nefx].periodic.fade_length = 1000; id[nefx] = SDL_HapticNewEffect(haptic, &efx[nefx]); if (id[nefx] < 0) { SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "UPLOADING EFFECT ERROR: %s\n", SDL_GetError()); abort_execution(); } nefx++; } /* Now the classical constant effect. */ if (supported & SDL_HAPTIC_CONSTANT) { SDL_Log(" effect %d: Constant Force\n", nefx); efx[nefx].type = SDL_HAPTIC_CONSTANT; efx[nefx].constant.direction.type = SDL_HAPTIC_POLAR; efx[nefx].constant.direction.dir[0] = 20000; /* Force comes from the south-west. */ efx[nefx].constant.length = 5000; efx[nefx].constant.level = 0x6000; efx[nefx].constant.attack_length = 1000; efx[nefx].constant.fade_length = 1000; id[nefx] = SDL_HapticNewEffect(haptic, &efx[nefx]); if (id[nefx] < 0) { SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "UPLOADING EFFECT ERROR: %s\n", SDL_GetError()); abort_execution(); } nefx++; } /* The cute spring effect. */ if (supported & SDL_HAPTIC_SPRING) { SDL_Log(" effect %d: Condition Spring\n", nefx); efx[nefx].type = SDL_HAPTIC_SPRING; efx[nefx].condition.length = 5000; for (i = 0; i < SDL_HapticNumAxes(haptic); i++) { efx[nefx].condition.right_sat[i] = 0xFFFF; efx[nefx].condition.left_sat[i] = 0xFFFF; efx[nefx].condition.right_coeff[i] = 0x2000; efx[nefx].condition.left_coeff[i] = 0x2000; efx[nefx].condition.center[i] = 0x1000; /* Displace the center for it to move. */ } id[nefx] = SDL_HapticNewEffect(haptic, &efx[nefx]); if (id[nefx] < 0) { SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "UPLOADING EFFECT ERROR: %s\n", SDL_GetError()); abort_execution(); } nefx++; } /* The interesting damper effect. */ if (supported & SDL_HAPTIC_DAMPER) { SDL_Log(" effect %d: Condition Damper\n", nefx); efx[nefx].type = SDL_HAPTIC_DAMPER; efx[nefx].condition.length = 5000; for (i = 0; i < SDL_HapticNumAxes(haptic); i++) { efx[nefx].condition.right_sat[i] = 0xFFFF; efx[nefx].condition.left_sat[i] = 0xFFFF; efx[nefx].condition.right_coeff[i] = 0x2000; efx[nefx].condition.left_coeff[i] = 0x2000; } id[nefx] = SDL_HapticNewEffect(haptic, &efx[nefx]); if (id[nefx] < 0) { SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "UPLOADING EFFECT ERROR: %s\n", SDL_GetError()); abort_execution(); } nefx++; } /* The pretty awesome inertia effect. */ if (supported & SDL_HAPTIC_INERTIA) { SDL_Log(" effect %d: Condition Inertia\n", nefx); efx[nefx].type = SDL_HAPTIC_INERTIA; efx[nefx].condition.length = 5000; for (i = 0; i < SDL_HapticNumAxes(haptic); i++) { efx[nefx].condition.right_sat[i] = 0xFFFF; efx[nefx].condition.left_sat[i] = 0xFFFF; efx[nefx].condition.right_coeff[i] = 0x2000; efx[nefx].condition.left_coeff[i] = 0x2000; efx[nefx].condition.deadband[i] = 0x1000; /* 1/16th of axis-range around the center is 'dead'. */ } id[nefx] = SDL_HapticNewEffect(haptic, &efx[nefx]); if (id[nefx] < 0) { SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "UPLOADING EFFECT ERROR: %s\n", SDL_GetError()); abort_execution(); } nefx++; } /* The hot friction effect. */ if (supported & SDL_HAPTIC_FRICTION) { SDL_Log(" effect %d: Condition Friction\n", nefx); efx[nefx].type = SDL_HAPTIC_FRICTION; efx[nefx].condition.length = 5000; for (i = 0; i < SDL_HapticNumAxes(haptic); i++) { efx[nefx].condition.right_sat[i] = 0xFFFF; efx[nefx].condition.left_sat[i] = 0xFFFF; efx[nefx].condition.right_coeff[i] = 0x2000; efx[nefx].condition.left_coeff[i] = 0x2000; } id[nefx] = SDL_HapticNewEffect(haptic, &efx[nefx]); if (id[nefx] < 0) { SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "UPLOADING EFFECT ERROR: %s\n", SDL_GetError()); abort_execution(); } nefx++; } /* Now we'll try a ramp effect */ if (supported & SDL_HAPTIC_RAMP) { SDL_Log(" effect %d: Ramp\n", nefx); efx[nefx].type = SDL_HAPTIC_RAMP; efx[nefx].ramp.direction.type = SDL_HAPTIC_CARTESIAN; efx[nefx].ramp.direction.dir[0] = 1; /* Force comes from */ efx[nefx].ramp.direction.dir[1] = -1; /* the north-east. */ efx[nefx].ramp.length = 5000; efx[nefx].ramp.start = 0x4000; efx[nefx].ramp.end = -0x4000; efx[nefx].ramp.attack_length = 1000; efx[nefx].ramp.fade_length = 1000; id[nefx] = SDL_HapticNewEffect(haptic, &efx[nefx]); if (id[nefx] < 0) { SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "UPLOADING EFFECT ERROR: %s\n", SDL_GetError()); abort_execution(); } nefx++; } /* Finally we'll try a left/right effect. */ if (supported & SDL_HAPTIC_LEFTRIGHT) { SDL_Log(" effect %d: Left/Right\n", nefx); efx[nefx].type = SDL_HAPTIC_LEFTRIGHT; efx[nefx].leftright.length = 5000; efx[nefx].leftright.large_magnitude = 0x3000; efx[nefx].leftright.small_magnitude = 0xFFFF; id[nefx] = SDL_HapticNewEffect(haptic, &efx[nefx]); if (id[nefx] < 0) { SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "UPLOADING EFFECT ERROR: %s\n", SDL_GetError()); abort_execution(); } nefx++; } SDL_Log ("\nNow playing effects for 5 seconds each with 1 second delay between\n"); for (i = 0; i < nefx; i++) { SDL_Log(" Playing effect %d\n", i); SDL_HapticRunEffect(haptic, id[i], 1); SDL_Delay(6000); /* Effects only have length 5000 */ } /* Quit */ if (haptic != NULL) SDL_HapticClose(haptic); SDL_Quit(); return 0; }
void Application::OnEvent(SDL_Event* Event) { if(Event->type == SDL_QUIT) { Running = false; } if(Event->type == SDL_JOYAXISMOTION) { if(Event->jaxis.axis == 0) { if(Event->jaxis.value > 5000 || Event->jaxis.value < -5000) { astate->xcont = (double) Event->jaxis.value / 32767.0; } else { astate->xcont = 0; } } if(Event->jaxis.axis == 3) { astate->targetx = (double) Event->jaxis.value / 32767.0; } if(Event->jaxis.axis == 4) { astate->targety = -(double) Event->jaxis.value / 32767.0; } } if(Event->type == SDL_KEYDOWN) { if(Event->key.keysym.sym == SDLK_LEFT) { astate->xcont--; } if(Event->key.keysym.sym == SDLK_RIGHT) { astate->xcont++; } if(astate->xcont > 0) { astate->xcont = 1; } else if (astate->xcont < 0) { astate->xcont = -1; } if(Event->key.keysym.sym == SDLK_ESCAPE) { Running = false; } } if(Event->type == SDL_KEYUP) { if(Event->key.keysym.sym == SDLK_LEFT) { astate->xcont++; } if(Event->key.keysym.sym == SDLK_RIGHT) { astate->xcont--; } if(astate->xcont > 0) { astate->xcont = 1; } else if (astate->xcont < 0) { astate->xcont = -1; } } // ref for below: // jbutton.button 0 = A // jbutton.button 1 = B // jbutton.button 2 = X // jbutton.button 3 = Y // jbutton.button 4 = left bump // jbutton.button 5 = right bump if (Event->type == SDL_JOYBUTTONDOWN) { if (Event->jbutton.button == 4 || Event->jbutton.button == 5) { astate->pushing = true; if (haptic != NULL) { SDL_HapticRunEffect(haptic, effect_id, SDL_HAPTIC_INFINITY); } } else if (Event->jbutton.button == 3) { entities.push_back(Bullet::Create(&Level::p_level->world, graphics, Player::player->x + (astate->xcont >= 0 ? Player::player->width/1.2 : -Player::player->width/1.2), Player::player->y, astate->xcont >= 0 ? 100:-100,0)); printf("player at %g %g\n",(Player::player->x),(Player::player->y)); // (Player::player->x)*10, // (Player::player->y)*10,4,0)); if (astate->xcont >= 0.0) { Player::player->shoot_right = true; } else { Player::player->shoot_left = true; } } /// \todo Get these controls unconnected else if (Event->jbutton.button == 2) { if (astate->xcont >= 0.0) { Player::player->swing_right = true; } else { Player::player->swing_left = true; } } } if (Event->type == SDL_JOYBUTTONUP) { if (Event->jbutton.button == 4 || Event->jbutton.button == 5) { astate->pushing = false; if (haptic != NULL) { SDL_HapticStopEffect(haptic, effect_id); } } } }
/** * @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)); HapticPrintSupported(haptic); } else { printf("No Haptic devices found!\n"); return 1; } /* We only want force feedback errors. */ SDL_ClearError(); /* Create effects. */ memset(&efx, 0, sizeof(efx)); nefx = 0; supported = SDL_HapticQuery(haptic); printf("\nUploading effects\n"); /* First we'll try a SINE effect. */ if (supported & SDL_HAPTIC_SINE) { printf(" effect %d: Sine Wave\n", nefx); efx[nefx].type = SDL_HAPTIC_SINE; efx[nefx].periodic.period = 1000; efx[nefx].periodic.magnitude = 0x4000; efx[nefx].periodic.length = 5000; efx[nefx].periodic.attack_length = 1000; efx[nefx].periodic.fade_length = 1000; id[nefx] = SDL_HapticNewEffect(haptic, &efx[nefx]); if (id[nefx] < 0) { printf("UPLOADING EFFECT ERROR: %s\n", SDL_GetError()); abort_execution(); } nefx++; } /* Now we'll try a SAWTOOTHUP */ if (supported & SDL_HAPTIC_SAWTOOTHUP) { printf(" effect %d: Sawtooth Up\n", nefx); efx[nefx].type = SDL_HAPTIC_SQUARE; efx[nefx].periodic.period = 500; efx[nefx].periodic.magnitude = 0x5000; efx[nefx].periodic.length = 5000; efx[nefx].periodic.attack_length = 1000; efx[nefx].periodic.fade_length = 1000; id[nefx] = SDL_HapticNewEffect(haptic, &efx[nefx]); if (id[nefx] < 0) { printf("UPLOADING EFFECT ERROR: %s\n", SDL_GetError()); abort_execution(); } nefx++; } /* Now the classical constant effect. */ if (supported & SDL_HAPTIC_CONSTANT) { printf(" effect %d: Constant Force\n", nefx); efx[nefx].type = SDL_HAPTIC_CONSTANT; efx[nefx].constant.direction.type = SDL_HAPTIC_POLAR; efx[nefx].constant.direction.dir[0] = 20000; /* Force comes from the south-west. */ efx[nefx].constant.length = 5000; efx[nefx].constant.level = 0x6000; efx[nefx].constant.attack_length = 1000; efx[nefx].constant.fade_length = 1000; id[nefx] = SDL_HapticNewEffect(haptic, &efx[nefx]); if (id[nefx] < 0) { printf("UPLOADING EFFECT ERROR: %s\n", SDL_GetError()); abort_execution(); } nefx++; } /* The cute spring effect. */ if (supported & SDL_HAPTIC_SPRING) { printf(" effect %d: Condition Spring\n", nefx); efx[nefx].type = SDL_HAPTIC_SPRING; efx[nefx].condition.length = 5000; for (i = 0; i < SDL_HapticNumAxes(haptic); i++) { efx[nefx].condition.right_sat[i] = 0x7FFF; efx[nefx].condition.left_sat[i] = 0x7FFF; efx[nefx].condition.right_coeff[i] = 0x2000; efx[nefx].condition.left_coeff[i] = 0x2000; efx[nefx].condition.center[i] = 0x1000; /* Displace the center for it to move. */ } id[nefx] = SDL_HapticNewEffect(haptic, &efx[nefx]); if (id[nefx] < 0) { printf("UPLOADING EFFECT ERROR: %s\n", SDL_GetError()); abort_execution(); } nefx++; } /* The pretty awesome inertia effect. */ if (supported & SDL_HAPTIC_INERTIA) { printf(" effect %d: Condition Inertia\n", nefx); efx[nefx].type = SDL_HAPTIC_SPRING; efx[nefx].condition.length = 5000; for (i = 0; i < SDL_HapticNumAxes(haptic); i++) { efx[nefx].condition.right_sat[i] = 0x7FFF; efx[nefx].condition.left_sat[i] = 0x7FFF; efx[nefx].condition.right_coeff[i] = 0x2000; efx[nefx].condition.left_coeff[i] = 0x2000; } id[nefx] = SDL_HapticNewEffect(haptic, &efx[nefx]); if (id[nefx] < 0) { printf("UPLOADING EFFECT ERROR: %s\n", SDL_GetError()); abort_execution(); } nefx++; } printf ("\nNow playing effects for 5 seconds each with 1 second delay between\n"); for (i = 0; i < nefx; i++) { printf(" Playing effect %d\n", i); SDL_HapticRunEffect(haptic, id[i], 1); SDL_Delay(6000); /* Effects only have length 5000 */ } /* Quit */ if (haptic != NULL) SDL_HapticClose(haptic); SDL_Quit(); return 0; }
/* * Haptic Feedback: * effect_volume=0..16 * effect{x,y,z} - effect direction * name - sound file name */ void Haptic_Feedback(char *name, int effect_volume, int effect_x, int effect_y, int effect_z) { #if SDL_VERSION_ATLEAST(2, 0, 0) int effect_type = HAPTIC_EFFECT_UNKNOWN; if (joy_haptic_magnitude->value <= 0) return; if (effect_volume <= 0) return; if (!joystick_haptic) return; if (last_haptic_volume != (int)(joy_haptic_magnitude->value * 255)) { IN_Haptic_Effects_Shutdown(); IN_Haptic_Effects_Init(); } last_haptic_volume = joy_haptic_magnitude->value * 255; if (strstr(name, "misc/menu")) { effect_type = HAPTIC_EFFECT_MENY; } else if (strstr(name, "weapons/blastf1a")) { effect_type = HAPTIC_EFFECT_BLASTER; } else if (strstr(name, "weapons/hyprbf1a")) { effect_type = HAPTIC_EFFECT_HYPER_BLASTER; } else if (strstr(name, "weapons/machgf")) { effect_type = HAPTIC_EFFECT_MACHINEGUN; } else if (strstr(name, "weapons/shotgf1b")) { effect_type = HAPTIC_EFFECT_SHOTGUN; } else if (strstr(name, "weapons/sshotf1b")) { effect_type = HAPTIC_EFFECT_SSHOTGUN; } else if (strstr(name, "weapons/railgf1a")) { effect_type = HAPTIC_EFFECT_RAILGUN; } else if (strstr(name, "weapons/rocklf1a") || strstr(name, "weapons/rocklx1a")) { effect_type = HAPTIC_EFFECT_ROCKETGUN; } else if (strstr(name, "weapons/grenlf1a") || strstr(name, "weapons/grenlx1a") || strstr(name, "weapons/hgrent1a")) { effect_type = HAPTIC_EFFECT_GRENADE; } else if (strstr(name, "weapons/bfg__f1y")) { effect_type = HAPTIC_EFFECT_BFG; } else if (strstr(name, "weapons/plasshot")) { effect_type = HAPTIC_EFFECT_PALANX; } else if (strstr(name, "weapons/rippfire")) { effect_type = HAPTIC_EFFECT_IONRIPPER; } else if (strstr(name, "weapons/nail1")) { effect_type = HAPTIC_EFFECT_ETFRIFLE; } else if (strstr(name, "weapons/shotg2")) { effect_type = HAPTIC_EFFECT_SHOTGUN2; } else if (strstr(name, "weapons/disint2")) { effect_type = HAPTIC_EFFECT_TRACKER; } else if (strstr(name, "player/male/pain") || strstr(name, "player/female/pain") || strstr(name, "players/male/pain") || strstr(name, "players/female/pain")) { effect_type = HAPTIC_EFFECT_PAIN; } else if (strstr(name, "player/step") || strstr(name, "player/land")) { effect_type = HAPTIC_EFFECT_STEP; } else if (strstr(name, "weapons/trapcock")) { effect_type = HAPTIC_EFFECT_TRAPCOCK; } if (effect_type != HAPTIC_EFFECT_UNKNOWN) { // check last effect for reuse if (last_haptic_efffect[last_haptic_efffect_pos].effect_type != effect_type || last_haptic_efffect[last_haptic_efffect_pos].effect_volume != effect_volume || last_haptic_efffect[last_haptic_efffect_pos].effect_x != effect_x || last_haptic_efffect[last_haptic_efffect_pos].effect_y != effect_y || last_haptic_efffect[last_haptic_efffect_pos].effect_z != effect_z) { // FIFO for effects last_haptic_efffect_pos = (last_haptic_efffect_pos+1) % last_haptic_efffect_size; IN_Haptic_Effect_Shutdown(&last_haptic_efffect[last_haptic_efffect_pos].effect_id); last_haptic_efffect[last_haptic_efffect_pos].effect_volume = effect_volume; last_haptic_efffect[last_haptic_efffect_pos].effect_type = effect_type; last_haptic_efffect[last_haptic_efffect_pos].effect_x = effect_x; last_haptic_efffect[last_haptic_efffect_pos].effect_y = effect_y; last_haptic_efffect[last_haptic_efffect_pos].effect_z = effect_z; last_haptic_efffect[last_haptic_efffect_pos].effect_id = IN_Haptic_Effects_To_Id( effect_type, effect_volume, effect_x, effect_y, effect_z); } SDL_HapticRunEffect(joystick_haptic, last_haptic_efffect[last_haptic_efffect_pos].effect_id, 1); } #endif }
// 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); }