Skip to content

Commit

Permalink
Merge pull request libretro#162 from jdgleaver/rumble
Browse files Browse the repository at this point in the history
Add rumble support
  • Loading branch information
inactive123 authored Nov 18, 2020
2 parents 094b576 + ba86c02 commit 93e27de
Show file tree
Hide file tree
Showing 3 changed files with 145 additions and 17 deletions.
102 changes: 97 additions & 5 deletions libgambatte/libretro/libretro.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -513,6 +513,75 @@ static void check_frame_blend_variable(void)
/* Interframe blending END */
/***************************/

/************************/
/* Rumble support START */
/************************/

static struct retro_rumble_interface rumble = {0};
static uint16_t rumble_strength_last = 0;
static uint16_t rumble_strength_up = 0;
static uint16_t rumble_strength_down = 0;
static uint16_t rumble_level = 0;
static bool rumble_active = false;

void cartridge_set_rumble(unsigned active)
{
if (!rumble.set_rumble_state ||
!rumble_level)
return;

if (active)
rumble_strength_up++;
else
rumble_strength_down++;

rumble_active = true;
}

static void apply_rumble(void)
{
uint16_t strength;

if (!rumble.set_rumble_state ||
!rumble_level)
return;

strength = (rumble_strength_up > 0) ?
(rumble_strength_up * rumble_level) /
(rumble_strength_up + rumble_strength_down) : 0;

rumble_strength_up = 0;
rumble_strength_down = 0;

if (strength == rumble_strength_last)
return;

rumble.set_rumble_state(0, RETRO_RUMBLE_WEAK, strength);
rumble.set_rumble_state(0, RETRO_RUMBLE_STRONG, strength);

rumble_strength_last = strength;
}

static void deactivate_rumble(void)
{
rumble_strength_up = 0;
rumble_strength_down = 0;
rumble_active = false;

if (!rumble.set_rumble_state ||
(rumble_strength_last == 0))
return;

rumble.set_rumble_state(0, RETRO_RUMBLE_WEAK, 0);
rumble.set_rumble_state(0, RETRO_RUMBLE_STRONG, 0);

rumble_strength_last = 0;
}

/**********************/
/* Rumble support END */
/**********************/

bool file_present_in_system(std::string fname)
{
const char *systemdirtmp = NULL;
Expand Down Expand Up @@ -769,6 +838,10 @@ void retro_deinit(void)
video_buf = NULL;
deinit_frame_blending();
libretro_supports_bitmasks = false;

deactivate_rumble();
memset(&rumble, 0, sizeof(struct retro_rumble_interface));
rumble_level = 0;
}

void retro_set_environment(retro_environment_t cb)
Expand Down Expand Up @@ -1045,19 +1118,29 @@ static void check_variables(void)
darkFilterLevel = static_cast<unsigned>(atoi(var.value));
}
gb.setDarkFilterLevel(darkFilterLevel);

var.key = "gambatte_up_down_allowed";
var.value = NULL;

up_down_allowed = false;
var.key = "gambatte_up_down_allowed";
var.value = NULL;
if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value)
{
if (!strcmp(var.value, "enabled"))
up_down_allowed = true;
else
up_down_allowed = false;
}
else
up_down_allowed = false;

rumble_level = 0;
var.key = "gambatte_rumble_level";
var.value = NULL;
if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value)
{
rumble_level = atoi(var.value);
rumble_level = (rumble_level > 10) ? 10 : rumble_level;
rumble_level = (rumble_level > 0) ? ((0x1999 * rumble_level) + 0x5) : 0;
}
if (rumble_level == 0)
deactivate_rumble();

/* Interframe blending option has its own handler */
check_frame_blend_variable();
Expand Down Expand Up @@ -1352,6 +1435,11 @@ bool retro_load_game(const struct retro_game_info *info)
return false;
}

if (environ_cb(RETRO_ENVIRONMENT_GET_RUMBLE_INTERFACE, &rumble))
log_cb(RETRO_LOG_INFO, "Rumble environment supported.\n");
else
log_cb(RETRO_LOG_INFO, "Rumble environment not supported.\n");

