Merge pull request #45 from yoshisuga/touchscreen_superscope

Support SuperScope input for touchscreen devices (iOS, Android, Switch)
This commit is contained in:
Autechre 2020-12-28 04:43:17 +01:00 committed by GitHub
commit 6f947cbf2c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 195 additions and 10 deletions

View File

@ -92,8 +92,9 @@ auto SuperScope::latch(bool data) -> void {
auto SuperScope::latch() -> void {
int nx = platform->inputPoll(port, ID::Device::SuperScope, X);
int ny = platform->inputPoll(port, ID::Device::SuperScope, Y);
x = max(-16, min(256 + 16, nx + x));
y = max(-16, min((int)ppu.vdisp() + 16, ny + y));
bool relativeMode = configuration.input.pointer.relative;
x = max(-16, min(256 + 16, relativeMode ? x + nx : nx ));
y = max(-16, min((int)ppu.vdisp() + 16, relativeMode ? y + ny : ny));
offscreen = (x < 0 || y < 0 || x >= 256 || y >= (int)ppu.vdisp());
if(!offscreen) ppu.latchCounters(x, y);
}

View File

@ -39,6 +39,8 @@ auto Configuration::process(Markup::Node document, bool load) -> void {
bind(natural, "Hacks/SA1/Overclock", hacks.sa1.overclock);
bind(natural, "Hacks/SuperFX/Overclock", hacks.superfx.overclock);
bind(boolean, "Input/Pointer/Relative", input.pointer.relative);
#undef bind
}

View File

@ -65,6 +65,12 @@ struct Configuration {
} superfx;
} hacks;
struct Input {
struct Pointer {
bool relative = false;
} pointer;
} input;
private:
auto process(Markup::Node document, bool load) -> void;
};

View File

@ -24,13 +24,7 @@ else ifeq ($(platform),windows)
else ifeq ($(platform),macos)
$(strip $(compiler) -o out/$(name).dylib -shared $(objects) $(options))
else ifeq ($(platform), ios-arm64)
ifeq ($(IOSSDK),)
IOSSDK := $(shell xcodebuild -version -sdk iphoneos Path)
endif
$(strip c++ -arch arm64 -marm -miphoneos-version-min=11.0 -isysroot $(IOSSDK) -o out/$(name)_ios.dylib -shared $(objects) -lpthread -ldl)
$(strip c++ -arch arm64 -marm -miphoneos-version-min=11.0 -isysroot $(shell xcodebuild -version -sdk iphoneos Path) -o out/$(name)_ios.dylib -shared $(objects) -lpthread -ldl)
else ifeq ($(platform), tvos-arm64)
ifeq ($(IOSSDK),)
IOSSDK := $(shell xcodebuild -version -sdk appletvos Path)
endif
$(strip c++ -arch arm64 -marm -mtvos-version-min=11.0 -isysroot $(IOSSDK) -o out/$(name)_tvos.dylib -shared $(objects) -lpthread -ldl)
$(strip c++ -arch arm64 -marm -mtvos-version-min=11.0 -isysroot $(shell xcodebuild -version -sdk appletvos Path) -o out/$(name)_tvos.dylib -shared $(objects) -lpthread -ldl)
endif

View File

@ -285,6 +285,34 @@ static void flush_variables()
else
run_ahead_frames = atoi(variable.value);
}
variable = { "bsnes_touchscreen_lightgun", nullptr };
if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &variable) && variable.value)
{
if (strcmp(variable.value, "ON") == 0)
{
emulator->configure("Input/Pointer/Relative", false);
retro_pointer_enabled = true;
}
else
{
emulator->configure("Input/Pointer/Relative", true);
retro_pointer_enabled = false;
}
}
variable = { "bsnes_touchscreen_lightgun_superscope_reverse", nullptr };
if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &variable) && variable.value)
{
if (strcmp(variable.value, "ON") == 0)
{
retro_pointer_superscope_reverse_buttons = true;
}
else
{
retro_pointer_superscope_reverse_buttons = false;
}
}
// Refresh Geometry
struct retro_system_av_info avinfo;
@ -471,6 +499,8 @@ static void set_environment_info(retro_environment_t cb)
{ "bsnes_coprocessor_prefer_hle", "Coprocessor Prefer HLE; ON|OFF" },
{ "bsnes_sgb_bios", "Preferred Super GameBoy BIOS (restart); SGB1.sfc|SGB2.sfc" },
{ "bsnes_run_ahead_frames", "Amount of frames for run-ahead; OFF|1|2|3|4" },
{ "bsnes_touchscreen_lightgun", "Enable Touchscreen Lightgun; ON|OFF" },
{ "bsnes_touchscreen_lightgun_superscope_reverse", "Super Scope Reverse Trigger Buttons; OFF|ON" },
{ nullptr },
};
cb(RETRO_ENVIRONMENT_SET_VARIABLES, const_cast<retro_variable *>(vars));

View File

