add gamepad menu support

This commit is contained in:
Zack Buhman 2026-05-29 23:41:48 -05:00
parent fb3c8b7a04
commit 6bfe25ee07
4 changed files with 101 additions and 17 deletions

View File

@ -12,11 +12,16 @@ namespace renpy {
constexpr int yStride = 100;
};
extern int lastGamepadItem;
extern bool lastUseGamepad;
bool overlap(int menuWidth, int menuHeight,
int x, int y,
int mx, int my,
int windowWidth, int windowHeight);
void update(interpreter & state,
int mx, int my, bool mLeft,
bool gUp, bool gDown, bool gAccept,
bool useGamepad,
int windowWidth, int windowHeight);
}

View File

@ -1023,6 +1023,9 @@ int main()
audio::init();
audio::load(renpy::script::audio, renpy::script::audio_length);
bool useGamepad = false;
uint32_t whichGamepad = 0;
while (quit == false) {
audio::update();
@ -1063,6 +1066,7 @@ int main()
}
}
if (event.type == SDL_EVENT_MOUSE_MOTION) {
useGamepad = false;
if (event.motion.state & SDL_BUTTON_LMASK) {
//collada_state.mouse_motion(cameraIndex, cameraTargetIndex, event.motion.xrel, event.motion.yrel, 0);
}
@ -1079,6 +1083,11 @@ int main()
if (event.type == SDL_EVENT_GAMEPAD_REMOVED) {
remove_gamepad(event.gdevice.which);
}
if (event.type == SDL_EVENT_GAMEPAD_BUTTON_DOWN) {
whichGamepad = event.gbutton.which;
useGamepad = true;
fprintf(stderr, "use gamepad: which %d\n", whichGamepad);
}
}
//////////////////////////////////////////////////////////////////////
@ -1089,7 +1098,22 @@ int main()
float my;
uint32_t mouseFlags = SDL_GetMouseState(&mx, &my);
bool mLeft = (mouseFlags & SDL_BUTTON_LMASK) != 0;
bool gUp = false;
bool gDown = false;
bool gAccept = false;
if (useGamepad) {
for (int i = 0; i < gamepad_count; i++) {
if (SDL_GetGamepadID(gamepads[i]) == whichGamepad) {
gUp = SDL_GetGamepadButton(gamepads[i], SDL_GAMEPAD_BUTTON_DPAD_UP);
gDown = SDL_GetGamepadButton(gamepads[i], SDL_GAMEPAD_BUTTON_DPAD_DOWN);
gAccept = SDL_GetGamepadButton(gamepads[i], SDL_GAMEPAD_BUTTON_SOUTH) || SDL_GetGamepadButton(gamepads[i], SDL_GAMEPAD_BUTTON_EAST);
break;
}
}
}
renpy::update(interpreter_state, mx, my, mLeft,
gUp, gDown, gAccept, useGamepad,
surfaceCapabilities.currentExtent.width,
surfaceCapabilities.currentExtent.height);

View File

@ -30,34 +30,84 @@ namespace renpy {
return mxf >= minX && mxf <= maxX && myf >= minY && myf <= maxY;
}
static bool lastMenuPause = false;
static bool lastmLeft = false;
int lastGamepadItem = 0;
bool lastUseGamepad = false;
static bool lastgUp = false;
static bool lastgDown = false;
static bool lastgAccept = false;
static void jumpToMenuItem(interpreter & state, int i)
{
// jump to menu item
uint32_t optionIndex = state.menu.optionIndex + i;
assert(optionIndex < (uint32_t)script::options_length);
uint32_t next_pc = script::options[optionIndex].statementIndex;
fprintf(stderr, "interact[%d]: menu jump %d\n", state.pc, next_pc);
state.pc = next_pc;
state.pause.menu = false;
}
void update(interpreter & state,
int mx, int my, bool mLeft,
bool _gUp, bool _gDown, bool _gAccept,
bool useGamepad,
int windowWidth, int windowHeight)
{
lastUseGamepad = useGamepad;
bool mDown = mLeft && (!lastmLeft);
lastmLeft = mLeft;
//if (mDown) {
//state.pause.voice = false;
//}
if (!state.pause.menu || !mDown)
bool pauseTransition = state.pause.menu && (!lastMenuPause);
lastMenuPause = state.pause.menu;
bool gUp = _gUp && (!lastgUp);
bool gDown = _gDown && (!lastgDown);
bool gAccept = _gAccept && (!lastgAccept);
lastgUp = _gUp;
lastgDown = _gDown;
lastgAccept = _gAccept;
if (!state.pause.menu) {
return;
}
for (uint32_t i = 0; i < state.menu.count; i++) {
int y = menu::yStride * i + menu::y;
if (pauseTransition) {
fprintf(stderr, "interact::update: menu pause transition\n");
lastGamepadItem = 0;
}
bool overlap = renpy::overlap(menu::width, menu::height, menu::x, y, mx, my, windowWidth, windowHeight);
if (overlap) {
// jump to menu item
uint32_t optionIndex = state.menu.optionIndex + i;
assert(optionIndex < (uint32_t)script::options_length);
uint32_t next_pc = script::options[optionIndex].statementIndex;
fprintf(stderr, "interact[%d]: menu jump %d\n", state.pc, next_pc);
state.pc = next_pc;
state.pause.menu = false;
break;
if (useGamepad) {
//printf("useGamepad %d %d\n", gUp, _gAccept);
if (gUp) {
lastGamepadItem -= 1;
if (lastGamepadItem < 0)
lastGamepadItem = state.menu.count - 1;
}
if (gDown) {
lastGamepadItem += 1;
if (lastGamepadItem >= (int)state.menu.count)
lastGamepadItem = 0;
}
if (gAccept) {
jumpToMenuItem(state, lastGamepadItem);
}
} else {
// use mouse
for (uint32_t i = 0; i < state.menu.count; i++) {
int y = menu::yStride * i + menu::y;
bool overlap = renpy::overlap(menu::width, menu::height, menu::x, y, mx, my, windowWidth, windowHeight);
if (overlap) {
lastGamepadItem = i;
if (mDown) {
jumpToMenuItem(state, i);
return;
}
}
}
}
}

View File

@ -534,7 +534,12 @@ namespace renpy {
for (uint32_t i = 0; i < state.menu.count; i++) {
int y = menu::yStride * i + menu::y;
bool overlap = renpy::overlap(menu::width, menu::height, menu::x, y, mx, my, windowWidth, windowHeight);
bool overlap = false;
if (renpy::lastUseGamepad) {
overlap = (i == (uint32_t)lastGamepadItem);
} else {
overlap = renpy::overlap(menu::width, menu::height, menu::x, y, mx, my, windowWidth, windowHeight);
}
instanceMappedData[maximumImageCount * frameIndex + outputIndex++] = {
.size = {menu::width, menu::height},
.topLeft = {menu::x, (int16_t)(y)},