/** * @brief Initializes the rumble effect. * * @return 0 on success. */ static int spfx_hapticInit (void) { #if SDL_VERSION_ATLEAST(1,3,0) SDL_HapticEffect *efx; /* Haptic must be enabled. */ if (haptic == NULL) return 0; efx = &haptic_rumbleEffect; memset( efx, 0, sizeof(SDL_HapticEffect) ); efx->type = SDL_HAPTIC_SINE; efx->periodic.direction.type = SDL_HAPTIC_POLAR; efx->periodic.length = 1000; efx->periodic.period = 200; efx->periodic.magnitude = 0x4000; efx->periodic.fade_length = 1000; efx->periodic.fade_level = 0; haptic_rumble = SDL_HapticNewEffect( haptic, efx ); if (haptic_rumble < 0) { WARN("Unable to upload haptic effect: %s.", SDL_GetError()); return -1; } #endif /* SDL_VERSION_ATLEAST(1,3,0) */ return 0; }
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; }
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); }
/* * Init haptic effects */ static int IN_Haptic_Effect_Init(int effect_x, int effect_y, int effect_z, int period, int magnitude, int length, int attack, int fade) { /* * Direction: * North - 0 * East - 9000 * South - 18000 * West - 27000 */ int effect_id; static SDL_HapticEffect haptic_effect; SDL_memset(&haptic_effect, 0, sizeof(SDL_HapticEffect)); // 0 is safe default haptic_effect.type = SDL_HAPTIC_SINE; haptic_effect.periodic.direction.type = SDL_HAPTIC_CARTESIAN; // Cartesian/3d coordinates haptic_effect.periodic.direction.dir[0] = effect_x; haptic_effect.periodic.direction.dir[1] = effect_y; haptic_effect.periodic.direction.dir[2] = effect_z; haptic_effect.periodic.period = period; haptic_effect.periodic.magnitude = magnitude; haptic_effect.periodic.length = length; haptic_effect.periodic.attack_length = attack; haptic_effect.periodic.fade_length = fade; effect_id = SDL_HapticNewEffect(joystick_haptic, &haptic_effect); if (effect_id < 0) { Com_Printf ("SDL_HapticNewEffect failed: %s\n", SDL_GetError()); Com_Printf ("Please try to rerun game. Effects will be disabled for now.\n"); IN_Haptic_Shutdown(); } return effect_id; }
/* * Init haptic effects */ static int IN_Haptic_Effect_Init(int dir, int period, int magnitude, int length, int attack, int fade) { /* * Direction: * North - 0 * East - 9000 * South - 18000 * West - 27000 */ int effect_id; static SDL_HapticEffect haptic_effect; SDL_memset(&haptic_effect, 0, sizeof(SDL_HapticEffect)); // 0 is safe default haptic_effect.type = SDL_HAPTIC_SINE; haptic_effect.periodic.direction.type = SDL_HAPTIC_POLAR; // Polar coordinates haptic_effect.periodic.direction.dir[0] = dir; haptic_effect.periodic.period = period; haptic_effect.periodic.magnitude = magnitude; haptic_effect.periodic.length = length; haptic_effect.periodic.attack_length = attack; haptic_effect.periodic.fade_length = fade; effect_id = SDL_HapticNewEffect(joystick_haptic, &haptic_effect); if (effect_id < 0) { Com_Printf ("SDL_HapticNewEffect failed: %s", SDL_GetError()); } return effect_id; }
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; }
void JoystickInfo::InitHapticEffect() { #if SDL_MAJOR_VERSION >= 2 if (haptic == NULL) return; #if 0 additional field of the effect /* Trigger */ Uint16 button; /**< Button that triggers the effect. */ Uint16 interval; /**< How soon it can be triggered again after button. */ // periodic parameter Sint16 offset; /**< Mean value of the wave. */ Uint16 phase; /**< Horizontal shift given by hundredth of a cycle. */ #endif /*******************************************************************/ /* Effect big & small */ /*******************************************************************/ for (int new_effect = 0; new_effect < 2 ; new_effect++) { // Direction of the effect SDL_HapticDirection haptic_effect_data[new_effect].periodic.direction.type = SDL_HAPTIC_POLAR; // Polar coordinates haptic_effect_data[new_effect].periodic.direction.dir[0] = 18000; // Force comes from south // periodic parameter haptic_effect_data[new_effect].periodic.period = 20; // 20 ms haptic_effect_data[new_effect].periodic.magnitude = 2000; // 2000/32767 strength // Replay haptic_effect_data[new_effect].periodic.length = 60; // 60 ms long haptic_effect_data[new_effect].periodic.delay = 0; // start 0 second after the upload // enveloppe haptic_effect_data[new_effect].periodic.attack_length = 5;// Takes 5 ms to get max strength haptic_effect_data[new_effect].periodic.attack_level = 0; // start at 0 haptic_effect_data[new_effect].periodic.fade_length = 5; // Takes 5 ms to fade away haptic_effect_data[new_effect].periodic.fade_level = 0; // finish at 0 } /*******************************************************************/ /* Effect small */ /*******************************************************************/ haptic_effect_data[0].type = SDL_HAPTIC_LEFTRIGHT; /*******************************************************************/ /* Effect big */ /*******************************************************************/ haptic_effect_data[1].type = SDL_HAPTIC_TRIANGLE; /*******************************************************************/ /* Upload effect to the device */ /*******************************************************************/ for (int i = 0 ; i < 2 ; i++) haptic_effect_id[i] = SDL_HapticNewEffect(haptic, &haptic_effect_data[i]); #endif }
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 }
JNIEXPORT jint JNICALL Java_at_wisch_joystick_FFJoystick_newEffectNative (JNIEnv *env, jclass, jint hapticDeviceIndex, jobject jEffect, jint effectType){ SDL_HapticEffect *effect = getEffectFromJavaEffect(env, jEffect, effectType); int num = SDL_HapticNewEffect(ffjoysticks[hapticDeviceIndex], effect); if (num < 0) { throwException(env, SDL_GetError()); return -21; } if (effect->type == SDL_HAPTIC_CUSTOM){ delete(effect->custom.data); } delete(effect); 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; }
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); } }
/* * Initializes the haptic device for simple rumble playback. */ int SDL_HapticRumbleInit(SDL_Haptic * haptic) { if (!ValidHaptic(haptic)) { return -1; } /* Already allocated. */ if (haptic->rumble_id >= 0) { return 0; } /* Copy over. */ SDL_HapticRumbleCreate(&haptic->rumble_effect); haptic->rumble_id = SDL_HapticNewEffect(haptic, &haptic->rumble_effect); if (haptic->rumble_id >= 0) { return 0; } return -1; }
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; }
/* * Initializes the haptic device for simple rumble playback. */ int SDL_HapticRumbleInit(SDL_Haptic * haptic) { SDL_HapticEffect *efx = &haptic->rumble_effect; if (!ValidHaptic(haptic)) { return -1; } /* Already allocated. */ if (haptic->rumble_id >= 0) { return 0; } SDL_zerop(efx); if (haptic->supported & SDL_HAPTIC_SINE) { efx->type = SDL_HAPTIC_SINE; efx->periodic.period = 1000; efx->periodic.magnitude = 0x4000; efx->periodic.length = 5000; efx->periodic.attack_length = 0; efx->periodic.fade_length = 0; } else if (haptic->supported & SDL_HAPTIC_LEFTRIGHT) { /* XInput? */ efx->type = SDL_HAPTIC_LEFTRIGHT; efx->leftright.length = 5000; efx->leftright.large_magnitude = 0x4000; efx->leftright.small_magnitude = 0x4000; } else { return SDL_SetError("Device doesn't support rumble"); } haptic->rumble_id = SDL_HapticNewEffect(haptic, &haptic->rumble_effect); if (haptic->rumble_id >= 0) { return 0; } return -1; }
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; }
// 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); }
bool Application::OnInit() { if(SDL_Init(SDL_INIT_EVERYTHING) < 0) { return false; } // Set up graphics SDL_Window *screen = SDL_CreateWindow("Psychokinesis", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, screenw, screenh, SDL_WINDOW_OPENGL); if(screen == NULL) { Logger::log("SDL_CreateWindow failure"); return false; } if((graphics.renderer = SDL_CreateRenderer(screen, -1, 0)) == NULL) { Logger::log("SDL_CreateRenderer failure"); return false; } graphics.camera = new Camera(); entities.push_back(new Entity(new CameraControl(graphics.camera), new NullPhysicsComponent(), new NullRenderComponent())); // Set up joystick controls std::stringstream ss; ss << SDL_NumJoysticks() << " joysticks were found"; Logger::log(ss.str()); SDL_JoystickEventState(SDL_ENABLE); joystick = SDL_JoystickOpen(0); // Set up rumble effects haptic = SDL_HapticOpen( 0 ); if (haptic == NULL) { Logger::log("SDL_HapticOpen failure"); } if (haptic != NULL && SDL_HapticRumbleInit( haptic ) != 0) { Logger::log("SDL_HapticRumbleInit failure: " + std::string(SDL_GetError())); haptic = NULL; } SDL_HapticEffect effect; memset(&effect, 0, sizeof(SDL_HapticEffect)); effect.type = SDL_HAPTIC_SINE; effect.periodic.direction.type = SDL_HAPTIC_POLAR; // Polar coordinates effect.periodic.direction.dir[0] = 18000; // Force comes from south effect.periodic.period = 1000; // 1000 ms effect.periodic.magnitude = 20000; // 20000/32767 strength effect.periodic.length = 1000; // .1 seconds long effect.periodic.attack_length = 0; // Takes 0 seconds to get max strength effect.periodic.fade_length = 0; // Takes 0 seconds to fade away effect_id = SDL_HapticNewEffect(haptic, &effect); Logger::log("Creating player"); Create(Entity::PLAYER, 4, 20); // Test blocks to shove around // Create(Entity::LITTLE_MAN, 26, 25); // Create(Entity::LITTLE_MAN, 21, 25); // Create(Entity::BIG_MAN, 17, 25); // Create(Entity::LITTLE_MAN, 26, 20); // Create(Entity::LITTLE_MAN, 11, 20); // Create(Entity::LITTLE_MAN, 7, 20); // Create(Entity::LITTLE_MAN, 26, 35); Create(Entity::LITTLE_MAN, 21, 35); Create(Entity::BIG_MAN, 17, 35); Create(Entity::LITTLE_MAN, 26, 30); Create(Entity::LITTLE_MAN, 11, 30); Create(Entity::LITTLE_MAN, 7, 30); /// \todo Make the bullet factory manage its own list entities.push_back(Bullet::Create(&Level::p_level->world, graphics, 20, 30, 20, 0)); mainhud.Hud_Load_Hit_Pts_Texture("art_assets/hit_pts_meter.png", graphics.renderer, Player::player->hit_pts); if(level.LoadAssets(graphics.renderer, "art_assets/sky2.png", "art_assets/lanscape.png") == NULL) { Logger::log("Level loading failure: " + std::string(SDL_GetError())); } Level::p_level->world.SetContactListener(&contactListen); oldtime = SDL_GetTicks(); 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[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; }
bool SDL2FFBDevice::uploadEffect(const int idx, const FFBEffectTypes type, std::shared_ptr<FFBEffectParameters> parameters) { SDL_HapticEffect* underlEff; int intIdx; std::shared_ptr<FFBEffect> effect = SDL2FFBEffectFactory::createEffect(type); std::shared_ptr<SDL2FFBEffect> sdlEff; CHECK_EFFECT_IDX(idx); if (type != FFBEffectTypes::NONE) sdlEff = std::static_pointer_cast<SDL2FFBEffect>(effect); else return false; if (sdlEff == nullptr) return false; if (!sdlEff->setParameters(parameters)) return false; /* There is no effect in the selected slot */ if (m_effects[idx]->type() != FFBEffectTypes::NONE) { /* Effects are not of the same type, delete the previous effect and create a new one */ if (*m_effects[idx] != *sdlEff) { if (!removeEffect(idx)) { return false; } } else { /* Effects are of the same type, update it */ underlEff = sdlEff->createFFstruct(); if (underlEff == nullptr) return false; intIdx = SDL_HapticUpdateEffect(c_haptic, std::static_pointer_cast<SDL2FFBEffect>(m_effects[idx])->internalIdx(), underlEff); if (intIdx < 0) { QMessageBox::critical(nullptr, SDL2DEV_ERR_CAPTION, QString("Unable to update the effect:\n%1").arg(SDL_GetError())); m_effects[idx]->setStatus(FFBEffect::FFBEffectStatus::UPLOADED); return true; } sdlEff->setStatus(m_effects[idx]->status()); goto out; } } underlEff = sdlEff->createFFstruct(); if (underlEff == nullptr) return false; intIdx = SDL_HapticNewEffect(c_haptic, underlEff); if (intIdx < 0) { QMessageBox::critical(nullptr, SDL2DEV_ERR_CAPTION, QString("Unable to create effect:\n%1").arg(SDL_GetError())); return false; } sdlEff->setStatus(FFBEffect::FFBEffectStatus::UPLOADED); out: sdlEff->setInternalIdx(intIdx); delete underlEff; m_effects[idx] = sdlEff; return true; }
ForceFeedback::ForceFeedback( const std::string & device, std::ostream & error_output, std::ostream & info_output) : device_name(device), enabled(true), lastforce(0), haptic(0), effect_id(-1) { // Close haptic if already open. if (haptic) { SDL_HapticClose(haptic); haptic = NULL; } // Do we have force feedback devices? int haptic_num = SDL_NumHaptics(); if (haptic_num == 0) { info_output << "No force feedback devices found." << std::endl; return; } info_output << "Number of force feedback devices: " << haptic_num << std::endl; // Try to create haptic device. int haptic_id = 0; haptic = SDL_HapticOpen(haptic_id); if (!haptic) { error_output << "Failed to initialize force feedback device: " << SDL_GetError(); return; } // Check for constant force support. unsigned int haptic_query = SDL_HapticQuery(haptic); if (!(haptic_query & SDL_HAPTIC_CONSTANT)) { error_output << "Constant force feedback not supported: " << SDL_GetError(); return; } // Create the effect. memset(&effect, 0, sizeof(SDL_HapticEffect) ); // 0 is safe default effect.type = SDL_HAPTIC_CONSTANT; effect.constant.direction.type = SDL_HAPTIC_CARTESIAN; // Using cartesian direction encoding. effect.constant.direction.dir[0] = 1; // X position effect.constant.direction.dir[1] = 0; // Y position effect.constant.length = 0xffff; effect.constant.delay = 0; effect.constant.button = 0; effect.constant.interval = 0; effect.constant.level = 0; effect.constant.attack_length = 0; effect.constant.attack_level = 0; effect.constant.fade_length = 0; effect.constant.fade_level = 0; // Upload the effect. effect_id = SDL_HapticNewEffect(haptic, &effect); if (effect_id == -1) { error_output << "Failed to initialize force feedback effect: " << SDL_GetError(); return; } info_output << "Force feedback enabled." << std::endl; }
bool SdlRumbleEffect::load() { mId = SDL_HapticNewEffect(mHaptic, &mEffect); return isActive(); }