mirror of
https://github.com/Mr-Wiseguy/Zelda64Recomp.git
synced 2024-11-22 12:59:14 +01:00
control rumble intensity to mimic n64 rumble pak & separate rumble from input
This commit is contained in:
parent
fa8092b70e
commit
51759611e1
@ -118,6 +118,7 @@ namespace recomp {
|
||||
|
||||
void get_n64_input(uint16_t* buttons_out, float* x_out, float* y_out);
|
||||
void set_rumble(bool);
|
||||
void update_rumble();
|
||||
void handle_events();
|
||||
|
||||
// Rumble strength ranges from 0 to 100.
|
||||
|
@ -13,16 +13,108 @@ void recomp_set_current_frame_poll_id();
|
||||
void PadMgr_HandleRetrace(void);
|
||||
void PadMgr_LockPadData(void);
|
||||
void PadMgr_UnlockPadData(void);
|
||||
void PadMgr_UpdateRumble(void);
|
||||
void PadMgr_UpdateConnections(void);
|
||||
void PadMgr_UpdateInputs(void);
|
||||
void PadMgr_InitVoice(void);
|
||||
OSMesgQueue* PadMgr_AcquireSerialEventQueue(void);
|
||||
void PadMgr_ReleaseSerialEventQueue(OSMesgQueue* serialEventQueue);
|
||||
|
||||
void PadMgr_ThreadEntry() {
|
||||
// @recomp Controller polling was moved to the main thread, so there's nothing to do here.
|
||||
|
||||
extern PadMgr* sPadMgrInstance;
|
||||
extern s32 sPadMgrRetraceCount;
|
||||
extern FaultMgr gFaultMgr;
|
||||
extern s32 sVoiceInitStatus;
|
||||
|
||||
|
||||
typedef enum {
|
||||
/* 0 */ VOICE_INIT_FAILED, // voice initialization failed
|
||||
/* 1 */ VOICE_INIT_TRY, // try to initialize voice
|
||||
/* 2 */ VOICE_INIT_SUCCESS // voice initialized
|
||||
} VoiceInitStatus;
|
||||
|
||||
void recomp_update_rumble();
|
||||
|
||||
void PadMgr_HandleRetrace(void) {
|
||||
// Execute rumble callback
|
||||
if (sPadMgrInstance->rumbleRetraceCallback != NULL) {
|
||||
sPadMgrInstance->rumbleRetraceCallback(sPadMgrInstance->rumbleRetraceArg);
|
||||
}
|
||||
|
||||
// Try and initialize a Voice Recognition Unit if not already attempted
|
||||
if (sVoiceInitStatus != VOICE_INIT_FAILED) {
|
||||
PadMgr_InitVoice();
|
||||
}
|
||||
|
||||
// Rumble Pak
|
||||
if (gFaultMgr.msgId != 0) {
|
||||
// If fault is active, no rumble
|
||||
PadMgr_RumbleStop();
|
||||
} else if (sPadMgrInstance->rumbleOffTimer > 0) {
|
||||
// If the rumble off timer is active, no rumble
|
||||
--sPadMgrInstance->rumbleOffTimer;
|
||||
PadMgr_RumbleStop();
|
||||
} else if (sPadMgrInstance->rumbleOnTimer == 0) {
|
||||
// If the rumble on timer is inactive, no rumble
|
||||
PadMgr_RumbleStop();
|
||||
} else if (!sPadMgrInstance->isResetting) {
|
||||
// If not resetting, update rumble
|
||||
PadMgr_UpdateRumble();
|
||||
--sPadMgrInstance->rumbleOnTimer;
|
||||
}
|
||||
|
||||
recomp_update_rumble();
|
||||
}
|
||||
|
||||
void poll_inputs(void) {
|
||||
OSMesgQueue* serialEventQueue = PadMgr_AcquireSerialEventQueue();
|
||||
// Begin reading controller data
|
||||
osContStartReadData(serialEventQueue);
|
||||
|
||||
// Wait for controller data
|
||||
osRecvMesg(serialEventQueue, NULL, OS_MESG_BLOCK);
|
||||
osContGetReadData(sPadMgrInstance->pads);
|
||||
|
||||
// Clear all but controller 1
|
||||
bzero(&sPadMgrInstance->pads[1], sizeof(*sPadMgrInstance->pads) * (MAXCONTROLLERS - 1));
|
||||
|
||||
// If in PreNMI, clear all controllers
|
||||
if (sPadMgrInstance->isResetting) {
|
||||
bzero(sPadMgrInstance->pads, sizeof(sPadMgrInstance->pads));
|
||||
}
|
||||
|
||||
// Query controller statuses
|
||||
osContStartQuery(serialEventQueue);
|
||||
osRecvMesg(serialEventQueue, NULL, OS_MESG_BLOCK);
|
||||
osContGetQuery(sPadMgrInstance->padStatus);
|
||||
|
||||
// Lock serial message queue
|
||||
PadMgr_ReleaseSerialEventQueue(serialEventQueue);
|
||||
|
||||
// Update connections
|
||||
PadMgr_UpdateConnections();
|
||||
|
||||
// Lock input data
|
||||
PadMgr_LockPadData();
|
||||
|
||||
// Update input data
|
||||
PadMgr_UpdateInputs();
|
||||
|
||||
// Execute input callback
|
||||
if (sPadMgrInstance->inputRetraceCallback != NULL) {
|
||||
sPadMgrInstance->inputRetraceCallback(sPadMgrInstance->inputRetraceArg);
|
||||
}
|
||||
|
||||
// Unlock input data
|
||||
PadMgr_UnlockPadData();
|
||||
sPadMgrRetraceCount++;
|
||||
}
|
||||
|
||||
// @recomp Patched to do the actual input polling.
|
||||
void PadMgr_GetInput(Input* inputs, s32 gameRequest) {
|
||||
// @recomp Do an actual poll if gameRequest is true.
|
||||
if (gameRequest) {
|
||||
PadMgr_HandleRetrace();
|
||||
poll_inputs();
|
||||
// @recomp Tag the current frame's input polling id for latency tracking.
|
||||
recomp_set_current_frame_poll_id();
|
||||
}
|
||||
|
@ -9,6 +9,12 @@
|
||||
#define osFlashWriteArray osFlashWriteArray_recomp
|
||||
#define osFlashWriteBuffer osFlashWriteBuffer_recomp
|
||||
#define osWritebackDCache osWritebackDCache_recomp
|
||||
|
||||
#define osContStartReadData osContStartReadData_recomp
|
||||
#define osContGetReadData osContGetReadData_recomp
|
||||
#define osContStartQuery osContStartQuery_recomp
|
||||
#define osContGetQuery osContGetQuery_recomp
|
||||
|
||||
#define sinf __sinf_recomp
|
||||
#define cosf __cosf_recomp
|
||||
#define bzero bzero_recomp
|
||||
|
@ -42,3 +42,8 @@ osFlashWriteArray_recomp = 0x8F000060;
|
||||
osFlashWriteBuffer_recomp = 0x8F000064;
|
||||
osWritebackDCache_recomp = 0x8F000068;
|
||||
recomp_get_pending_set_time = 0x8F00006C;
|
||||
osContStartReadData_recomp = 0x8F000070;
|
||||
osContGetReadData_recomp = 0x8F000074;
|
||||
osContStartQuery_recomp = 0x8F000078;
|
||||
osContGetQuery_recomp = 0x8F00007C;
|
||||
recomp_update_rumble = 0x8F000080;
|
||||
|
@ -31,6 +31,8 @@ static struct {
|
||||
std::array<float, 2> rotation_delta{};
|
||||
std::mutex pending_rotation_mutex;
|
||||
std::array<float, 2> pending_rotation_delta{};
|
||||
float cur_rumble;
|
||||
bool rumble_active;
|
||||
} InputState;
|
||||
|
||||
std::atomic<recomp::InputDevice> scanning_device = recomp::InputDevice::COUNT;
|
||||
@ -370,10 +372,34 @@ void recomp::poll_inputs() {
|
||||
}
|
||||
|
||||
void recomp::set_rumble(bool on) {
|
||||
uint16_t rumble_strength = recomp::get_rumble_strength() * 0xFFFF / 100;
|
||||
InputState.rumble_active = on;
|
||||
}
|
||||
|
||||
static float lerp(float from, float to, float amount) {
|
||||
return (from + (to - from) * amount);
|
||||
}
|
||||
static float smoothstep(float from, float to, float amount) {
|
||||
amount = (amount * amount) * (3.0f - 2.0f * amount);
|
||||
return lerp(from, to, amount);
|
||||
}
|
||||
|
||||
// Update rumble to attempt to mimic the way n64 rumble ramps up and falls off
|
||||
void recomp::update_rumble() {
|
||||
// Note: values are not accurate! just approximations based on feel
|
||||
if (InputState.rumble_active) {
|
||||
InputState.cur_rumble += 0.17f;
|
||||
if (InputState.cur_rumble > 1) InputState.cur_rumble = 1;
|
||||
} else {
|
||||
InputState.cur_rumble *= 0.92f;
|
||||
InputState.cur_rumble -= 0.01f;
|
||||
if (InputState.cur_rumble < 0) InputState.cur_rumble = 0;
|
||||
}
|
||||
float smooth_rumble = smoothstep(0, 1, InputState.cur_rumble);
|
||||
|
||||
uint16_t rumble_strength = smooth_rumble * (recomp::get_rumble_strength() * 0xFFFF / 100);
|
||||
uint32_t duration = 1000000; // Dummy duration value that lasts long enough to matter as the game will reset rumble on its own.
|
||||
for (const auto& controller : InputState.cur_controllers) {
|
||||
SDL_GameControllerRumble(controller, 0, on ? rumble_strength : 0, duration);
|
||||
SDL_GameControllerRumble(controller, 0, rumble_strength, duration);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -81,3 +81,7 @@ extern "C" void recomp_get_low_health_beeps_enabled(uint8_t* rdram, recomp_conte
|
||||
extern "C" void recomp_time_us(uint8_t* rdram, recomp_context* ctx) {
|
||||
_return(ctx, static_cast<u32>(std::chrono::duration_cast<std::chrono::microseconds>(ultramodern::time_since_start()).count()));
|
||||
}
|
||||
|
||||
extern "C" void recomp_update_rumble(uint8_t* rdram, recomp_context* ctx) {
|
||||
recomp::update_rumble();
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user