libretro additions and fixes

This commit is contained in:
hunterk 2025-06-23 21:18:57 -05:00
parent 6ce835b3e6
commit 2e2ffad3ef
8 changed files with 6294 additions and 2157 deletions

View File

@ -17,6 +17,10 @@
#include "Logger.hxx"
#ifdef __LIB_RETRO__
extern void libretro_logger(int log_level, const char *string);
#endif
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Logger& Logger::instance()
{
@ -52,6 +56,10 @@ void Logger::debug(string_view message)
void Logger::logMessage(string_view message, Level level)
{
const std::lock_guard<std::mutex> lock(mutex);
#ifdef __LIB_RETRO__
libretro_logger(static_cast<int>(level), string{message}.c_str());
#endif
if(level == Logger::Level::ERR)
{

View File

@ -99,3 +99,9 @@ size_t FSNodeLIBRETRO::read(ByteBuffer& image, size_t) const
extern uInt32 libretro_read_rom(void* data);
return libretro_read_rom(image.get());
}
size_t FSNodeLIBRETRO::read(stringstream& buffer) const
{
extern uInt32 libretro_get_rom_size(void);
return libretro_get_rom_size();
}

View File

@ -50,6 +50,7 @@ class FSNodeLIBRETRO : public AbstractFSNode
AbstractFSNodePtr getParent() const override;
size_t read(ByteBuffer& image, size_t) const override;
size_t read(stringstream& buffer) const override;
protected:
string _name;

View File

@ -1,4 +1,5 @@
DEBUG = 0
DEBUG := 0
SILENT := 0
HAVE_EXCEPTIONS = 1
HAVE_STRINGS_H = 1
@ -540,7 +541,7 @@ else ifeq ($(platform), windows_msvc2005_x86)
else
TARGET := $(TARGET_NAME)_libretro.dll
CXX ?= g++
SHARED := -shared -static-libgcc -static-libstdc++ -s -Wl,--version-script=link.T
SHARED := -shared -static-libgcc -static-libstdc++ -Wl,--version-script=link.T
CXXFLAGS += -D__WIN32__
endif
@ -548,7 +549,7 @@ CORE_DIR := ../..
ifeq ($(DEBUG), 1)
ifneq (,$(findstring msvc,$(platform)))
CXXFLAGS += -Od -Zi -DDEBUG -D_DEBUG
CXXFLAGS += -Od -Zi -D_DEBUG
ifeq ($(STATIC_LINKING),1)
CXXFLAGS += -MTd
@ -556,7 +557,7 @@ ifeq ($(DEBUG), 1)
CXXFLAGS += -MDd
endif
else
CXXFLAGS += -O0 -g -DDEBUG
CXXFLAGS += -O0 -g
endif
else
ifneq (,$(findstring msvc,$(platform)))
@ -572,6 +573,8 @@ else
CXXFLAGS += -MD
endif
endif
SHARED += -s
endif
include Makefile.common
@ -590,7 +593,7 @@ else
endif
CXXFLAGS += $(CODE_DEFINES) $(WARNINGS_DEFINES) $(fpic)
CXXFLAGS += -D__LIB_RETRO__ -DSOUND_SUPPORT
CXXFLAGS += -D__LIB_RETRO__ -DSOUND_SUPPORT -MMD
CXXFLAGS += -DHAVE_STDINT_H
ifeq (,$(findstring msvc,$(platform)))
@ -627,8 +630,16 @@ ifeq ($(platform), theos_ios)
${LIBRARY_NAME}_FILES = $(SOURCES_CXX) $(SOURCES_C)
include $(THEOS_MAKE_PATH)/library.mk
else
default: info all
info:
$(info CXXFLAGS: $(CXXFLAGS))
$(info -------)
all: $(TARGET)
-include $(OBJECTS:.o=.d))
$(TARGET): $(OBJECTS)
ifeq ($(STATIC_LINKING), 1)
$(AR) rcs $@ $(OBJECTS)
@ -637,11 +648,16 @@ else
endif
%.o: %.cxx
@if [ $(SILENT) -ne 1 ]; then\
$(if $@, $(shell echo echo CXX $<),);\
fi
$(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) -c $(OBJOUT)$@ $<
%.o: %.c
%.o: %.c @if [ $(SILENT) -ne 1 ]; then\
$(if $@, $(shell echo echo CC $<),);\
fi
$(CC) $(INCFLAGS) -c $(OBJOUT)$@ $<
clean:
rm -f $(OBJECTS) $(TARGET)
rm -f $(OBJECTS) $(OBJECTS:.o=.d) $(TARGET)
endif

View File

@ -51,9 +51,7 @@ class SoundLIBRETRO : public Sound
SoundLIBRETRO(OSystem& osystem, AudioSettings& audioSettings)
: Sound(osystem),
myAudioSettings{audioSettings}
{
Logger::debug("SoundLIBRETRO::SoundLIBRETRO started ...");
Logger::debug("SoundLIBRETRO::SoundLIBRETRO initialized");
{
}
~SoundLIBRETRO() override = default;
@ -65,16 +63,12 @@ class SoundLIBRETRO : public Sound
void open(shared_ptr<AudioQueue> audioQueue,
shared_ptr<const EmulationTiming>) override
{
Logger::debug("SoundLIBRETRO::open started ...");
audioQueue->ignoreOverflows(!myAudioSettings.enabled());
myAudioQueue = audioQueue;
myUnderrun = true;
myCurrentFragment = nullptr;
Logger::debug("SoundLIBRETRO::open finished");
myIsInitializedFlag = true;
}
@ -87,8 +81,9 @@ class SoundLIBRETRO : public Sound
void dequeue(Int16* stream, uInt32* samples)
{
uInt32 outIndex = 0;
uInt32 frame = myAudioSettings.sampleRate() / myOSystem.console().gameRefreshRate();
while (myAudioQueue->size())
while (myAudioQueue->size() && outIndex <= frame)
{
Int16* nextFragment = myAudioQueue->dequeue(myCurrentFragment);

View File

@ -232,36 +232,14 @@ float StellaLIBRETRO::getVideoAspectPar() const
if (getVideoNTSC())
{
if (!video_aspect_ntsc)
{
if (video_filter != NTSCFilter::Preset::OFF)
{
// non-interlace square pixel clock -- 1.0 pixel @ color burst -- double-width pixels
par = (6.1363635F / 3.579545454F) / 2.0;
}
else
{
// blargg filter
par = 1.0;
}
}
par = (6.1363635f / 3.579545454f) / 2.0;
else
par = video_aspect_ntsc / 100.0;
}
else
{
if (!video_aspect_pal)
{
if (video_filter != NTSCFilter::Preset::OFF)
{
// non-interlace square pixel clock -- 0.8 pixel @ color burst -- double-width pixels
par = (7.3750000F / (4.43361875F * 4.F / 5.F)) / 2.F;
}
else
{
// blargg filter
par = 1.0;
}
}
par = (7.3750000f / (4.43361875f * 4.0f / 5.0f)) / 2.0f;
else
par = video_aspect_pal / 100.0;
}
@ -357,6 +335,8 @@ void StellaLIBRETRO::setVideoFilter(NTSCFilter::Preset mode)
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void StellaLIBRETRO::setVideoPalette(const string& mode)
{
video_palette = mode;
if (system_ready)
{
myOSystem->settings().setValue("palette", video_palette);

View File

@ -6,6 +6,7 @@
#include <cstddef>
#include <cstdio>
#include <cstdlib>
#include <stdarg.h>
#ifdef _MSC_VER
#define snprintf _snprintf
@ -37,7 +38,12 @@ static int setting_stereo;
static int setting_phosphor, setting_console, setting_phosphor_blend;
static int stella_paddle_joypad_sensitivity;
static int stella_paddle_analog_sensitivity;
static int stella_paddle_mouse_sensitivity;
static int stella_paddle_analog_deadzone;
static bool stella_paddle_analog_absolute;
static bool stella_lightgun_crosshair;
static int setting_crop_hoverscan, crop_left;
static int setting_crop_voverscan, crop_top;
static NTSCFilter::Preset setting_filter;
static const char* setting_palette;
static int setting_reload;
@ -45,8 +51,29 @@ static int setting_reload;
static bool system_reset;
static unsigned input_devices[4];
static int32_t input_crosshair[2];
static Controller::Type input_type[2];
void libretro_logger(int log_level, const char *source)
{
retro_log_level log_mode = RETRO_LOG_INFO;
char *string = strdup(source);
char *token = strtok(string, "\n");
switch (log_level)
{
case 2: log_mode = RETRO_LOG_DEBUG; break;
case 0: log_mode = RETRO_LOG_ERROR; break;
}
while (token != NULL)
{
log_cb(log_mode, "%s\n", token);
token = strtok(NULL, "\n");
}
free(string);
string = NULL;
}
// TODO input:
// https://github.com/libretro/blueMSX-libretro/blob/master/libretro.c
@ -60,6 +87,91 @@ uint32_t libretro_read_rom(void* data)
return stella.getROMSize();
}
uint32_t libretro_get_rom_size(void)
{
return stella.getROMSize();
}
#define RETRO_ANALOG_COMMON() \
bool mouse_l = input_state_cb(pad, RETRO_DEVICE_MOUSE, 0, RETRO_DEVICE_ID_MOUSE_LEFT); \
bool mouse_r = input_state_cb(pad, RETRO_DEVICE_MOUSE, 0, RETRO_DEVICE_ID_MOUSE_RIGHT); \
int32_t mouse_x = input_state_cb(pad, RETRO_DEVICE_MOUSE, 0, RETRO_DEVICE_ID_MOUSE_X); \
int32_t analog_x = input_state_cb(pad, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_LEFT, RETRO_DEVICE_ID_ANALOG_X); \
*input_bitmask |= mouse_l << RETRO_DEVICE_ID_JOYPAD_B; \
if (stella_paddle_analog_deadzone && abs(analog_x) < stella_paddle_analog_deadzone * 0x7fff / 100) \
analog_x = 0; \
if (mouse_r) \
mouse_x *= 3; \
static void retro_analog_paddle(unsigned pad, int32_t *analog_axis, int32_t *input_bitmask)
{
RETRO_ANALOG_COMMON();
if (mouse_x)
*analog_axis += mouse_x * stella_paddle_mouse_sensitivity;
else if (!stella_paddle_analog_absolute)
*analog_axis += analog_x / 50;
else
*analog_axis = analog_x;
*analog_axis = BSPF::clamp(*analog_axis, -0x7fff, 0x7fff);
}
static void retro_analog_wheel(unsigned pad, int32_t *analog_axis, int32_t *input_bitmask)
{
RETRO_ANALOG_COMMON();
if (mouse_x)
*analog_axis = mouse_x * stella_paddle_mouse_sensitivity * 50;
else
*analog_axis = analog_x;
*analog_axis = BSPF::clamp(*analog_axis, -0x7fff, 0x7fff);
}
static void draw_crosshair(int16_t x, int16_t y, uint16_t color)
{
int i;
int size = 3;
int width = stella.getVideoWidthMax();
int viewport_w = stella.getVideoWidth();
int viewport_h = stella.getVideoHeight();
uint8_t zoom = stella.getVideoZoom();
/* crosshair center position */
uint32_t *ptr = (uint32_t *)stella.getVideoBuffer() + (y * width) + x;
/* default crosshair dimension */
int x_start = x - size * zoom;
int x_end = x + size * zoom;
int y_start = y - size;
int y_end = y + size;
if (zoom > 1)
x_end++;
/* off-screen */
if (x <= 0 || y <= 0)
return;
/* framebuffer limits */
if (x_start < 0) x_start = 0;
if (x_end > viewport_w) x_end = viewport_w;
if (y_start < 0) y_start = 0;
if (y_end > viewport_h) y_end = viewport_h;
/* draw crosshair */
for (i = (x_start - x); i <= (x_end - x); i++)
{
ptr[i] = (i & zoom) ? color : 0xffffff;
}
for (i = (y_start - y); i <= (y_end - y); i++)
{
ptr[i * width] = (i & 1) ? color : 0xffffff;
if (zoom > 1)
ptr[(i * width) + 1] = (i & 1) ? color : 0xffffff;
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
static void update_input()
{
@ -68,7 +180,8 @@ static void update_input()
#define EVENT stella.setInputEvent
int32_t input_bitmask[4];
#define GET_BITMASK(pad) if (libretro_supports_bitmasks) \
#define GET_BITMASK(pad) \
if (libretro_supports_bitmasks) \
input_bitmask[(pad)] = input_state_cb((pad), RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_MASK); \
else \
{ \
@ -78,37 +191,54 @@ static void update_input()
}
#define MASK_EVENT(evt, pad, id) stella.setInputEvent((evt), (input_bitmask[(pad)] & (1 << (id))) ? 1 : 0)
input_crosshair[0] = input_crosshair[1] = 0;
int pad = 0;
GET_BITMASK(pad)
switch(input_type[0])
{
using enum Controller::Type;
case Driving:
MASK_EVENT(Event::LeftDrivingCCW, pad, RETRO_DEVICE_ID_JOYPAD_LEFT);
MASK_EVENT(Event::LeftDrivingCW, pad, RETRO_DEVICE_ID_JOYPAD_RIGHT);
{
int32_t wheel = 0;
retro_analog_wheel(pad, &wheel, &input_bitmask[pad]);
EVENT(Event::LeftDrivingAnalog, wheel);
MASK_EVENT(Event::LeftDrivingCCW, pad, RETRO_DEVICE_ID_JOYPAD_LEFT);
MASK_EVENT(Event::LeftDrivingCW, pad, RETRO_DEVICE_ID_JOYPAD_RIGHT);
MASK_EVENT(Event::LeftDrivingFire, pad, RETRO_DEVICE_ID_JOYPAD_B);
break;
}
case Paddles:
{
static int32_t paddle_a = 0;
static int32_t paddle_b = 0;
retro_analog_paddle(pad, &paddle_a, &input_bitmask[pad]);
EVENT(Event::LeftPaddleAAnalog, paddle_a);
MASK_EVENT(Event::LeftPaddleAIncrease, pad, RETRO_DEVICE_ID_JOYPAD_LEFT);
MASK_EVENT(Event::LeftPaddleADecrease, pad, RETRO_DEVICE_ID_JOYPAD_RIGHT);
MASK_EVENT(Event::LeftPaddleAFire, pad, RETRO_DEVICE_ID_JOYPAD_B);
EVENT(Event::LeftPaddleAAnalog, input_state_cb(pad, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_LEFT, RETRO_DEVICE_ID_ANALOG_X));
pad++;
MASK_EVENT(Event::LeftPaddleAFire, pad, RETRO_DEVICE_ID_JOYPAD_B);
GET_BITMASK(pad)
retro_analog_paddle(pad, &paddle_b, &input_bitmask[pad]);
EVENT(Event::LeftPaddleBAnalog, paddle_b);
MASK_EVENT(Event::LeftPaddleBIncrease, pad, RETRO_DEVICE_ID_JOYPAD_LEFT);
MASK_EVENT(Event::LeftPaddleBDecrease, pad, RETRO_DEVICE_ID_JOYPAD_RIGHT);
MASK_EVENT(Event::LeftPaddleBFire, pad, RETRO_DEVICE_ID_JOYPAD_B);
EVENT(Event::LeftPaddleBAnalog, input_state_cb(pad, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_RIGHT, RETRO_DEVICE_ID_ANALOG_X));
MASK_EVENT(Event::LeftPaddleBFire, pad, RETRO_DEVICE_ID_JOYPAD_B);
break;
}
case Lightgun:
{
// scale from -0x8000..0x7fff to image rect
const Common::Rect& rect = stella.getImageRect();
const Int32 x = (input_state_cb(pad, RETRO_DEVICE_LIGHTGUN, 0, RETRO_DEVICE_ID_LIGHTGUN_SCREEN_X) + 0x8000) * rect.w() / 0x10000;
const Int32 y = (input_state_cb(pad, RETRO_DEVICE_LIGHTGUN, 0, RETRO_DEVICE_ID_LIGHTGUN_SCREEN_Y) + 0x8000) * rect.h() / 0x10000;
const Common::Rect& rect = stella.getImageRect();
const int32_t x = (input_state_cb(pad, RETRO_DEVICE_LIGHTGUN, 0, RETRO_DEVICE_ID_LIGHTGUN_SCREEN_X) + 0x7fff) * rect.w() / 0xffff;
const int32_t y = (input_state_cb(pad, RETRO_DEVICE_LIGHTGUN, 0, RETRO_DEVICE_ID_LIGHTGUN_SCREEN_Y) + 0x7fff) * rect.h() / 0xffff;
input_crosshair[0] = x > 0 && x < 0x7fff ? x * stella.getVideoWidth() / rect.w() : 0;
input_crosshair[1] = y > 0 && y < 0x7fff ? y * stella.getVideoHeight() / rect.h() : 0;
EVENT(Event::MouseAxisXValue, x);
EVENT(Event::MouseAxisYValue, y);
@ -117,6 +247,46 @@ static void update_input()
break;
}
case Controller::Type::AmigaMouse:
case Controller::Type::AtariMouse:
case Controller::Type::TrakBall:
{
bool mouse_l = input_state_cb(pad, RETRO_DEVICE_MOUSE, 0, RETRO_DEVICE_ID_MOUSE_LEFT);
bool mouse_r = input_state_cb(pad, RETRO_DEVICE_MOUSE, 0, RETRO_DEVICE_ID_MOUSE_RIGHT);
int32_t mouse_x = input_state_cb(pad, RETRO_DEVICE_MOUSE, 0, RETRO_DEVICE_ID_MOUSE_X);
int32_t mouse_y = input_state_cb(pad, RETRO_DEVICE_MOUSE, 0, RETRO_DEVICE_ID_MOUSE_Y);
int32_t analog_x = input_state_cb(pad, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_LEFT, RETRO_DEVICE_ID_ANALOG_X);
int32_t analog_y = input_state_cb(pad, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_LEFT, RETRO_DEVICE_ID_ANALOG_Y);
float analog_mag = sqrt((analog_x * analog_x) + (analog_y * analog_y));
if (stella_paddle_analog_deadzone && analog_mag <= stella_paddle_analog_deadzone * 0x7fff / 100)
analog_x = analog_y = 0;
mouse_x += analog_x / (80000 / stella_paddle_analog_sensitivity);
mouse_y += analog_y / (80000 / stella_paddle_analog_sensitivity);
if (input_bitmask[pad] & (1 << RETRO_DEVICE_ID_JOYPAD_LEFT))
mouse_x -= stella_paddle_joypad_sensitivity;
else if (input_bitmask[pad] & (1 << RETRO_DEVICE_ID_JOYPAD_RIGHT))
mouse_x += stella_paddle_joypad_sensitivity;
if (input_bitmask[pad] & (1 << RETRO_DEVICE_ID_JOYPAD_UP))
mouse_y -= stella_paddle_joypad_sensitivity;
else if (input_bitmask[pad] & (1 << RETRO_DEVICE_ID_JOYPAD_DOWN))
mouse_y += stella_paddle_joypad_sensitivity;
if (input_bitmask[pad] & (1 << RETRO_DEVICE_ID_JOYPAD_B))
mouse_l = true;
if (input_bitmask[pad] & (1 << RETRO_DEVICE_ID_JOYPAD_A))
mouse_r = true;
EVENT(Event::MouseAxisXMove, mouse_x);
EVENT(Event::MouseAxisYMove, mouse_y);
EVENT(Event::MouseButtonLeftValue, mouse_l);
EVENT(Event::MouseButtonRightValue, mouse_r);
break;
}
case Joy2BPlus:
case BoosterGrip:
MASK_EVENT(Event::LeftJoystickFire9, pad, RETRO_DEVICE_ID_JOYPAD_Y);
@ -140,24 +310,38 @@ static void update_input()
{
using enum Controller::Type;
case Driving:
MASK_EVENT(Event::RightDrivingCCW, pad, RETRO_DEVICE_ID_JOYPAD_LEFT);
MASK_EVENT(Event::RightDrivingCW, pad, RETRO_DEVICE_ID_JOYPAD_RIGHT);
{
int32_t wheel = 0;
retro_analog_wheel(pad, &wheel, &input_bitmask[pad]);
EVENT(Event::RightDrivingAnalog, wheel);
MASK_EVENT(Event::RightDrivingCCW, pad, RETRO_DEVICE_ID_JOYPAD_LEFT);
MASK_EVENT(Event::RightDrivingCW, pad, RETRO_DEVICE_ID_JOYPAD_RIGHT);
MASK_EVENT(Event::RightDrivingFire, pad, RETRO_DEVICE_ID_JOYPAD_B);
break;
}
case Paddles:
{
static int32_t paddle_a = 0;
static int32_t paddle_b = 0;
retro_analog_paddle(pad, &paddle_a, &input_bitmask[pad]);
EVENT(Event::RightPaddleAAnalog, paddle_a);
MASK_EVENT(Event::RightPaddleAIncrease, pad, RETRO_DEVICE_ID_JOYPAD_LEFT);
MASK_EVENT(Event::RightPaddleADecrease, pad, RETRO_DEVICE_ID_JOYPAD_RIGHT);
MASK_EVENT(Event::RightPaddleAFire, pad, RETRO_DEVICE_ID_JOYPAD_B);
EVENT(Event::RightPaddleAAnalog, input_state_cb(pad, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_LEFT, RETRO_DEVICE_ID_ANALOG_X));
pad++;
GET_BITMASK(pad)
retro_analog_paddle(pad, &paddle_b, &input_bitmask[pad]);
EVENT(Event::RightPaddleBAnalog, paddle_b);
MASK_EVENT(Event::RightPaddleBIncrease, pad, RETRO_DEVICE_ID_JOYPAD_LEFT);
MASK_EVENT(Event::RightPaddleBDecrease, pad, RETRO_DEVICE_ID_JOYPAD_RIGHT);
MASK_EVENT(Event::RightPaddleBFire, pad, RETRO_DEVICE_ID_JOYPAD_B);
EVENT(Event::RightPaddleBAnalog, input_state_cb(pad, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_RIGHT, RETRO_DEVICE_ID_ANALOG_X));
break;
}
case Joy2BPlus:
case BoosterGrip:
@ -252,6 +436,13 @@ static void update_variables(bool init = false)
geometry_update = true;
}
RETRO_GET("stella_crop_voverscan")
{
setting_crop_voverscan = atoi(var.value);
geometry_update = true;
}
RETRO_GET("stella_ntsc_aspect")
{
@ -400,9 +591,36 @@ static void update_variables(bool init = false)
setting_reload = value;
}
RETRO_GET("stella_paddle_mouse_sensitivity")
{
stella_paddle_mouse_sensitivity = atoi(var.value);
}
RETRO_GET("stella_paddle_analog_deadzone")
{
stella_paddle_analog_deadzone = atoi(var.value);
}
RETRO_GET("stella_paddle_analog_absolute")
{
stella_paddle_analog_absolute = false;
if(!strcmp(var.value, "enabled"))
stella_paddle_analog_absolute = true;
}
RETRO_GET("stella_lightgun_crosshair")
{
stella_lightgun_crosshair = false;
if(!strcmp(var.value, "enabled"))
stella_lightgun_crosshair = true;
}
if(!init && !system_reset)
{
crop_left = setting_crop_hoverscan ? (stella.getVideoZoom() == 2 ? 26 : 8) : 0;
crop_left = setting_crop_hoverscan ? (stella.getVideoZoom() == 2 ? 32 : 8) : 0;
crop_top = setting_crop_voverscan;
if(geometry_update) update_geometry();
}
@ -460,6 +678,7 @@ void retro_get_system_info(struct retro_system_info *info)
{
*info = retro_system_info{}; // reset to defaults
info->library_name = stella.getCoreName();
#ifndef GIT_VERSION
#define GIT_VERSION ""
@ -474,19 +693,19 @@ void retro_get_system_info(struct retro_system_info *info)
void retro_get_system_av_info(struct retro_system_av_info *info)
{
*info = retro_system_av_info{}; // reset to defaults
unsigned crop_width = crop_left ? 8 : 0;
info->timing.fps = stella.getVideoRate();
info->timing.sample_rate = stella.getAudioRate();
info->geometry.base_width = stella.getRenderWidth() - crop_left *
(stella.getVideoZoom() == 1 ? 2 : 1);
info->geometry.base_width = stella.getRenderWidth();
info->geometry.base_height = stella.getRenderHeight();
info->geometry.max_width = stella.getVideoWidthMax();
info->geometry.max_height = stella.getVideoHeightMax();
info->geometry.aspect_ratio = stella.getVideoAspectPar() *
(float) info->geometry.base_width / (float) info->geometry.base_height;
(float)(160 - crop_width) * 2 / (float)(stella.getVideoHeight() - (crop_top * 2));
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -494,20 +713,16 @@ void retro_set_controller_port_device(unsigned port, unsigned device)
{
if(port < 4)
{
switch (device)
switch(device)
{
case RETRO_DEVICE_NONE:
case RETRO_DEVICE_JOYPAD:
case RETRO_DEVICE_ANALOG:
case RETRO_DEVICE_LIGHTGUN:
//case RETRO_DEVICE_KEYBOARD:
//case RETRO_DEVICE_MOUSE:
input_devices[port] = device;
break;
default:
if (log_cb) log_cb(RETRO_LOG_ERROR, "%s\n", "[libretro]: Invalid device, setting type to RETRO_DEVICE_JOYPAD ...");
input_devices[port] = RETRO_DEVICE_JOYPAD;
break;
}
}
}
@ -522,15 +737,20 @@ void retro_set_environment(retro_environment_t cb)
{ "stella_console", "Console display; auto|ntsc|pal|secam|ntsc50|pal60|secam60" },
{ "stella_palette", "Palette colors; standard|z26|user|custom" },
{ "stella_filter", "TV effects; disabled|composite|s-video|rgb|badly adjusted" },
{ "stella_ntsc_aspect", "NTSC aspect %; par|100|101|102|103|104|105|106|107|108|109|110|111|112|113|114|115|116|117|118|119|120|121|122|123|124|125|50|75|76|77|78|79|80|81|82|83|84|85|86|87|88|89|90|91|92|93|94|95|96|97|98|99" },
{ "stella_pal_aspect", "PAL aspect %; par|100|101|102|103|104|105|106|107|108|109|110|111|112|113|114|115|116|117|118|119|120|121|122|123|124|125|50|75|76|77|78|79|80|81|82|83|84|85|86|87|88|89|90|91|92|93|94|95|96|97|98|99" },
{ "stella_crop_hoverscan", "Crop horizontal overscan; disabled|enabled" },
{ "stella_crop_voverscan", "Crop vertical overscan; 0|1|2|3|4|5|6|7|8|9|10|11|12|13|14|15|16|17|18|19|20|21|22|23|24" },
{ "stella_ntsc_aspect", "NTSC aspect %; par|100|101|102|103|104|105|106|107|108|109|110|111|112|113|114|115|116|117|118|119|120|121|122|123|124|125|75|76|77|78|79|80|81|82|83|84|85|86|87|88|89|90|91|92|93|94|95|96|97|98|99" },
{ "stella_pal_aspect", "PAL aspect %; par|100|101|102|103|104|105|106|107|108|109|110|111|112|113|114|115|116|117|118|119|120|121|122|123|124|125|75|76|77|78|79|80|81|82|83|84|85|86|87|88|89|90|91|92|93|94|95|96|97|98|99" },
{ "stella_stereo", "Stereo sound; auto|off|on" },
{ "stella_phosphor", "Phosphor mode; auto|off|on" },
{ "stella_phosphor_blend", "Phosphor blend %; 60|65|70|75|80|85|90|95|100|0|5|10|15|20|25|30|35|40|45|50|55" },
{ "stella_paddle_mouse_sensitivity", "Paddle mouse sensitivity; 10|11|12|13|14|15|16|17|18|19|20|21|22|23|24|25|26|27|28|29|30|1|2|3|4|5|6|7|8|9" },
{ "stella_paddle_joypad_sensitivity", "Paddle joypad sensitivity; 3|4|5|6|7|8|9|10|11|12|13|14|15|16|17|18|19|20|1|2" },
{ "stella_paddle_analog_sensitivity", "Paddle analog sensitivity; 20|21|22|23|24|25|26|27|28|29|30|0|1|2|3|4|5|6|7|8|9|10|11|12|13|14|15|16|17|18|19" },
{ "stella_reload", "Enable reload/next game; off|on" },
{ "stella_paddle_analog_deadzone", "Paddle analog deadzone; 15|16|17|18|19|20|21|22|23|24|25|26|27|28|29|30|0|1|2|3|4|5|6|7|8|9|10|11|12|13|14" },
{ "stella_paddle_analog_absolute", "Paddle analog absolute; disabled|enabled" },
{ "stella_lightgun_crosshair", "Lightgun crosshair; disabled|enabled" },
{ NULL, NULL },
};
@ -538,119 +758,92 @@ void retro_set_environment(retro_environment_t cb)
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
static void fallback_log(enum retro_log_level level, const char *fmt, ...)
{
(void)level;
va_list va;
va_start(va, fmt);
vfprintf(stderr, fmt, va);
va_end(va);
}
void retro_init()
{
struct retro_log_callback log;
unsigned level = 4;
log_cb = NULL;
if(environ_cb(RETRO_ENVIRONMENT_GET_LOG_INTERFACE, &log)) log_cb = log.log;
log_cb = fallback_log;
if(environ_cb(RETRO_ENVIRONMENT_GET_LOG_INTERFACE, &log))
log_cb = log.log;
environ_cb(RETRO_ENVIRONMENT_SET_PERFORMANCE_LEVEL, &level);
libretro_supports_bitmasks = environ_cb(RETRO_ENVIRONMENT_GET_INPUT_BITMASKS, NULL);
}
static const struct retro_controller_description controllers[] = {
{ "Automatic", RETRO_DEVICE_JOYPAD },
{ "None", RETRO_DEVICE_NONE },
{ NULL, 0 }
};
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool retro_load_game(const struct retro_game_info *info)
{
enum retro_pixel_format fmt = RETRO_PIXEL_FORMAT_XRGB8888;
// Tell libretro we allow those 4 different types of devices for player 0
static const struct retro_controller_description player0_controller_description[] = {
{ "None", RETRO_DEVICE_NONE },
{ "Joystick", RETRO_DEVICE_JOYPAD },
{ "Analog", RETRO_DEVICE_ANALOG },
{ "Lightgun", RETRO_DEVICE_LIGHTGUN }
};
// Tell libretro we allow those 3 different types of devices for other players
static const struct retro_controller_description other_player_controller_description[] = {
{ "None", RETRO_DEVICE_NONE },
{ "Joystick", RETRO_DEVICE_JOYPAD },
{ "Analog", RETRO_DEVICE_ANALOG }
};
// Tell libretro we allow those types for 4 players
static const struct retro_controller_info controller_infos[5] = {
{ player0_controller_description, 4 },
{ other_player_controller_description, 3 },
{ other_player_controller_description, 3 },
{ other_player_controller_description, 3 },
static const struct retro_controller_info controller_info[] = {
{ controllers, sizeof(controllers) / sizeof(controllers[0]) },
{ controllers, sizeof(controllers) / sizeof(controllers[0]) },
{ controllers, sizeof(controllers) / sizeof(controllers[0]) },
{ controllers, sizeof(controllers) / sizeof(controllers[0]) },
{ NULL, 0 }
};
static const struct retro_input_descriptor desc[] = {
{ 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_UP, "Up" },
{ 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_DOWN, "Down" },
{ 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_LEFT, "Left" },
{ 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_RIGHT, "Right" },
{ 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_A, "Trigger" },
{ 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_B, "Fire" },
{ 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_X, "Reload/Next game" },
{ 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_Y, "Booster" },
#define RETRO_DESCRIPTOR_BLOCK(_user) \
{ _user, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_UP, "Up" }, \
{ _user, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_DOWN, "Down" }, \
{ _user, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_LEFT, "Left" }, \
{ _user, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_RIGHT, "Right" }, \
{ _user, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_B, "Fire" }, \
{ _user, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_A, "Trigger" }, \
{ _user, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_Y, "Booster" }, \
{ _user, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_SELECT, "Select" }, \
{ _user, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_START, "Reset" }, \
{ _user, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_L, "Left Difficulty A" }, \
{ _user, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R, "Right Difficulty A" }, \
{ _user, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_L2, "Left Difficulty B" }, \
{ _user, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R2, "Right Difficulty B" }, \
{ _user, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_L3, "Color" }, \
{ _user, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R3, "Black/White" }, \
{ _user, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_LEFT, RETRO_DEVICE_ID_ANALOG_X, "Axis" } \
{ 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_SELECT, "Select" },
{ 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_START, "Reset" },
{ 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_L, "Left Difficulty A" },
{ 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R, "Right Difficulty A" },
{ 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_L2, "Left Difficulty B" },
{ 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R2, "Right Difficulty B" },
{ 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_L3, "Color" },
{ 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R3, "Black/White" },
#define RETRO_DESCRIPTOR_EXTRA_BLOCK(_user) \
{ _user, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_LEFT, "Left" }, \
{ _user, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_RIGHT, "Right" }, \
{ _user, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_B, "Fire" }, \
{ _user, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_LEFT, RETRO_DEVICE_ID_ANALOG_X, "Axis" } \
{ 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_UP, "Up" },
{ 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_DOWN, "Down" },
{ 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_LEFT, "Left" },
{ 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_RIGHT, "Right" },
{ 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_A, "Trigger" },
{ 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_B, "Fire" },
{ 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_X, "Reload/Next game" },
{ 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_Y, "Booster" },
{ 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_SELECT, "Select" },
{ 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_START, "Reset" },
{ 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_L, "Left Difficulty A" },
{ 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R, "Right Difficulty A" },
{ 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_L2, "Left Difficulty B" },
{ 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R2, "Right Difficulty B" },
{ 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_L3, "Color" },
{ 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R3, "Black/White" },
{ 2, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_LEFT, "Left" },
{ 2, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_RIGHT, "Right" },
{ 2, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_B, "Fire" },
{ 3, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_LEFT, "Left" },
{ 3, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_RIGHT, "Right" },
{ 3, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_B, "Fire" },
{ 0, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_LEFT, RETRO_DEVICE_ID_ANALOG_X, "Axis" },
{ 0, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_BUTTON, RETRO_DEVICE_ID_JOYPAD_B, "Button" },
{ 1, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_LEFT, RETRO_DEVICE_ID_ANALOG_X, "Axis" },
{ 1, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_BUTTON, RETRO_DEVICE_ID_JOYPAD_B, "Button" },
{ 2, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_LEFT, RETRO_DEVICE_ID_ANALOG_X, "Axis" },
{ 2, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_BUTTON, RETRO_DEVICE_ID_JOYPAD_B, "Button" },
{ 3, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_LEFT, RETRO_DEVICE_ID_ANALOG_X, "Axis" },
{ 3, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_BUTTON, RETRO_DEVICE_ID_JOYPAD_B, "Button" },
{ 0, RETRO_DEVICE_LIGHTGUN, 0, RETRO_DEVICE_ID_LIGHTGUN_SCREEN_X, "Screen X" },
{ 0, RETRO_DEVICE_LIGHTGUN, 0, RETRO_DEVICE_ID_LIGHTGUN_SCREEN_Y, "Screen Y" },
{ 0, RETRO_DEVICE_LIGHTGUN, 0, RETRO_DEVICE_ID_LIGHTGUN_TRIGGER, "Button" },
{ 0, 0, 0, 0, NULL },
static struct retro_input_descriptor input_descriptors[] =
{
RETRO_DESCRIPTOR_BLOCK(0),
RETRO_DESCRIPTOR_BLOCK(1),
RETRO_DESCRIPTOR_EXTRA_BLOCK(2),
RETRO_DESCRIPTOR_EXTRA_BLOCK(3),
{0, 0, 0, 0, NULL},
};
#undef RETRO_DESCRIPTOR_BLOCK
#undef RETRO_DESCRIPTOR_EXTRA_BLOCK
if(!info || info->size > stella.getROMMax()) return false;
// Send controller infos to libretro
environ_cb(RETRO_ENVIRONMENT_SET_CONTROLLER_INFO, (void*)controller_infos);
environ_cb(RETRO_ENVIRONMENT_SET_CONTROLLER_INFO, (void*)controller_info);
// Send controller input descriptions to libretro
environ_cb(RETRO_ENVIRONMENT_SET_INPUT_DESCRIPTORS, (void*)desc);
environ_cb(RETRO_ENVIRONMENT_SET_INPUT_DESCRIPTORS, (void*)input_descriptors);
if(!environ_cb(RETRO_ENVIRONMENT_SET_PIXEL_FORMAT, &fmt))
{
if(log_cb) log_cb(RETRO_LOG_INFO, "[Stella]: XRGB8888 is not supported.\n");
if(log_cb) log_cb(RETRO_LOG_INFO, "XRGB8888 is not supported.\n");
return false;
}
@ -686,20 +879,21 @@ void retro_run()
return;
}
update_input();
stella.runFrame();
if(stella_lightgun_crosshair && input_crosshair[0] && input_crosshair[1])
draw_crosshair(input_crosshair[0], input_crosshair[1], 0x0000ff);
if(stella.getVideoResize())
update_geometry();
//printf("retro_run - %d %d %d - %d\n", stella.getVideoWidth(), stella.getVideoHeight(), stella.getVideoPitch(), stella.getAudioSize() );
if(stella.getVideoReady())
video_cb(reinterpret_cast<uInt32*>(stella.getVideoBuffer()) + crop_left, stella.getVideoWidth() - crop_left, stella.getVideoHeight(), stella.getVideoPitch());
video_cb(reinterpret_cast<uInt32*>(stella.getVideoBuffer()) + crop_left + (crop_top * stella.getVideoWidthMax()),
stella.getVideoWidth() - crop_left,
stella.getVideoHeight() - crop_top * 2,
stella.getVideoPitch());
if(stella.getAudioReady())
audio_batch_cb(stella.getAudioBuffer(), stella.getAudioSize());

File diff suppressed because it is too large Load Diff