diff --git a/libretro/Makefile b/libretro/Makefile index cde75a0..75ddfc6 100644 --- a/libretro/Makefile +++ b/libretro/Makefile @@ -6,6 +6,15 @@ ifneq ($(GIT_VERSION)," unknown") CFLAGS += -DGIT_VERSION=\"$(GIT_VERSION)\" endif +SPACE := +SPACE := $(SPACE) $(SPACE) +BACKSLASH := +BACKSLASH := \$(BACKSLASH) +filter_out1 = $(filter-out $(firstword $1),$1) +filter_out2 = $(call filter_out1,$(call filter_out1,$1)) +unixpath = $(subst \,/,$1) +unixcygpath = /$(subst :,,$(call unixpath,$1)) + CFLAGS += -DSAMEBOY_CORE_VERSION=\"$(VERSION)\" ifeq ($(platform),) @@ -134,6 +143,102 @@ else ifeq ($(platform), vita) AR = arm-vita-eabi-ar CFLAGS += -Wl,-q -Wall -O3 -fno-short-enums -fno-optimize-sibling-calls STATIC_LINKING = 1 + +# Windows MSVC 2017 all architectures +else ifneq (,$(findstring windows_msvc2017,$(platform))) + + NO_GCC := 1 + CFLAGS += -DNOMINMAX + CXXFLAGS += -DNOMINMAX + WINDOWS_VERSION = 1 + + PlatformSuffix = $(subst windows_msvc2017_,,$(platform)) + ifneq (,$(findstring desktop,$(PlatformSuffix))) + WinPartition = desktop + MSVC2017CompileFlags = -DWINAPI_FAMILY=WINAPI_FAMILY_DESKTOP_APP -FS + LDFLAGS += -MANIFEST -LTCG:incremental -NXCOMPAT -DYNAMICBASE -DEBUG -OPT:REF -INCREMENTAL:NO -SUBSYSTEM:WINDOWS -MANIFESTUAC:"level='asInvoker' uiAccess='false'" -OPT:ICF -ERRORREPORT:PROMPT -NOLOGO -TLBID:1 + LIBS += kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib + else ifneq (,$(findstring uwp,$(PlatformSuffix))) + WinPartition = uwp + MSVC2017CompileFlags = -DWINAPI_FAMILY=WINAPI_FAMILY_APP -D_WINDLL -D_UNICODE -DUNICODE -D__WRL_NO_DEFAULT_LIB__ -EHsc -FS + LDFLAGS += -APPCONTAINER -NXCOMPAT -DYNAMICBASE -MANIFEST:NO -LTCG -OPT:REF -SUBSYSTEM:CONSOLE -MANIFESTUAC:NO -OPT:ICF -ERRORREPORT:PROMPT -NOLOGO -TLBID:1 -DEBUG:FULL -WINMD:NO + LIBS += WindowsApp.lib + endif + + CFLAGS += $(MSVC2017CompileFlags) + CXXFLAGS += $(MSVC2017CompileFlags) + + TargetArchMoniker = $(subst $(WinPartition)_,,$(PlatformSuffix)) + + CC = cl.exe + CXX = cl.exe + LD = link.exe + + reg_query = $(call filter_out2,$(subst $2,,$(shell reg query "$2" -v "$1" 2>nul))) + fix_path = $(subst $(SPACE),\ ,$(subst \,/,$1)) + + ProgramFiles86w := $(shell cmd /c "echo %PROGRAMFILES(x86)%") + ProgramFiles86 := $(shell cygpath "$(ProgramFiles86w)") + + WindowsSdkDir ?= $(call reg_query,InstallationFolder,HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Microsoft SDKs\Windows\v10.0) + WindowsSdkDir ?= $(call reg_query,InstallationFolder,HKEY_CURRENT_USER\SOFTWARE\Wow6432Node\Microsoft\Microsoft SDKs\Windows\v10.0) + WindowsSdkDir ?= $(call reg_query,InstallationFolder,HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SDKs\Windows\v10.0) + WindowsSdkDir ?= $(call reg_query,InstallationFolder,HKEY_CURRENT_USER\SOFTWARE\Microsoft\Microsoft SDKs\Windows\v10.0) + WindowsSdkDir := $(WindowsSdkDir) + + WindowsSDKVersion ?= $(firstword $(foreach folder,$(subst $(subst \,/,$(WindowsSdkDir)Include/),,$(wildcard $(call fix_path,$(WindowsSdkDir)Include\*))),$(if $(wildcard $(call fix_path,$(WindowsSdkDir)Include/$(folder)/um/Windows.h)),$(folder),)))$(BACKSLASH) + WindowsSDKVersion := $(WindowsSDKVersion) + + VsInstallBuildTools = $(ProgramFiles86)/Microsoft Visual Studio/2017/BuildTools + VsInstallEnterprise = $(ProgramFiles86)/Microsoft Visual Studio/2017/Enterprise + VsInstallProfessional = $(ProgramFiles86)/Microsoft Visual Studio/2017/Professional + VsInstallCommunity = $(ProgramFiles86)/Microsoft Visual Studio/2017/Community + + VsInstallRoot ?= $(shell if [ -d "$(VsInstallBuildTools)" ]; then echo "$(VsInstallBuildTools)"; fi) + ifeq ($(VsInstallRoot), ) + VsInstallRoot = $(shell if [ -d "$(VsInstallEnterprise)" ]; then echo "$(VsInstallEnterprise)"; fi) + endif + ifeq ($(VsInstallRoot), ) + VsInstallRoot = $(shell if [ -d "$(VsInstallProfessional)" ]; then echo "$(VsInstallProfessional)"; fi) + endif + ifeq ($(VsInstallRoot), ) + VsInstallRoot = $(shell if [ -d "$(VsInstallCommunity)" ]; then echo "$(VsInstallCommunity)"; fi) + endif + VsInstallRoot := $(VsInstallRoot) + + VcCompilerToolsVer := $(shell cat "$(VsInstallRoot)/VC/Auxiliary/Build/Microsoft.VCToolsVersion.default.txt" | grep -o '[0-9\.]*') + VcCompilerToolsDir := $(VsInstallRoot)/VC/Tools/MSVC/$(VcCompilerToolsVer) + + WindowsSDKSharedIncludeDir := $(shell cygpath -w "$(WindowsSdkDir)\Include\$(WindowsSDKVersion)\shared") + WindowsSDKUCRTIncludeDir := $(shell cygpath -w "$(WindowsSdkDir)\Include\$(WindowsSDKVersion)\ucrt") + WindowsSDKUMIncludeDir := $(shell cygpath -w "$(WindowsSdkDir)\Include\$(WindowsSDKVersion)\um") + WindowsSDKUCRTLibDir := $(shell cygpath -w "$(WindowsSdkDir)\Lib\$(WindowsSDKVersion)\ucrt\$(TargetArchMoniker)") + WindowsSDKUMLibDir := $(shell cygpath -w "$(WindowsSdkDir)\Lib\$(WindowsSDKVersion)\um\$(TargetArchMoniker)") + + # For some reason the HostX86 compiler doesn't like compiling for x64 + # ("no such file" opening a shared library), and vice-versa. + # Work around it for now by using the strictly x86 compiler for x86, and x64 for x64. + # NOTE: What about ARM? + ifneq (,$(findstring x64,$(TargetArchMoniker))) + VCCompilerToolsBinDir := $(VcCompilerToolsDir)\bin\HostX64 + else + VCCompilerToolsBinDir := $(VcCompilerToolsDir)\bin\HostX86 + endif + + PATH := $(shell IFS=$$'\n'; cygpath "$(VCCompilerToolsBinDir)/$(TargetArchMoniker)"):$(PATH) + PATH := $(PATH):$(shell IFS=$$'\n'; cygpath "$(VsInstallRoot)/Common7/IDE") + INCLUDE := $(shell IFS=$$'\n'; cygpath -w "$(VcCompilerToolsDir)/include") + LIB := $(shell IFS=$$'\n'; cygpath -w "$(VcCompilerToolsDir)/lib/$(TargetArchMoniker)") + ifneq (,$(findstring uwp,$(PlatformSuffix))) + LIB := $(LIB);$(shell IFS=$$'\n'; cygpath -w "$(LIB)/store") + endif + + export INCLUDE := $(INCLUDE);$(WindowsSDKSharedIncludeDir);$(WindowsSDKUCRTIncludeDir);$(WindowsSDKUMIncludeDir) + export LIB := $(LIB);$(WindowsSDKUCRTLibDir);$(WindowsSDKUMLibDir) + TARGET := $(TARGET_NAME)_libretro.dll + PSS_STYLE :=2 + LDFLAGS += -DLL + else CC = gcc TARGET := $(TARGET_NAME)_libretro.dll @@ -157,6 +262,22 @@ include Makefile.common OBJECTS := $(patsubst %.c,$(CORE_DIR)/build/obj/%_libretro.c.o,$(SOURCES_C)) +OBJOUT = -o +LINKOUT = -o + +ifneq (,$(findstring msvc,$(platform))) + OBJOUT = -Fo + LINKOUT = -out: +ifeq ($(STATIC_LINKING),1) + LD ?= lib.exe + STATIC_LINKING=0 +else + LD = link.exe +endif +else + LD = $(CC) +endif + CFLAGS += -Wall -D__LIBRETRO__ $(fpic) $(INCFLAGS) -std=gnu11 -D_GNU_SOURCE -D_USE_MATH_DEFINES all: $(TARGET) @@ -182,15 +303,15 @@ $(TARGET): $(OBJECTS) ifeq ($(STATIC_LINKING), 1) $(AR) rcs $@ $(OBJECTS) else - $(CC) $(fpic) $(SHARED) $(INCFLAGS) -o $@ $(OBJECTS) $(LDFLAGS) + $(LD) $(fpic) $(SHARED) $(INCFLAGS) $(LINKOUT)$@ $(OBJECTS) $(LDFLAGS) endif $(CORE_DIR)/build/obj/%_libretro.c.o: %.c -@$(MKDIR) -p $(dir $@) - $(CC) -c -o $@ $< $(CFLAGS) $(fpic) -DGB_INTERNAL + $(CC) -c $(OBJOUT)$@ $< $(CFLAGS) $(fpic) -DGB_INTERNAL %.o: %.c - $(CC) $(CFLAGS) $(fpic) -c -o $@ $< + $(CC) $(CFLAGS) $(fpic) -c $(OBJOUT)$@ $< clean: rm -f $(OBJECTS) $(TARGET) diff --git a/libretro/Makefile.common b/libretro/Makefile.common index dfedccf..fb3a02f 100644 --- a/libretro/Makefile.common +++ b/libretro/Makefile.common @@ -1,6 +1,7 @@ INCFLAGS := -I$(CORE_DIR) SOURCES_C := $(CORE_DIR)/Core/gb.c \ + $(CORE_DIR)/Core/sgb.c \ $(CORE_DIR)/Core/apu.c \ $(CORE_DIR)/Core/memory.c \ $(CORE_DIR)/Core/mbc.c \ @@ -14,6 +15,8 @@ SOURCES_C := $(CORE_DIR)/Core/gb.c \ $(CORE_DIR)/libretro/agb_boot.c \ $(CORE_DIR)/libretro/cgb_boot.c \ $(CORE_DIR)/libretro/dmg_boot.c \ + $(CORE_DIR)/libretro/sgb_boot.c \ + $(CORE_DIR)/libretro/sgb2_boot.c \ $(CORE_DIR)/libretro/libretro.c CFLAGS += -DDISABLE_TIMEKEEPING -DDISABLE_REWIND -DDISABLE_DEBUGGER diff --git a/libretro/libretro.c b/libretro/libretro.c index 7d50c52..3dc33a5 100644 --- a/libretro/libretro.c +++ b/libretro/libretro.c @@ -35,6 +35,10 @@ static const char slash = '/'; #define VIDEO_HEIGHT 144 #define VIDEO_PIXELS (VIDEO_WIDTH * VIDEO_HEIGHT) +#define SGB_VIDEO_WIDTH 256 +#define SGB_VIDEO_HEIGHT 224 +#define SGB_VIDEO_PIXELS (SGB_VIDEO_WIDTH * SGB_VIDEO_HEIGHT) + #define RETRO_MEMORY_GAMEBOY_1_SRAM ((1 << 8) | RETRO_MEMORY_SAVE_RAM) #define RETRO_MEMORY_GAMEBOY_1_RTC ((2 << 8) | RETRO_MEMORY_RTC) #define RETRO_MEMORY_GAMEBOY_2_SRAM ((3 << 8) | RETRO_MEMORY_SAVE_RAM) @@ -49,6 +53,8 @@ enum model { MODEL_DMG, MODEL_CGB, MODEL_AGB, + MODEL_SGB, + MODEL_SGB2, MODEL_AUTO }; @@ -56,7 +62,9 @@ static const GB_model_t libretro_to_internal_model[] = { [MODEL_DMG] = GB_MODEL_DMG_B, [MODEL_CGB] = GB_MODEL_CGB_E, - [MODEL_AGB] = GB_MODEL_AGB + [MODEL_AGB] = GB_MODEL_AGB, + [MODEL_SGB] = GB_MODEL_SGB, + [MODEL_SGB2] = GB_MODEL_SGB2 }; enum screen_layout { @@ -69,12 +77,6 @@ enum audio_out { GB_2 }; -enum mode{ - MODE_SINGLE_GAME, - MODE_SINGLE_GAME_DUAL, - MODE_DUAL_GAME -}; - static enum model model[2]; static enum model auto_model = MODEL_CGB; @@ -93,11 +95,7 @@ static bool initialized = false; static unsigned screen_layout = 0; static unsigned audio_out = 0; -static enum mode mode = MODE_SINGLE_GAME; - static bool geometry_updated = false; -static bool sameboy_dual = false; - static bool link_cable_emulation = false; /*static bool infrared_emulation = false;*/ @@ -109,8 +107,8 @@ char retro_game_path[4096]; GB_gameboy_t gameboy[2]; -extern const unsigned char dmg_boot[], cgb_boot[], agb_boot[]; -extern const unsigned dmg_boot_length, cgb_boot_length, agb_boot_length; +extern const unsigned char dmg_boot[], cgb_boot[], agb_boot[], sgb_boot[], sgb2_boot[]; +extern const unsigned dmg_boot_length, cgb_boot_length, agb_boot_length, sgb_boot_length, sgb2_boot_length; bool vblank1_occurred = false, vblank2_occurred = false; static void fallback_log(enum retro_log_level level, const char *fmt, ...) @@ -124,44 +122,31 @@ static void fallback_log(enum retro_log_level level, const char *fmt, ...) static struct retro_rumble_interface rumble; -static void extract_basename(char *buf, const char *path, size_t size) -{ - const char *base = strrchr(path, '/'); - if (!base) - base = strrchr(path, '\\'); - if (!base) - base = path; - - if (*base == '\\' || *base == '/') - base++; - - strncpy(buf, base, size - 1); - buf[size - 1] = '\0'; - - char *ext = strrchr(buf, '.'); - if (ext) - *ext = '\0'; -} - static void GB_update_keys_status(GB_gameboy_t *gb, unsigned port) { - input_poll_cb(); - GB_set_key_state(gb, GB_KEY_RIGHT,input_state_cb(port, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_RIGHT)); - GB_set_key_state(gb, GB_KEY_LEFT, input_state_cb(port, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_LEFT)); - GB_set_key_state(gb, GB_KEY_UP,input_state_cb(port, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_UP) ); - GB_set_key_state(gb, GB_KEY_DOWN,input_state_cb(port, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_DOWN)); - GB_set_key_state(gb, GB_KEY_A,input_state_cb(port, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_A) ); - GB_set_key_state(gb, GB_KEY_B,input_state_cb(port, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_B) ); - GB_set_key_state(gb, GB_KEY_SELECT,input_state_cb(port, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_SELECT)); - GB_set_key_state(gb, GB_KEY_START,input_state_cb(port, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_START) ); + GB_set_key_state_for_player(gb, GB_KEY_RIGHT, emulated_devices == 1 ? port : 0, + input_state_cb(port, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_RIGHT)); + GB_set_key_state_for_player(gb, GB_KEY_LEFT, emulated_devices == 1 ? port : 0, + input_state_cb(port, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_LEFT)); + GB_set_key_state_for_player(gb, GB_KEY_UP, emulated_devices == 1 ? port : 0, + input_state_cb(port, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_UP)); + GB_set_key_state_for_player(gb, GB_KEY_DOWN, emulated_devices == 1 ? port : 0, + input_state_cb(port, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_DOWN)); + GB_set_key_state_for_player(gb, GB_KEY_A, emulated_devices == 1 ? port : 0, + input_state_cb(port, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_A)); + GB_set_key_state_for_player(gb, GB_KEY_B, emulated_devices == 1 ? port : 0, + input_state_cb(port, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_B)); + GB_set_key_state_for_player(gb, GB_KEY_SELECT, emulated_devices == 1 ? port : 0, + input_state_cb(port, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_SELECT)); + GB_set_key_state_for_player(gb, GB_KEY_START, emulated_devices == 1 ? port : 0, + input_state_cb(port, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_START)); if (gb->rumble_state) rumble.set_rumble_state(port, RETRO_RUMBLE_STRONG, 65535); else rumble.set_rumble_state(port, RETRO_RUMBLE_STRONG, 0); - } @@ -230,26 +215,9 @@ static retro_environment_t environ_cb; /* variables for single cart mode */ static const struct retro_variable vars_single[] = { - { "sameboy_dual", "Single cart dual mode (reload); disabled|enabled" }, { "sameboy_color_correction_mode", "Color correction; off|correct curves|emulate hardware|preserve brightness" }, { "sameboy_high_pass_filter_mode", "High-pass filter; off|accurate|remove dc offset" }, - { "sameboy_model", "Emulated model; Game Boy Color|Game Boy Advance|Auto|Game Boy" }, - { NULL } -}; - -/* variables for single cart dual gameboy mode */ -static const struct retro_variable vars_single_dual[] = { - { "sameboy_dual", "Single cart dual mode (reload); disabled|enabled" }, - { "sameboy_link", "Link cable emulation; enabled|disabled" }, - /*{ "sameboy_ir", "Infrared Sensor Emulation; disabled|enabled" },*/ - { "sameboy_screen_layout", "Screen layout; top-down|left-right" }, - { "sameboy_audio_output", "Audio output; Game Boy #1|Game Boy #2" }, - { "sameboy_model_1", "Emulated model for Game Boy #1; Game Boy Color|Game Boy Advance|Auto|Game Boy" }, - { "sameboy_model_2", "Emulated model for Game Boy #2; Game Boy Color|Game Boy Advance|Auto|Game Boy" }, - { "sameboy_color_correction_mode_1", "Color correction for Game Boy #1; off|correct curves|emulate hardware|preserve brightness" }, - { "sameboy_color_correction_mode_2", "Color correction for Game Boy #2; off|correct curves|emulate hardware|preserve brightness" }, - { "sameboy_high_pass_filter_mode_1", "High-pass filter for Game Boy #1; off|accurate|remove dc offset" }, - { "sameboy_high_pass_filter_mode_2", "High-pass filter for Game Boy #2; off|accurate|remove dc offset" }, + { "sameboy_model", "Emulated model; Auto|Game Boy|Game Boy Color|Game Boy Advance|Super Game Boy|Super Game Boy 2" }, { NULL } }; @@ -259,8 +227,8 @@ static const struct retro_variable vars_dual[] = { /*{ "sameboy_ir", "Infrared Sensor Emulation; disabled|enabled" },*/ { "sameboy_screen_layout", "Screen layout; top-down|left-right" }, { "sameboy_audio_output", "Audio output; Game Boy #1|Game Boy #2" }, - { "sameboy_model_1", "Emulated model for Game Boy #1; Game Boy Color|Game Boy Advance|Auto|Game Boy" }, - { "sameboy_model_2", "Emulated model for Game Boy #2; Game Boy Color|Game Boy Advance|Auto|Game Boy" }, + { "sameboy_model_1", "Emulated model for Game Boy #1; Auto|Game Boy|Game Boy Color|Game Boy Advance" }, + { "sameboy_model_2", "Emulated model for Game Boy #2; Auto|Game Boy|Game Boy Color|Game Boy Advance" }, { "sameboy_color_correction_mode_1", "Color correction for Game Boy #1; off|correct curves|emulate hardware|preserve brightness" }, { "sameboy_color_correction_mode_2", "Color correction for Game Boy #2; off|correct curves|emulate hardware|preserve brightness" }, { "sameboy_high_pass_filter_mode_1", "High-pass filter for Game Boy #1; off|accurate|remove dc offset" }, @@ -283,15 +251,88 @@ static const struct retro_subsystem_rom_info gb_roms[] = { { "GameBoy #2", "gb|gbc", true, false, true, gb2_memory, 1 }, }; - static const struct retro_subsystem_info subsystems[] = { - { "2 Player Game Boy Link", "gb_link_2p", gb_roms, 2, RETRO_GAME_TYPE_GAMEBOY_LINK_2P }, - { NULL }, +static const struct retro_subsystem_info subsystems[] = { + { "2 Player Game Boy Link", "gb_link_2p", gb_roms, 2, RETRO_GAME_TYPE_GAMEBOY_LINK_2P }, + { NULL }, }; static const struct retro_controller_description controllers[] = { { "Nintendo Game Boy", RETRO_DEVICE_SUBCLASS(RETRO_DEVICE_JOYPAD, 0) }, }; +static const struct retro_controller_description controllers_sgb[] = { + { "SNES/SFC Gamepad", RETRO_DEVICE_SUBCLASS(RETRO_DEVICE_JOYPAD, 0) }, +}; + +static struct retro_input_descriptor descriptors_1p[] = { + { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_LEFT, "Left" }, + { 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_RIGHT, "Right" }, + { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_B, "B" }, + { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_A, "A" }, + { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_SELECT, "Select" }, + { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_START, "Start" }, + { 0 }, +}; + +static struct retro_input_descriptor descriptors_2p[] = { + { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_LEFT, "Left" }, + { 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_RIGHT, "Right" }, + { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_B, "B" }, + { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_A, "A" }, + { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_SELECT, "Select" }, + { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_START, "Start" }, + { 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_LEFT, "Left" }, + { 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_RIGHT, "Right" }, + { 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_B, "B" }, + { 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_A, "A" }, + { 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_SELECT, "Select" }, + { 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_START, "Start" }, + { 0 }, +}; + +static struct retro_input_descriptor descriptors_4p[] = { + { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_LEFT, "Left" }, + { 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_RIGHT, "Right" }, + { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_B, "B" }, + { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_A, "A" }, + { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_SELECT, "Select" }, + { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_START, "Start" }, + { 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_LEFT, "Left" }, + { 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_RIGHT, "Right" }, + { 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_B, "B" }, + { 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_A, "A" }, + { 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_SELECT, "Select" }, + { 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_START, "Start" }, + { 2, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_LEFT, "Left" }, + { 2, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_UP, "Up" }, + { 2, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_DOWN, "Down" }, + { 2, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_RIGHT, "Right" }, + { 2, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_B, "B" }, + { 2, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_A, "A" }, + { 2, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_SELECT, "Select" }, + { 3, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_START, "Start" }, + { 3, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_LEFT, "Left" }, + { 3, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_UP, "Up" }, + { 3, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_DOWN, "Down" }, + { 3, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_RIGHT, "Right" }, + { 3, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_B, "B" }, + { 3, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_A, "A" }, + { 3, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_SELECT, "Select" }, + { 3, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_START, "Start" }, + { 0 }, +}; + + static void set_link_cable_state(bool state) { if (state && emulated_devices == 2) @@ -327,9 +368,9 @@ static void init_for_current_model(unsigned id) else { GB_init(&gameboy[i], libretro_to_internal_model[effective_model]); } - const char *model_name = (const char *[]){"dmg", "cgb", "agb"}[effective_model]; - const unsigned char *boot_code = (const unsigned char *[]){dmg_boot, cgb_boot, agb_boot}[effective_model]; - unsigned boot_length = (unsigned []){dmg_boot_length, cgb_boot_length, agb_boot_length}[effective_model]; + const char *model_name = (const char *[]){"dmg", "cgb", "agb", "sgb", "sgb2"}[effective_model]; + const unsigned char *boot_code = (const unsigned char *[]){dmg_boot, cgb_boot, agb_boot, sgb_boot, sgb2_boot}[effective_model]; + unsigned boot_length = (unsigned []){dmg_boot_length, cgb_boot_length, agb_boot_length, sgb_boot_length, sgb2_boot_length}[effective_model]; char buf[256]; snprintf(buf, sizeof(buf), "%s%c%s_boot.bin", retro_system_directory, slash, model_name); @@ -338,7 +379,8 @@ static void init_for_current_model(unsigned id) if (GB_load_boot_rom(&gameboy[i], buf)) GB_load_boot_rom_from_buffer(&gameboy[i], boot_code, boot_length); GB_set_user_data(&gameboy[i], (void*)NULL); - GB_set_pixels_output(&gameboy[i],(unsigned int*)(frame_buf + i * VIDEO_PIXELS)); + + GB_set_pixels_output(&gameboy[i],(unsigned int*)(frame_buf + i * ((model[i] == MODEL_SGB || model[i] == MODEL_SGB2) ? SGB_VIDEO_PIXELS : VIDEO_PIXELS))); GB_set_rgb_encode_callback(&gameboy[i], rgb_encode); GB_set_sample_rate(&gameboy[i], AUDIO_FREQUENCY); @@ -388,7 +430,7 @@ static void init_for_current_model(unsigned id) descs[6].ptr = GB_get_direct_access(&gameboy[i], GB_DIRECT_ACCESS_OAM, &size, &bank); descs[6].start = 0xFE00; descs[6].len = 0x00A0; - + descs[7].ptr = GB_get_direct_access(&gameboy[i], GB_DIRECT_ACCESS_RAM, &size, &bank) + 0x1000; descs[7].start = 0xD000; descs[7].len = 0x1000; @@ -397,12 +439,46 @@ static void init_for_current_model(unsigned id) mmaps.descriptors = descs; mmaps.num_descriptors = sizeof(descs) / sizeof(descs[0]); environ_cb(RETRO_ENVIRONMENT_SET_MEMORY_MAPS, &mmaps); + + /* Let's be extremely nitpicky about how devices and descriptors are set */ + if (emulated_devices == 1 && (model[0] == MODEL_SGB || model[0] == MODEL_SGB2)) + { + static const struct retro_controller_info ports[] = { + { controllers_sgb, 1 }, + { controllers_sgb, 1 }, + { controllers_sgb, 1 }, + { controllers_sgb, 1 }, + { NULL, 0 }, + }; + environ_cb(RETRO_ENVIRONMENT_SET_CONTROLLER_INFO, (void*)ports); + environ_cb(RETRO_ENVIRONMENT_SET_INPUT_DESCRIPTORS, descriptors_4p); + } + else if (emulated_devices == 1) + { + static const struct retro_controller_info ports[] = { + { controllers, 1 }, + { NULL, 0 }, + }; + environ_cb(RETRO_ENVIRONMENT_SET_CONTROLLER_INFO, (void*)ports); + environ_cb(RETRO_ENVIRONMENT_SET_INPUT_DESCRIPTORS, descriptors_1p); + } + else + { + static const struct retro_controller_info ports[] = { + { controllers, 1 }, + { controllers, 1 }, + { NULL, 0 }, + }; + environ_cb(RETRO_ENVIRONMENT_SET_CONTROLLER_INFO, (void*)ports); + environ_cb(RETRO_ENVIRONMENT_SET_INPUT_DESCRIPTORS, descriptors_2p); + } + } -static void check_variables(bool link) +static void check_variables() { struct retro_variable var = {0}; - if (!link) + if (emulated_devices == 1) { var.key = "sameboy_color_correction_mode"; var.value = NULL; @@ -441,11 +517,16 @@ static void check_variables(bool link) new_model = MODEL_CGB; else if (strcmp(var.value, "Game Boy Advance") == 0) new_model = MODEL_AGB; + else if (strcmp(var.value, "Super Game Boy") == 0) + new_model = MODEL_SGB; + else if (strcmp(var.value, "Super Game Boy 2") == 0) + new_model = MODEL_SGB2; else new_model = MODEL_AUTO; if (new_model != model[0]) { + geometry_updated = true; model[0] = new_model; init_for_current_model(0); } @@ -516,6 +597,10 @@ static void check_variables(bool link) new_model = MODEL_CGB; else if (strcmp(var.value, "Game Boy Advance") == 0) new_model = MODEL_AGB; + else if (strcmp(var.value, "Super Game Boy") == 0) + new_model = MODEL_SGB; + else if (strcmp(var.value, "Super Game Boy 2") == 0) + new_model = MODEL_SGB2; else new_model = MODEL_AUTO; @@ -537,6 +622,10 @@ static void check_variables(bool link) new_model = MODEL_CGB; else if (strcmp(var.value, "Game Boy Advance") == 0) new_model = MODEL_AGB; + else if (strcmp(var.value, "Super Game Boy") == 0) + new_model = MODEL_SGB; + else if (strcmp(var.value, "Super Game Boy 2") == 0) + new_model = MODEL_SGB; else new_model = MODEL_AUTO; @@ -547,53 +636,42 @@ static void check_variables(bool link) } } - } + var.key = "sameboy_screen_layout"; + var.value = NULL; + if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) + { + if (strcmp(var.value, "top-down") == 0) + screen_layout = LAYOUT_TOP_DOWN; + else + screen_layout = LAYOUT_LEFT_RIGHT; - var.key = "sameboy_screen_layout"; - var.value = NULL; - if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) - { - if (strcmp(var.value, "top-down") == 0) - screen_layout = LAYOUT_TOP_DOWN; - else - screen_layout = LAYOUT_LEFT_RIGHT; + geometry_updated = true; + } - geometry_updated = true; - } + var.key = "sameboy_link"; + var.value = NULL; + if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) + { + bool tmp = link_cable_emulation; + if (strcmp(var.value, "enabled") == 0) + link_cable_emulation = true; + else + link_cable_emulation = false; + if (link_cable_emulation && link_cable_emulation != tmp) + set_link_cable_state(true); + else if (!link_cable_emulation && link_cable_emulation != tmp) + set_link_cable_state(false); + } - var.key = "sameboy_dual"; - var.value = NULL; - if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) - { - if (strcmp(var.value, "enabled") == 0) - sameboy_dual = true; - else - sameboy_dual = false; - } - - var.key = "sameboy_link"; - var.value = NULL; - if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) - { - bool tmp = link_cable_emulation; - if (strcmp(var.value, "enabled") == 0) - link_cable_emulation = true; - else - link_cable_emulation = false; - if (link_cable_emulation && link_cable_emulation != tmp) - set_link_cable_state(true); - else if (!link_cable_emulation && link_cable_emulation != tmp) - set_link_cable_state(false); - } - - var.key = "sameboy_audio_output"; - var.value = NULL; - if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) - { - if (strcmp(var.value, "Game Boy #1") == 0) - audio_out = GB_1; - else - audio_out = GB_2; + var.key = "sameboy_audio_output"; + var.value = NULL; + if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) + { + if (strcmp(var.value, "Game Boy #1") == 0) + audio_out = GB_1; + else + audio_out = GB_2; + } } } @@ -610,37 +688,6 @@ void retro_init(void) snprintf(retro_save_directory, sizeof(retro_save_directory), "%s", dir); else snprintf(retro_save_directory, sizeof(retro_save_directory), "%s", "."); - - static const struct retro_controller_info ports[] = { - { controllers, 1 }, - { controllers, 1 }, - { NULL, 0 }, - }; - - environ_cb(RETRO_ENVIRONMENT_SET_CONTROLLER_INFO, (void*)ports); - - struct retro_input_descriptor desc[] = { - { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_LEFT, "Left" }, - { 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_RIGHT, "Right" }, - { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_B, "B" }, - { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_A, "A" }, - { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_SELECT, "Select" }, - { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_START, "Start" }, - { 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_LEFT, "Left" }, - { 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_RIGHT, "Right" }, - { 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_B, "B" }, - { 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_A, "A" }, - { 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_SELECT, "Select" }, - { 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_START, "Start" }, - { 0 }, - }; - - environ_cb(RETRO_ENVIRONMENT_SET_INPUT_DESCRIPTORS, desc); - } void retro_deinit(void) @@ -679,23 +726,42 @@ void retro_get_system_av_info(struct retro_system_av_info *info) struct retro_game_geometry geom; struct retro_system_timing timing = { FRAME_RATE, AUDIO_FREQUENCY }; - if (screen_layout == LAYOUT_TOP_DOWN) { - geom.base_width = VIDEO_WIDTH; - geom.base_height = VIDEO_HEIGHT * emulated_devices; - geom.aspect_ratio = (double)VIDEO_WIDTH / (emulated_devices * VIDEO_HEIGHT); - }else if (screen_layout == LAYOUT_LEFT_RIGHT) { - geom.base_width = VIDEO_WIDTH * emulated_devices; - geom.base_height = VIDEO_HEIGHT; - geom.aspect_ratio = ((double)VIDEO_WIDTH * emulated_devices) / VIDEO_HEIGHT; + if (emulated_devices == 2) + { + if (screen_layout == LAYOUT_TOP_DOWN) { + geom.base_width = VIDEO_WIDTH; + geom.base_height = VIDEO_HEIGHT * emulated_devices; + geom.aspect_ratio = (double)VIDEO_WIDTH / (emulated_devices * VIDEO_HEIGHT); + }else if (screen_layout == LAYOUT_LEFT_RIGHT) { + geom.base_width = VIDEO_WIDTH * emulated_devices; + geom.base_height = VIDEO_HEIGHT; + geom.aspect_ratio = ((double)VIDEO_WIDTH * emulated_devices) / VIDEO_HEIGHT; + } + } + else + { + if (model[0] == MODEL_SGB || model[0] == MODEL_SGB2) + { + geom.base_width = SGB_VIDEO_WIDTH; + geom.base_height = SGB_VIDEO_HEIGHT; + geom.aspect_ratio = (double)SGB_VIDEO_WIDTH / SGB_VIDEO_HEIGHT; + } + else + { + geom.base_width = VIDEO_WIDTH; + geom.base_height = VIDEO_HEIGHT; + geom.aspect_ratio = (double)VIDEO_WIDTH / VIDEO_HEIGHT; + } } - geom.max_width = VIDEO_WIDTH * emulated_devices; - geom.max_height = VIDEO_HEIGHT * emulated_devices; + geom.max_width = SGB_VIDEO_WIDTH * emulated_devices; + geom.max_height = SGB_VIDEO_HEIGHT * emulated_devices; info->geometry = geom; info->timing = timing; } + void retro_set_environment(retro_environment_t cb) { environ_cb = cb; @@ -735,7 +801,7 @@ void retro_set_video_refresh(retro_video_refresh_t cb) void retro_reset(void) { for (int i = 0; i < emulated_devices; i++) - GB_reset(&gameboy[i]); + GB_reset(&gameboy[i]); } @@ -750,19 +816,25 @@ void retro_run(void) if (geometry_updated) { struct retro_system_av_info info; retro_get_system_av_info(&info); - geometry_updated = false; environ_cb(RETRO_ENVIRONMENT_SET_GEOMETRY, &info.geometry); + geometry_updated = false; } if (!frame_buf) return; if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE_UPDATE, &updated) && updated) - check_variables(emulated_devices == 2 ? true : false); + check_variables(); - GB_update_keys_status(&gameboy[0], 0); if (emulated_devices == 2) - GB_update_keys_status(&gameboy[1], 1); + GB_update_keys_status(&gameboy[1], 1); + else if (emulated_devices == 1 && (model[0] == MODEL_SGB || model[0] == MODEL_SGB2)) + { + for (unsigned i = 0; i < 4; i++) + GB_update_keys_status(&gameboy[0], i); + } + else + GB_update_keys_status(&gameboy[0], 0); vblank1_occurred = vblank2_occurred = false; signed delta = 0; @@ -778,22 +850,36 @@ void retro_run(void) } } else - GB_run_frame(&gameboy[0]); + { + int x = GB_run_frame(&gameboy[0]); + log_cb(RETRO_LOG_DEBUG, "%d\n", x); + } - if (screen_layout == LAYOUT_TOP_DOWN) { - video_cb(frame_buf, VIDEO_WIDTH, VIDEO_HEIGHT * emulated_devices, VIDEO_WIDTH * sizeof(uint32_t)); - }else if (screen_layout == LAYOUT_LEFT_RIGHT) { - /* use slow memcpy method for now */ - for (int index = 0; index < emulated_devices; index++) { - for (int y = 0; y < VIDEO_HEIGHT; y++) { - for (int x = 0; x < VIDEO_WIDTH; x++) { - frame_buf_copy[VIDEO_WIDTH * emulated_devices * y + (x + VIDEO_WIDTH * index)] = frame_buf[VIDEO_WIDTH * (y + VIDEO_HEIGHT * index) + x]; + if (emulated_devices == 2) + { + if (screen_layout == LAYOUT_TOP_DOWN) { + video_cb(frame_buf, VIDEO_WIDTH, VIDEO_HEIGHT * emulated_devices, VIDEO_WIDTH * sizeof(uint32_t)); + }else if (screen_layout == LAYOUT_LEFT_RIGHT) { + /* use slow memcpy method for now */ + for (int index = 0; index < emulated_devices; index++) { + for (int y = 0; y < VIDEO_HEIGHT; y++) { + for (int x = 0; x < VIDEO_WIDTH; x++) { + frame_buf_copy[VIDEO_WIDTH * emulated_devices * y + (x + VIDEO_WIDTH * index)] = frame_buf[VIDEO_WIDTH * (y + VIDEO_HEIGHT * index) + x]; + } } } - } - video_cb(frame_buf_copy, VIDEO_WIDTH * emulated_devices, VIDEO_HEIGHT, VIDEO_WIDTH * emulated_devices * sizeof(uint32_t)); + video_cb(frame_buf_copy, VIDEO_WIDTH * emulated_devices, VIDEO_HEIGHT, VIDEO_WIDTH * emulated_devices * sizeof(uint32_t)); + } } + else + { + if (model[0] == MODEL_SGB || model[0] == MODEL_SGB2) + video_cb(frame_buf, SGB_VIDEO_WIDTH, SGB_VIDEO_HEIGHT, SGB_VIDEO_WIDTH * sizeof(uint32_t)); + else + video_cb(frame_buf, VIDEO_WIDTH, VIDEO_HEIGHT, VIDEO_WIDTH * sizeof(uint32_t)); + } + initialized = true; } @@ -801,23 +887,10 @@ void retro_run(void) bool retro_load_game(const struct retro_game_info *info) { environ_cb(RETRO_ENVIRONMENT_SET_VARIABLES, (void *)vars_single); - check_variables(false); + check_variables(); - if (sameboy_dual) - { - emulated_devices = 2; - mode = MODE_SINGLE_GAME_DUAL; - environ_cb(RETRO_ENVIRONMENT_SET_VARIABLES, (void *)vars_single_dual); - check_variables(true); - } - else - mode = MODE_SINGLE_GAME; - - frame_buf = (uint32_t*)malloc(emulated_devices * VIDEO_PIXELS * sizeof(uint32_t)); - frame_buf_copy = (uint32_t*)malloc(emulated_devices * VIDEO_PIXELS * sizeof(uint32_t)); - - memset(frame_buf, 0, emulated_devices * VIDEO_PIXELS * sizeof(uint32_t)); - memset(frame_buf_copy, 0, emulated_devices * VIDEO_PIXELS * sizeof(uint32_t)); + frame_buf = (uint32_t*)malloc(SGB_VIDEO_PIXELS* emulated_devices * sizeof(uint32_t)); + memset(frame_buf, 0, SGB_VIDEO_PIXELS * emulated_devices * sizeof(uint32_t)); enum retro_pixel_format fmt = RETRO_PIXEL_FORMAT_XRGB8888; if (!environ_cb(RETRO_ENVIRONMENT_SET_PIXEL_FORMAT, &fmt)) @@ -847,37 +920,12 @@ bool retro_load_game(const struct retro_game_info *info) else log_cb(RETRO_LOG_INFO, "Rumble environment not supported\n"); - check_variables(emulated_devices == 2 ? true : false); - - /* hack: use upstream's file based I/O for Game Boy 2 battery in single cart mode */ - if (mode == MODE_SINGLE_GAME_DUAL) - { - char path[PATH_MAX]; - char file[PATH_MAX]; - - extract_basename(file, retro_game_path, sizeof(file)); - snprintf (path, sizeof(path), "%s%c%s.srm.2", retro_save_directory, slash, file); - log_cb(RETRO_LOG_INFO, "Loading battery for Game Boy 2 from: %s\n", path); - GB_load_battery(&gameboy[1], path); - } - + check_variables(); return true; } void retro_unload_game(void) { - /* hack: use upstream's file based I/O for Game Boy 2 battery in single cart mode */ - if (mode == MODE_SINGLE_GAME_DUAL) - { - char path[PATH_MAX]; - char file[PATH_MAX]; - - extract_basename(file, retro_game_path, sizeof(file)); - snprintf (path, sizeof(path), "%s%c%s.srm.2", retro_save_directory, slash, file); - log_cb(RETRO_LOG_INFO, "Saving battery for Game Boy 2 to: %s\n", path); - GB_save_battery(&gameboy[1], path); - } - for (int i = 0; i < emulated_devices; i++) GB_free(&gameboy[i]); } @@ -891,15 +939,12 @@ bool retro_load_game_special(unsigned type, const struct retro_game_info *info, { if (type == RETRO_GAME_TYPE_GAMEBOY_LINK_2P) - { emulated_devices = 2; - mode = MODE_DUAL_GAME; - } else return false; /* all other types are unhandled for now */ environ_cb(RETRO_ENVIRONMENT_SET_VARIABLES, (void *)vars_dual); - check_variables(true); + check_variables(); frame_buf = (uint32_t*)malloc(emulated_devices * VIDEO_PIXELS * sizeof(uint32_t)); frame_buf_copy = (uint32_t*)malloc(emulated_devices * VIDEO_PIXELS * sizeof(uint32_t)); @@ -935,7 +980,7 @@ bool retro_load_game_special(unsigned type, const struct retro_game_info *info, else log_cb(RETRO_LOG_INFO, "Rumble environment not supported\n"); - check_variables(emulated_devices == 2 ? true : false); + check_variables(); return true; } @@ -998,139 +1043,124 @@ bool retro_unserialize(const void *data, size_t size) void *retro_get_memory_data(unsigned type) { void *data = NULL; - switch(mode) + if (emulated_devices == 1) { - case MODE_SINGLE_GAME: - case MODE_SINGLE_GAME_DUAL: /* todo: hook this properly */ - { - switch(type) - { - case RETRO_MEMORY_SYSTEM_RAM: - data = gameboy[0].ram; - break; - case RETRO_MEMORY_SAVE_RAM: - if (gameboy[0].cartridge_type->has_battery && gameboy[0].mbc_ram_size != 0) - data = gameboy[0].mbc_ram; - else - data = NULL; - break; - case RETRO_MEMORY_VIDEO_RAM: - data = gameboy[0].vram; - break; - case RETRO_MEMORY_RTC: - if(gameboy[0].cartridge_type->has_battery) - data = GB_GET_SECTION(&gameboy[0], rtc); - else - data = NULL; - break; - default: - break; - } - } - break; - case MODE_DUAL_GAME: - { - switch (type) - { - case RETRO_MEMORY_GAMEBOY_1_SRAM: - if (gameboy[0].cartridge_type->has_battery && gameboy[0].mbc_ram_size != 0) - data = gameboy[0].mbc_ram; - else - data = NULL; - break; - case RETRO_MEMORY_GAMEBOY_2_SRAM: - if (gameboy[1].cartridge_type->has_battery && gameboy[1].mbc_ram_size != 0) - data = gameboy[1].mbc_ram; - else - data = NULL; - break; - case RETRO_MEMORY_GAMEBOY_1_RTC: - if(gameboy[0].cartridge_type->has_battery) - data = GB_GET_SECTION(&gameboy[0], rtc); - else - data = NULL; - break; - case RETRO_MEMORY_GAMEBOY_2_RTC: - if(gameboy[1].cartridge_type->has_battery) - data = GB_GET_SECTION(&gameboy[1], rtc); - else - data = NULL; - break; - default: - break; - } - } - break; - default: - break; + switch(type) + { + case RETRO_MEMORY_SYSTEM_RAM: + data = gameboy[0].ram; + break; + case RETRO_MEMORY_SAVE_RAM: + if (gameboy[0].cartridge_type->has_battery && gameboy[0].mbc_ram_size != 0) + data = gameboy[0].mbc_ram; + else + data = NULL; + break; + case RETRO_MEMORY_VIDEO_RAM: + data = gameboy[0].vram; + break; + case RETRO_MEMORY_RTC: + if(gameboy[0].cartridge_type->has_battery) + data = GB_GET_SECTION(&gameboy[0], rtc); + else + data = NULL; + break; + default: + break; + } } + else + { + switch (type) + { + case RETRO_MEMORY_GAMEBOY_1_SRAM: + if (gameboy[0].cartridge_type->has_battery && gameboy[0].mbc_ram_size != 0) + data = gameboy[0].mbc_ram; + else + data = NULL; + break; + case RETRO_MEMORY_GAMEBOY_2_SRAM: + if (gameboy[1].cartridge_type->has_battery && gameboy[1].mbc_ram_size != 0) + data = gameboy[1].mbc_ram; + else + data = NULL; + break; + case RETRO_MEMORY_GAMEBOY_1_RTC: + if(gameboy[0].cartridge_type->has_battery) + data = GB_GET_SECTION(&gameboy[0], rtc); + else + data = NULL; + break; + case RETRO_MEMORY_GAMEBOY_2_RTC: + if(gameboy[1].cartridge_type->has_battery) + data = GB_GET_SECTION(&gameboy[1], rtc); + else + data = NULL; + break; + default: + break; + } + } + return data; } size_t retro_get_memory_size(unsigned type) { size_t size = 0; - switch(mode) + if (emulated_devices == 1) { - case MODE_SINGLE_GAME: - case MODE_SINGLE_GAME_DUAL: /* todo: hook this properly */ - { - switch(type) - { - case RETRO_MEMORY_SYSTEM_RAM: - size = gameboy[0].ram_size; - break; - case RETRO_MEMORY_SAVE_RAM: - if (gameboy[0].cartridge_type->has_battery && gameboy[0].mbc_ram_size != 0) - size = gameboy[0].mbc_ram_size; - else - size = 0; - break; - case RETRO_MEMORY_VIDEO_RAM: - size = gameboy[0].vram_size; - break; - case RETRO_MEMORY_RTC: - if(gameboy[0].cartridge_type->has_battery) - size = GB_SECTION_SIZE(rtc); - else - size = 0; - break; - default: - break; - } - } - break; - case MODE_DUAL_GAME: - { - switch (type) - { - case RETRO_MEMORY_GAMEBOY_1_SRAM: - if (gameboy[0].cartridge_type->has_battery && gameboy[0].mbc_ram_size != 0) - size = gameboy[0].mbc_ram_size; - else - size = 0; - break; - case RETRO_MEMORY_GAMEBOY_2_SRAM: - if (gameboy[1].cartridge_type->has_battery && gameboy[1].mbc_ram_size != 0) - size = gameboy[1].mbc_ram_size; - else - size = 0; - break; - case RETRO_MEMORY_GAMEBOY_1_RTC: - if(gameboy[0].cartridge_type->has_battery) - size = GB_SECTION_SIZE(rtc); - break; - case RETRO_MEMORY_GAMEBOY_2_RTC: - if(gameboy[1].cartridge_type->has_battery) - size = GB_SECTION_SIZE(rtc); - break; - default: - break; - } - } - break; - default: - break; + switch(type) + { + case RETRO_MEMORY_SYSTEM_RAM: + size = gameboy[0].ram_size; + break; + case RETRO_MEMORY_SAVE_RAM: + if (gameboy[0].cartridge_type->has_battery && gameboy[0].mbc_ram_size != 0) + size = gameboy[0].mbc_ram_size; + else + size = 0; + break; + case RETRO_MEMORY_VIDEO_RAM: + size = gameboy[0].vram_size; + break; + case RETRO_MEMORY_RTC: + if(gameboy[0].cartridge_type->has_battery) + size = GB_SECTION_SIZE(rtc); + else + size = 0; + break; + default: + break; + } + } + else + { + switch (type) + { + case RETRO_MEMORY_GAMEBOY_1_SRAM: + if (gameboy[0].cartridge_type->has_battery && gameboy[0].mbc_ram_size != 0) + size = gameboy[0].mbc_ram_size; + else + size = 0; + break; + case RETRO_MEMORY_GAMEBOY_2_SRAM: + if (gameboy[1].cartridge_type->has_battery && gameboy[1].mbc_ram_size != 0) + size = gameboy[1].mbc_ram_size; + else + size = 0; + break; + case RETRO_MEMORY_GAMEBOY_1_RTC: + if(gameboy[0].cartridge_type->has_battery) + size = GB_SECTION_SIZE(rtc); + break; + case RETRO_MEMORY_GAMEBOY_2_RTC: + if(gameboy[1].cartridge_type->has_battery) + size = GB_SECTION_SIZE(rtc); + break; + default: + break; + } } return size;