@ -18,8 +18,150 @@ using namespace nall;
#include "resources.hpp"
#include "libretro.h"
#define RETRO_DEVICE_LIGHTGUN_SUPER_SCOPE RETRO_DEVICE_SUBCLASS(RETRO_DEVICE_LIGHTGUN, 0)
static Emulator::Interface *emulator;
// Touchscreen Lightgun Support
static const int POINTER_PRESSED_CYCLES = 4; // For touchscreen sensitivity
struct retro_pointer_state
{
int x;
int y;
bool superscope_trigger_pressed;
bool superscope_cursor_pressed;
bool superscope_turbo_pressed;
bool superscope_start_pressed;
int pointer_pressed = 0;
int pointer_cycles_after_released = 0;
int pointer_pressed_last_x = 0;
int pointer_pressed_last_y = 0;
};
static retro_pointer_state retro_pointer = { 0, 0, false, false, false, false };
static bool retro_pointer_enabled = false;
static bool retro_pointer_superscope_reverse_buttons = false;
static void input_update_pointer_lightgun( unsigned port, unsigned gun_device)
{
int x, y;
x = input_state(port, RETRO_DEVICE_POINTER, 0, RETRO_DEVICE_ID_POINTER_X);
y = input_state(port, RETRO_DEVICE_POINTER, 0, RETRO_DEVICE_ID_POINTER_Y);
int screen_width = 256;
int screen_height = 224;
/*scale & clamp*/
x = ( ( x + 0x7FFF ) * screen_width ) / 0xFFFF;
if ( x < 0 )
x = 0;
else if ( x >= screen_width )
x = screen_width - 1;
/*scale & clamp*/
y = ( ( y + 0x7FFF ) * screen_height ) / 0xFFFF;
if ( y < 0 )
y = 0;
else if ( y >= screen_height )
y = screen_height - 1;
// Touch sensitivity: Keep the gun position held for a fixed number of cycles after touch is released
// because a very light touch can result in a misfire
if ( retro_pointer.pointer_cycles_after_released > 0 && retro_pointer.pointer_cycles_after_released < POINTER_PRESSED_CYCLES ) {
retro_pointer.pointer_cycles_after_released++;
retro_pointer.x = retro_pointer.pointer_pressed_last_x;
retro_pointer.y = retro_pointer.pointer_pressed_last_y;
return;
}
if ( input_state( port, RETRO_DEVICE_POINTER, 0, RETRO_DEVICE_ID_POINTER_PRESSED ) )
{
retro_pointer.pointer_pressed = 1;
retro_pointer.pointer_cycles_after_released = 0;
retro_pointer.pointer_pressed_last_x = x;
retro_pointer.pointer_pressed_last_y = y;
} else if ( retro_pointer.pointer_pressed ) {
retro_pointer.pointer_cycles_after_released++;
retro_pointer.pointer_pressed = 0;
x = retro_pointer.pointer_pressed_last_x;
y = retro_pointer.pointer_pressed_last_y;
// unpress the primary trigger
if (retro_pointer_superscope_reverse_buttons)
retro_pointer.superscope_cursor_pressed = false;
else
retro_pointer.superscope_trigger_pressed = false;
return;
}
retro_pointer.x = x;
retro_pointer.y = y;
// triggers
switch (gun_device)
{
case RETRO_DEVICE_LIGHTGUN_SUPER_SCOPE:
{
bool start_pressed = false;
bool trigger_pressed = false;
bool turbo_pressed = false;
bool cursor_pressed = false;
if ( input_state(port, RETRO_DEVICE_POINTER, 0, RETRO_DEVICE_ID_POINTER_PRESSED) ) {
int touch_count = input_state(port, RETRO_DEVICE_POINTER, 0, RETRO_DEVICE_ID_POINTER_COUNT);
if ( touch_count == 4 ) {
// start button
start_pressed = true;
} else if ( touch_count == 3 ) {
turbo_pressed = true;
} else if ( touch_count == 2 ) {
if ( retro_pointer_superscope_reverse_buttons )
{
trigger_pressed = true;
} else
{
cursor_pressed = true;
}
} else {
if ( retro_pointer_superscope_reverse_buttons )
{
cursor_pressed = true;
} else
{
trigger_pressed = true;
}
}
}
retro_pointer.superscope_trigger_pressed = trigger_pressed;
retro_pointer.superscope_cursor_pressed = cursor_pressed;
retro_pointer.superscope_start_pressed = start_pressed;
retro_pointer.superscope_turbo_pressed = turbo_pressed;
break;
}
default:
break;
}
}
static int input_handle_touchscreen_lightgun( unsigned port, unsigned gun_device, unsigned inputId)
{
input_update_pointer_lightgun(port, gun_device);
switch (inputId)
{
case 0: // X
return retro_pointer.x;
case 1: // Y
return retro_pointer.y;
case 2: // Trigger
return retro_pointer.superscope_trigger_pressed ? 1 : 0;
case 3: // Cursor
return retro_pointer.superscope_cursor_pressed ? 1 : 0;
case 4: // Turbo
return retro_pointer.superscope_turbo_pressed ? 1 : 0;
case 5: // Pause
return retro_pointer.superscope_start_pressed ? 1 : 0;
default:
return 0; // Unknown input
}
}
struct Program : Emulator::Platform
{
Program();
@ -312,6 +454,16 @@ auto pollInputDevices(uint port, uint device, uint input) -> int16
// TODO: SuperScope/Justifiers.
// Do we care? The v94 port hasn't hooked them up. :)
case SuperFamicom::ID::Device::SuperScope:
{
libretro_device = RETRO_DEVICE_LIGHTGUN_SUPER_SCOPE;
if (retro_pointer_enabled)
{
return input_handle_touchscreen_lightgun(libretro_port, libretro_device, input);
} else {
return 0;
}
}
default:
return 0;