struct retro_input_descriptor desc[] = {
{ 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_LEFT, "D-Pad Left" },
{ 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_UP, "D-Pad Up" },
Expand Down Expand Up @@ -1600,6 +1688,10 @@ void retro_run()
audio_batch_cb(sound_buf.i16, read_avail);
#endif

/* Apply any 'pending' rumble effects */
if (rumble_active)
apply_rumble();

frames_count++;

bool updated = false;
Expand Down
20 changes: 20 additions & 0 deletions libgambatte/libretro/libretro_core_options.h
Original file line number Diff line number Diff line change
Expand Up @@ -302,6 +302,26 @@ struct retro_core_option_definition option_defs_us[] = {
},
"disabled"
},
{
"gambatte_rumble_level",
"Gamepad Rumble Strength",
"Enables haptic feedback effects for supported games (Pokemon Pinball, Perfect Dark...).",
{
{ "0", NULL },
{ "1", NULL },
{ "2", NULL },
{ "3", NULL },
{ "4", NULL },
{ "5", NULL },
{ "6", NULL },
{ "7", NULL },
{ "8", NULL },
{ "9", NULL },
{ "10", NULL },
{ NULL, NULL },
},
"10"
},
#ifdef HAVE_NETWORK
{
"gambatte_show_gb_link_settings",
Expand Down
40 changes: 28 additions & 12 deletions libgambatte/src/mem/cartridge.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@
#include <string.h>
#include <algorithm>

extern void cartridge_set_rumble(unsigned active);

namespace gambatte
{

Expand Down Expand Up @@ -417,36 +419,49 @@ namespace gambatte
unsigned short rombank;
unsigned char rambank;
bool enableRam;
bool hasRumble;
static unsigned adjustedRombank(const unsigned bank) { return bank; }
void setRambank() const {
memptrs.setRambank(enableRam ? MemPtrs::READ_EN | MemPtrs::WRITE_EN : 0,
rambank & (rambanks(memptrs) - 1));
}
void setRombank() const { memptrs.setRombank(adjustedRombank(rombank) & (rombanks(memptrs) - 1));}
public:
explicit Mbc5(MemPtrs &memptrs)
explicit Mbc5(MemPtrs &memptrs, bool rumble)
: memptrs(memptrs),
rombank(1),
rambank(0),
enableRam(false)
enableRam(false),
hasRumble(rumble)
{
}
virtual void romWrite(const unsigned P, const unsigned data) {
switch (P >> 13 & 3) {
case 0:
switch (P >> 12 & 0x7) {
case 0x0:
case 0x1:
enableRam = (data & 0xF) == 0xA;
setRambank();
break;
case 1:
case 0x2:
case 0x3:
rombank = P < 0x3000 ? (rombank & 0x100) | data
: (data << 8 & 0x100) | (rombank & 0xFF);
setRombank();
break;
case 2:
rambank = data & 0xF;
case 0x4:
case 0x5:
if(hasRumble && ((P >> 12 & 0x7) == 4))
{
cartridge_set_rumble((data >> 3) & 1);
rambank = (data & ~8) & 0x0f;
}
else
{
rambank = data & 0x0f;
}
setRambank();
break;
case 3:
default:
break;
}
}
Expand Down Expand Up @@ -527,6 +542,7 @@ namespace gambatte
unsigned rombanks = 2;
bool cgb = false;
enum Cartridgetype { PLAIN, MBC1, MBC2, MBC3, MBC5, HUC1, HUC3 } type = PLAIN;
bool rumble = false;

{
unsigned i;
Expand Down Expand Up @@ -558,9 +574,9 @@ namespace gambatte
case 0x19: printf("MBC5 ROM loaded.\n"); type = MBC5; break;
case 0x1A: printf("MBC5 ROM+RAM loaded.\n"); type = MBC5; break;
case 0x1B: printf("MBC5 ROM+RAM+BATTERY loaded.\n"); type = MBC5; break;
case 0x1C: printf("MBC5+RUMBLE ROM not supported.\n"); type = MBC5; break;
case 0x1D: printf("MBC5+RUMBLE+RAM ROM not suported.\n"); type = MBC5; break;
case 0x1E: printf("MBC5+RUMBLE+RAM+BATTERY ROM not supported.\n"); type = MBC5; break;
case 0x1C: printf("MBC5+RUMBLE ROM loaded.\n"); type = MBC5; rumble = true; break;
case 0x1D: printf("MBC5+RUMBLE+RAM ROM loaded.\n"); type = MBC5; rumble = true; break;
case 0x1E: printf("MBC5+RUMBLE+RAM+BATTERY ROM loaded.\n"); type = MBC5; rumble = true; break;
case 0x20: printf("MBC6 ROM not supported.\n"); return -1;
case 0x22: printf("MBC7 ROM not supported.\n"); return -1;
case 0xFC: printf("Pocket Camera ROM not supported.\n"); return -1;
Expand Down Expand Up @@ -630,7 +646,7 @@ namespace gambatte
break;
case MBC2: mbc.reset(new Mbc2(memptrs_)); break;
case MBC3: mbc.reset(new Mbc3(memptrs_, hasRtc(memptrs_.romdata()[0x147]) ? &rtc_ : 0)); break;
case MBC5: mbc.reset(new Mbc5(memptrs_)); break;
case MBC5: mbc.reset(new Mbc5(memptrs_, rumble)); break;
case HUC1: mbc.reset(new HuC1(memptrs_)); break;
case HUC3:
huc3_.set(true);
Expand Down

0 comments on commit 93e27de

Please sign in to comment.