diff --git a/makefile.libsnes b/makefile.libsnes new file mode 100644 index 000000000..e1fe0d712 --- /dev/null +++ b/makefile.libsnes @@ -0,0 +1,107 @@ +DEBUG=0 + +ifeq ($(platform),) +platform = unix +ifeq ($(shell uname -a),) + platform = win +else ifneq ($(findstring Darwin,$(shell uname -a)),) + platform = osx +else ifneq ($(findstring MINGW,$(shell uname -a)),) + platform = win +endif +endif + +ifeq ($(platform), unix) + TARGET := libsnes.so + fpic := -fPIC + SHARED := -shared -Wl,-no-undefined + ENDIANNESS_DEFINES := -DLSB_FIRST +else ifeq ($(platform), osx) + TARGET := libsnes.dylib + fpic := -fPIC + SHARED := -dynamiclib + ENDIANNESS_DEFINES := -DLSB_FIRST +else ifeq ($(platform), ps3) + TARGET := libsnes.a + SHARED := -shared, -Wl, --version-script=libsnes/link.T + CC = ppu-lv2-gcc + CXX = ppu-lv2-g++ + AR = ppu-lv2-ar + ENDIANNESS_DEFINES = -DWORDS_BIGENDIAN + PLATFORM_DEFINES := -D__CELLOS_LV2 -DSN_TARGET_PS3 +else + TARGET := snes.dll + CC = gcc + CXX = g++ + SHARED := -shared -Wl,-no-undefined + LDFLAGS += -static-libgcc -static-libstdc++ + ENDIANNESS_DEFINES := -DLSB_FIRST +endif + +all: $(TARGET) + +MAIN_FBA_DIR := ./fbalpha/trunk/src +FBA_BURN_DIR := $(MAIN_FBA_DIR)/burn +FBA_BURN_DRIVERS_DIR := $(MAIN_FBA_DIR)/burn/drivers +FBA_BURNER_DIR := $(MAIN_FBA_DIR)/burner +LIBSNES_DIR := ./libsnes +FBA_CPU_DIR := $(MAIN_FBA_DIR)/cpu +FBA_LIB_DIR := ./utils +FBA_INTERFACE_DIR := $(MAIN_FBA_DIR)/interface + +BURN_BLACKLIST := $(FBA_BURN_DIR)/zet_c68k.cpp $(FBA_BURN_DIR)/sek_c68k.cpp $(FBA_BURNER_DIR)/tracklst.cpp $(FBA_CPU_DIR)/arm7/arm7exec.c $(FBA_CPU_DIR)/arm7/arm7core.c $(FBA_CPU_DIR)/hd6309/6309tbl.c $(FBA_CPU_DIR)/hd6309/6309ops.c $(FBA_CPU_DIR)/konami/konamtbl.c $(FBA_CPU_DIR)/konami/konamops.c $(FBA_CPU_DIR)/m68k/m68k_in.c $(FBA_CPU_DIR)/m6800/6800ops.c $(FBA_CPU_DIR)/m6800/6800tbl.c $(FBA_CPU_DIR)/m6805/6805ops.c $(FBA_CPU_DIR)/m6809/6809ops.c $(FBA_CPU_DIR)/m6809/6809tbl.c $(FBA_CPU_DIR)/sh2/mksh2.cpp $(FBA_CPU_DIR)/sh2/mksh2-x86.cpp $(FBA_CPU_DIR)/m68k/m68kmake.c $(FBA_BURNER_DIR)/wave_writer.cpp $(FBA_CPU_DIR)/m68k/m68kdasm.c $(FBA_LIBSNES_DIR)/menu.cpp $(FBA_CPU_DIR)/sh2/mksh2.cpp $(FBA_BURNER_DIR)/sshot.cpp $(FBA_BURNER_DIR)/conc.cpp $(FBA_BURNER_DIR)/dat.cpp $(FBA_BURNER_DIR)/cong.cpp $(FBA_BURNER_DIR)/image.cpp $(FBA_BURNER_DIR)/misc.cpp $(FBA_CPU_DIR)/h6280/tblh6280.c $(FBA_CPU_DIR)/m6502/t65sc02.c $(FBA_CPU_DIR)/m6502/t65c02.c $(FBA_CPU_DIR)/m6502/tdeco16.c $(FBA_CPU_DIR)/m6502/tn2a03.c $(FBA_CPU_DIR)/m6502/t6502.c $(FBA_CPU_DIR)/nec/v25sfr.c $(FBA_CPU_DIR)/nec/v25instr.c $(FBA_CPU_DIR)/nec/necinstr.c $(FBA_BURN_DIR)/drivers/capcom/ctv_make.cpp + +FBA_BURN_DIRS := $(FBA_BURN_DIR) $(FBA_BURN_DIR)/devices $(FBA_BURN_DIR)/sound $(FBA_BURN_DRIVERS_DIR)/capcom $(FBA_BURN_DRIVERS_DIR)/cave $(FBA_BURN_DRIVERS_DIR)/dataeast $(FBA_BURN_DRIVERS_DIR)/cps3 $(FBA_BURN_DRIVERS_DIR)/galaxian $(FBA_BURN_DRIVERS_DIR)/konami $(FBA_BURN_DRIVERS_DIR)/irem $(FBA_BURN_DRIVERS_DIR)/megadrive $(FBA_BURN_DRIVERS_DIR)/misc $(FBA_BURN_DRIVERS_DIR)/neogeo $(FBA_BURN_DRIVERS_DIR)/pgm $(FBA_BURN_DRIVERS_DIR)/psikyo $(FBA_BURN_DRIVERS_DIR)/sega $(FBA_BURN_DRIVERS_DIR)/taito $(FBA_BURN_DRIVERS_DIR)/toaplan $(FBA_BURN_DRIVERS_DIR)/misc_post90s $(FBA_BURN_DRIVERS_DIR)/misc_pre90s + +FBA_CPU_DIRS := $(FBA_CPU_DIR) $(FBA_CPU_DIR)/arm7 $(FBA_CPU_DIR)/arm $(FBA_CPU_DIR)/hd6309 $(FBA_CPU_DIR)/i8039 $(FBA_CPU_DIR)/konami $(FBA_CPU_DIR)/m68k $(FBA_CPU_DIR)/m6502 $(FBA_CPU_DIR)/m6800 $(FBA_CPU_DIR)/m6805 $(FBA_CPU_DIR)/m6809 $(FBA_CPU_DIR)/nec $(FBA_CPU_DIR)/s2650 $(FBA_CPU_DIR)/sh2 $(FBA_CPU_DIR)/z80 $(FBA_CPU_DIR)/h6280 + +FBA_LIB_DIRS := $(FBA_LIB_DIR)/zlib $(FBA_LIB_DIR)/File_Extractor/fex $(FBA_LIB_DIR)/File_Extractor/7z_C + +FBA_SRC_DIRS := $(FBA_BURNER_DIR) $(FBA_BURN_DIRS) $(FBA_CPU_DIRS) $(FBA_BURNER_DIRS) $(FBA_LIB_DIRS) + +FBA_CXXSRCS := $(filter-out $(BURN_BLACKLIST),$(foreach dir,$(FBA_SRC_DIRS),$(wildcard $(dir)/*.cpp))) +FBA_CXXSRCS += $(LIBSNES_DIR)/libsnes.cpp $(LIBSNES_DIR)/archive.cpp $(FBA_BURNER_DIR)/platform/win32/neocdlist.cpp +FBA_CXXOBJ := $(FBA_CXXSRCS:.cpp=.o) +FBA_CSRCS := $(filter-out $(BURN_BLACKLIST),$(foreach dir,$(FBA_SRC_DIRS),$(wildcard $(dir)/*.c))) +FBA_COBJ := $(FBA_CSRCS:.c=.o) + +OBJS := $(FBA_COBJ) $(FBA_CXXOBJ) + +FBA_DEFINES := -DNO_ASMCORE -DNO_AUTOFIRE -DNO_CHEATSEARCH -DNO_COMBO -DUSE_SPEEDHACKS -DNO_PNG -DOLD_AUDIOCORE=0 -D__LIBSNES__ $(ENDIANNESS_DEFINES) $(PLATFORM_DEFINES) -DTIXML_USE_TICPP + +ifeq ($(DEBUG), 1) +CFLAGS += -O0 -g +CXXFLAGS += -O0 -g +else +CFLAGS += -O3 -DNDEBUG +CXXFLAGS += -O3 -DNDEBUG +endif + +CFLAGS += -std=gnu99 $(fpic) -Wno-write-strings $(FBA_DEFINES) +CXXFLAGS += $(fpic) -Wno-write-strings $(FBA_DEFINES) +LDFLAGS += -Wl,-no-undefined $(fpic) -Wl,--version-script=libsnes/link.T + +INCDIRS := -I$(FBA_BURNER_DIR)/platform/win32 -I$(LIBSNES_DIR) -I$(FBA_BURN_DIR) -I$(FBA_BURN_DIR)/burner -I$(MAIN_FBA_DIR)/cpu -I$(FBA_BURN_DIR)/sound -I$(FBA_BURN_DIR)/devices -I../../generated -I$(FBA_INTERFACE_DIR) -I$(FBA_INTERFACE_DIR)/input -I$(FBA_INTERFACE_DIR)/cd -I$(FBA_BURNER_DIR) -I$(MAIN_FBA_DIR)/generated -I$(FBA_CPU_DIR) -I$(FBA_CPU_DIR)/m6809 -I$(FBA_CPU_DIR)/m6805 -I$(FBA_CPU_DIR)/m6800 -I$(FBA_CPU_DIR)/nec -I$(FBA_CPU_DIR)/hd6309 -I$(FBA_CPU_DIR)/arm7 -I$(FBA_CPU_DIR)/i8039 -I$(FBA_CPU_DIR)/konami -I$(FBA_CPU_DIR)/m68k -I$(FBA_CPU_DIR)/m6502 -I$(FBA_CPU_DIR)/z80 -I$(FBA_CPU_DIR)/sh2 -I$(FBA_CPU_DIR)/s2650 -I$(FBA_CPU_DIR)/arm -I$(FBA_LIB_DIR)/zlib -I$(FBA_BURN_DIR)/drivers/capcom -I$(FBA_BURN_DIR)/drivers/dataeast -I$(FBA_BURN_DIR)/drivers/cave -I$(FBA_BURN_DIR)/drivers/neogeo -I$(FBA_BURN_DIR)/drivers/psikyo -I$(FBA_BURN_DIR)/drivers/sega -I$(FBA_BURN_DIR)/drivers/toaplan -I$(FBA_BURN_DIR)/drivers/taito -I$(FBA_BURN_DIR)/drivers/misc_post90s -I$(FBA_LIB_DIR) + +$(TARGET): $(OBJS) + @echo "LD $@" +ifeq ($(platform), ps3) + @$(AR) rcs $@ $(OBJECTS) +else + @$(CXX) -o $@ $(SHARED) $(OBJS) $(LDFLAGS) +endif + +%.o: %.cpp + @echo "CXX $<" + @$(CXX) -c -o $@ $< $(CXXFLAGS) $(INCDIRS) + +%.o: %.c + @echo "CC $<" + @$(CC) -c -o $@ $< $(CFLAGS) $(INCDIRS) + +clean: + rm -f $(TARGET) + rm -f $(OBJS) + +.PHONY: clean + diff --git a/src/burner/libsnes/archive.cpp b/src/burner/libsnes/archive.cpp new file mode 100644 index 000000000..49bdfbfc2 --- /dev/null +++ b/src/burner/libsnes/archive.cpp @@ -0,0 +1,296 @@ +// Archive extract module, added by regret +// use Blargg's File_Extractor (http://www.slack.net/~ant/) + +/* changelog: + update 5: change loadonefile() to use separate fex handle + update 4: update to Blargg's File_Extractor 1.0.0 + update 3: rewrite interface, use Blargg's great File_Extractor + update 2: add load one file from archive + update 1: add 7zip aupport +*/ + +#include "burner.h" +#include "File_Extractor/fex/fex.h" +#include "archive.h" + +static File_Extractor* fex = NULL; +static fex_err_t err = NULL; +static int nCurrFile = 0; // The current file we are pointing to + +static inline bool error(const char* error) +{ + if (error) + { +#ifdef _DEBUG + printf("fex Error: %s\n", error); +#endif + return true; + } + return false; +} + +// check if input name has 7z or zip file, the name will link with extension +// return value: 0:zip; 1:7z; -1:none +int archiveCheck(char* name, int zipOnly) +{ + if (!name) + return ARC_NONE; + + static char archiveName[MAX_PATH] = ""; + int ret = ARC_NONE; + + // try zip first + sprintf(archiveName, "%s.zip", name); + + static File_Extractor* fex_scan = NULL; + static fex_err_t err_scan = NULL; + + err_scan = fex_open(&fex_scan, archiveName); + + if (!error(err_scan)) { + ret = ARC_ZIP; + strcat(name, ".zip"); + } else { + if (!zipOnly) { + // try 7z + sprintf(archiveName, "%s.7z", name); + + err_scan = fex_open(&fex_scan, archiveName); + if (!error(err_scan)) { + ret = ARC_7Z; + strcat(name, ".7z"); + } + } + } + + if (fex_scan) { + fex_close(fex_scan); + fex_scan = NULL; + } + + return ret; +} + +int archiveOpen(const char* archive) +{ + if (!archive) + return 1; + + err = fex_open(&fex, archive); + + if (error(err)) + return 1; + + nCurrFile = 0; + return 0; +} + +int archiveClose() +{ + if (fex) { + fex_close(fex); + fex = NULL; + } + return 0; +} + +// Get the contents of a archive file into an array of ArcEntry +int archiveGetList(ArcEntry** list, int* count) +{ + if (!fex || !list) + return 1; + + int nListLen = 0; + + while (!fex_done(fex)) + { + err = fex_next(fex); + if (error(err)) + { + archiveClose(); + return 1; + } + nListLen++; + } + + // Make an array of File Entries + if (nListLen == 0) + { + archiveClose(); + return 1; + } + + ArcEntry* List = (struct ArcEntry *)malloc(nListLen * sizeof(struct ArcEntry)); + + if (List == NULL) + { + archiveClose(); + return 1; + } + memset(List, 0, nListLen * sizeof(ArcEntry)); + + err = fex_rewind(fex); + + if (error(err)) + { + archiveClose(); + return 1; + } + + // Step through all of the files, until we get to the end + for (nCurrFile = 0, err = NULL; + nCurrFile < nListLen && !error(err); + nCurrFile++, err = fex_next(fex)) + { + fex_stat(fex); + + // Allocate space for the filename + const char* name = fex_name(fex); + if (name == NULL) continue; + char* szName = (char *)malloc(strlen(name) + 1); + if (szName == NULL) continue; + strcpy(szName, name); + + List[nCurrFile].szName = szName; + List[nCurrFile].nLen = fex_size(fex); + List[nCurrFile].nCrc = fex_crc32(fex); + } + + // return the file list + *list = List; + + if (count) + *count = nListLen; + + err = fex_rewind(fex); + + if (error(err)) + { + archiveClose(); + return 1; + } + + nCurrFile = 0; + return 0; +} + +int archiveLoadFile(uint8_t* dest, int nLen, int nEntry, int* wrote) +{ + if (!fex || nLen <= 0) + return 1; + + // if (nEntry < nCurrFile) + { + err = fex_rewind(fex); + + if (error(err)) + return 1; + + nCurrFile = 0; + } + + // Now step through to the file we need + while (nCurrFile < nEntry) + { + err = fex_next(fex); + + if (error(err) || fex_done(fex)) + return 1; + + nCurrFile++; + } + + err = fex_read(fex, dest, nLen); + + if (error(err)) + return 1; + + if (wrote != NULL) + *wrote = nLen; + + return 0; +} + +int archiveLoadOneFile(const char* arc, const char* file, void** dest, int* wrote) +{ + File_Extractor* fex_one = NULL; + fex_err_t err_one = fex_open(&fex_one, arc); + + if (error(err_one)) + return 1; + + int nListLen = 0; + while (!fex_done(fex_one)) + { + err_one = fex_next(fex_one); + if (error(err_one)) + { + fex_close(fex_one); + return 1; + } + nListLen++; + } + + if (nListLen <= 0) + { + fex_close(fex_one); + return 1; + } + + err_one = fex_rewind(fex_one); + if (error(err_one)) + { + fex_close(fex_one); + return 1; + } + + if (file) { + const char* filename = file; + int currentFile = 0; + + for (currentFile = 0, err_one = NULL; + currentFile < nListLen && !error(err_one); + currentFile++, err_one = fex_next(fex_one)) + { + fex_stat(fex_one); + + const char* name = fex_name(fex_one); + if (name == NULL) + continue; + if (!strcmp(name, filename)) + break; + } + + if (currentFile == nListLen) + { + fex_close(fex_one); + return 1; // didn't find + } + } + + fex_stat(fex_one); + long len = fex_size(fex_one); + + if (*dest == NULL) + { + *dest = (unsigned char*)malloc(len); + if (!*dest) + { + fex_close(fex_one); + return 1; + } + } + + // Extract file + err_one = fex_read(fex_one, *dest, len); + if (wrote != NULL) *wrote = len; + + fex_close(fex_one); + + if (error(err_one)) + { + free(*dest); + return 1; + } + return 0; +} diff --git a/src/burner/libsnes/archive.h b/src/burner/libsnes/archive.h new file mode 100644 index 000000000..d3a659312 --- /dev/null +++ b/src/burner/libsnes/archive.h @@ -0,0 +1,18 @@ +#ifndef ARCHIVE_H__ +#define ARCHIVE_H__ + +#include +#include + +struct ArcEntry { char* szName; unsigned int nLen; unsigned int nCrc; }; + +enum ARCTYPE { ARC_NONE = -1, ARC_ZIP = 0, ARC_7Z, ARC_NUM }; + +int archiveCheck(char* name, int zipOnly = 0); +int archiveOpen(const char* archive); +int archiveClose(); +int archiveGetList(ArcEntry** list, int* count = NULL); +int archiveLoadFile(uint8_t* dest, int len, int entry, int* wrote = NULL); + +#endif + diff --git a/src/burner/libsnes/libsnes.cpp b/src/burner/libsnes/libsnes.cpp new file mode 100644 index 000000000..11487630b --- /dev/null +++ b/src/burner/libsnes/libsnes.cpp @@ -0,0 +1,932 @@ +#include "libsnes.hpp" +#include "archive.h" +#include "burner.h" +#include "inp_keys.h" +#include "state.h" +#include +#include + +#include +#include +#include + +// FBA cruft. + +unsigned ArcadeJoystick; + +int bDrvOkay; +int bRunPause; +bool bAlwaysProcessKeyboardInput; + +struct ROMFIND +{ + unsigned int nState; + int nArchive; + int nPos; +}; + +unsigned int BurnDrvGetIndexByName(const char* name); +int BurnDrvGetArchiveName(char** pszName, unsigned int i, bool ext, unsigned int type); + +#define STAT_NOFIND 0 +#define STAT_OK 1 +#define STAT_CRC 2 +#define STAT_SMALL 3 +#define STAT_LARGE 4 + +static std::vector g_find_list_path; +static ROMFIND g_find_list[1024]; +static unsigned g_rom_count; + +#define AUDIO_SEGMENT_LENGTH 534 // <-- Hardcoded value that corresponds well to 32kHz audio. +#define AUDIO_SEGMENT_LENGTH_TIMES_CHANNELS (534 * 2) + +static uint16_t g_fba_frame[1024 * 1024]; +static uint16_t g_fba_frame_conv[1024 * 1024]; +static int16_t g_audio_buf[AUDIO_SEGMENT_LENGTH_TIMES_CHANNELS]; + +// libsnes globals + +static snes_video_refresh_t video_cb; +static snes_audio_sample_t audio_cb; +static snes_input_poll_t poll_cb; +static snes_input_state_t input_cb; +void snes_set_video_refresh(snes_video_refresh_t cb) { video_cb = cb; } +void snes_set_audio_sample(snes_audio_sample_t cb) { audio_cb = cb; } +void snes_set_input_poll(snes_input_poll_t cb) { poll_cb = cb; } +void snes_set_input_state(snes_input_state_t cb) { input_cb = cb; } + +// SSNES extension. +static snes_environment_t environ_cb; +void snes_set_environment(snes_environment_t cb) { environ_cb = cb; } + +static char g_rom_name[1024]; +static char g_rom_dir[1024]; +static char g_basename[1024]; + +///// +static void poll_input(); +static bool init_input(); + +// FBA stubs +TCHAR szAppHiscorePath[MAX_PATH]; +TCHAR szAppSamplesPath[MAX_PATH]; +TCHAR szAppBurnVer[16]; + +CDEmuStatusValue CDEmuStatus; + +const char* isowavLBAToMSF(const int LBA) { return ""; } +int isowavMSFToLBA(const char* address) { return 0; } +TCHAR* GetIsoPath() { return NULL; } +INT32 CDEmuInit() { return 0; } +INT32 CDEmuExit() { return 0; } +INT32 CDEmuStop() { return 0; } +INT32 CDEmuPlay(UINT8 M, UINT8 S, UINT8 F) { return 0; } +INT32 CDEmuLoadSector(INT32 LBA, char* pBuffer) { return 0; } +UINT8* CDEmuReadTOC(INT32 track) { return 0; } +UINT8* CDEmuReadQChannel() { return 0; } +INT32 CDEmuGetSoundBuffer(INT16* buffer, INT32 samples) { return 0; } +void InpDIPSWResetDIPs (void) {} +int InputSetCooperativeLevel(const bool bExclusive, const bool bForeGround) { return 0; } +void Reinitialise(void) {} + +// Non-idiomatic (OutString should be to the left to match strcpy()) +// Seems broken to not check nOutSize. +char* TCHARToANSI(const TCHAR* pszInString, char* pszOutString, int /*nOutSize*/) +{ + if (pszOutString) + { + strcpy(pszOutString, pszInString); + return pszOutString; + } + + return (char*)pszInString; +} + +int QuoteRead(char **, char **, char*) { return 1; } +char *LabelCheck(char *, char *) { return 0; } +const int nConfigMinVersion = 0x020921; +////////////// + +static int find_rom_by_crc(unsigned crc, const ArcEntry *list, unsigned elems) +{ + for (unsigned i = 0; i < elems; i++) + { + if (list[i].nCrc == crc) + return i; + } + + return -1; +} + +static void free_archive_list(ArcEntry *list, unsigned count) +{ + if (list) + { + for (unsigned i = 0; i < count; i++) + free(list[i].szName); + free(list); + } +} + +static int archive_load_rom(uint8_t *dest, int *wrote, int i) +{ + if (i < 0 || i >= g_rom_count) + return 1; + + int archive = g_find_list[i].nArchive; + + if (archiveOpen(g_find_list_path[archive].c_str())) + return 1; + + BurnRomInfo ri = {0}; + BurnDrvGetRomInfo(&ri, i); + + if (archiveLoadFile(dest, ri.nLen, g_find_list[i].nPos, wrote)) + { + archiveClose(); + return 1; + } + + archiveClose(); + return 0; +} + +// This code is very confusing. The original code is even more confusing :( +static bool open_archive() +{ + // FBA wants some roms ... Figure out how many. + g_rom_count = 0; + while (!BurnDrvGetRomInfo(0, g_rom_count)) + g_rom_count++; + + g_find_list_path.clear(); + + // Check if we have said archives. + // Check if archives are found. These are relative to g_rom_dir. + char *rom_name; + for (unsigned index = 0; index < 32; index++) + { + if (BurnDrvGetArchiveName(&rom_name, index, false, 0)) + continue; + + char path[1024]; + snprintf(path, sizeof(path), "%s/%s", g_rom_dir, rom_name); + + int ret = archiveCheck(path, 0); + if (ret == ARC_NONE) + continue; + + g_find_list_path.push_back(path); + } + + memset(g_find_list, 0, sizeof(g_find_list)); + + for (unsigned z = 0; z < g_find_list_path.size(); z++) + { + if (archiveOpen(g_find_list_path[z].c_str())) + continue; + + ArcEntry *list; + int count; + archiveGetList(&list, &count); + + // Try to map the ROMs FBA wants to ROMs we find inside our pretty archives ... + for (unsigned i = 0; i < g_rom_count; i++) + { + if (g_find_list[i].nState == STAT_OK) + continue; + + BurnRomInfo ri = {0}; + BurnDrvGetRomInfo(&ri, i); + + int index = find_rom_by_crc(ri.nCrc, list, count); + if (index < 0) + { + archiveClose(); + return false; + } + + // Yay, we found it! + g_find_list[i].nArchive = z; + g_find_list[i].nPos = index; + g_find_list[i].nState = STAT_OK; + + // Sanity checking ... + //if (!(ri.nType & BRF_OPT) && ri.nCrc) + // nTotalSize += ri.nLen; + + if (list[index].nLen == ri.nLen) + { + if (ri.nCrc && list[index].nCrc != ri.nCrc) + g_find_list[i].nState = STAT_CRC; + } + else if (list[index].nLen < ri.nLen) + g_find_list[i].nState = STAT_SMALL; + else if (list[index].nLen > ri.nLen) + g_find_list[i].nState = STAT_LARGE; + } + + + free_archive_list(list, count); + + archiveClose(); + } + + BurnExtLoadRom = archive_load_rom; + return true; +} + +void snes_init() +{ + BurnLibInit(); + + if (environ_cb) + { + bool need_fullpath = true; + environ_cb(SNES_ENVIRONMENT_SET_NEED_FULLPATH, &need_fullpath); + } +} + +void snes_term() +{ + BurnDrvExit(); + BurnLibExit(); +} + +static bool g_reset; +void snes_power() { g_reset = true; } +void snes_reset() { g_reset = true; } + +// Copy stuff :o +static inline void blit_regular(unsigned width, unsigned height, unsigned pitch) +{ + for (unsigned y = 0; y < height; y++) + { + memcpy(g_fba_frame_conv + y * 1024, + g_fba_frame + y * (pitch >> 1), + width * sizeof(uint16_t)); + } + + video_cb(g_fba_frame_conv, width, height); +} + +static inline void blit_flipped(unsigned width, unsigned height, unsigned pitch) +{ + for (unsigned y = 0; y < height; y++) + { + memcpy(g_fba_frame_conv + (height - 1 - y) * 1024, + g_fba_frame + y * (pitch >> 1), + width * sizeof(uint16_t)); + } + + video_cb(g_fba_frame_conv, width, height); +} + +static inline void blit_vertical(unsigned width, unsigned height, unsigned pitch) +{ + unsigned in_width = height; + unsigned in_height = width; + pitch >>= 1; + + // Flip y and x coords pretty much ... + for (unsigned y = 0; y < in_height; y++) + for (unsigned x = 0; x < in_width; x++) + g_fba_frame_conv[(height - x - 1) * 1024 + y] = g_fba_frame[y * pitch + x]; + + video_cb(g_fba_frame_conv, width, height); +} + +static inline void blit_vertical_flipped(unsigned width, unsigned height, unsigned pitch) +{ + unsigned in_width = height; + unsigned in_height = width; + pitch >>= 1; + + // Flip y and x coords pretty much ... + for (unsigned y = 0; y < in_height; y++) + for (unsigned x = 0; x < in_width; x++) + g_fba_frame_conv[x * 1024 + (width - 1 - y)] = g_fba_frame[y * pitch + x]; + + video_cb(g_fba_frame_conv, width, height); +} + +void snes_run() +{ + int width, height; + BurnDrvGetVisibleSize(&width, &height); + pBurnDraw = (uint8_t*)g_fba_frame; + + unsigned drv_flags = BurnDrvGetFlags(); + if (drv_flags & BDF_ORIENTATION_VERTICAL) + nBurnPitch = height * sizeof(uint16_t); + else + nBurnPitch = width * sizeof(uint16_t); + + nBurnLayer = 0xff; + pBurnSoundOut = g_audio_buf; + nBurnSoundRate = 32000; + nBurnSoundLen = AUDIO_SEGMENT_LENGTH; + nCurrentFrame++; + + poll_input(); + + BurnDrvFrame(); + + if ((drv_flags & (BDF_ORIENTATION_VERTICAL | BDF_ORIENTATION_FLIPPED)) == (BDF_ORIENTATION_VERTICAL | BDF_ORIENTATION_FLIPPED)) + blit_vertical_flipped(width, height, nBurnPitch); + else if (drv_flags & BDF_ORIENTATION_VERTICAL) + blit_vertical(width, height, nBurnPitch); + else if (drv_flags & BDF_ORIENTATION_FLIPPED) + blit_flipped(width, height, nBurnPitch); + else + blit_regular(width, height, nBurnPitch); + + for (unsigned i = 0; i < AUDIO_SEGMENT_LENGTH_TIMES_CHANNELS; i += 2) + audio_cb(g_audio_buf[i + 0], g_audio_buf[i + 1]); +} + +static uint8_t *write_state_ptr; +static const uint8_t *read_state_ptr; +static unsigned state_size; + +static int burn_write_state_cb(BurnArea *pba) +{ + memcpy(write_state_ptr, pba->Data, pba->nLen); + write_state_ptr += pba->nLen; + return 0; +} + +static int burn_read_state_cb(BurnArea *pba) +{ + memcpy(pba->Data, read_state_ptr, pba->nLen); + read_state_ptr += pba->nLen; + return 0; +} + +static int burn_dummy_state_cb(BurnArea *pba) +{ + state_size += pba->nLen; +} + +unsigned snes_serialize_size() +{ + if (state_size) + return state_size; + + BurnAcb = burn_dummy_state_cb; + state_size = 0; + BurnAreaScan(ACB_VOLATILE | ACB_WRITE, 0); + return state_size; +} + +bool snes_serialize(uint8_t *data, unsigned size) +{ + if (size != state_size) + return false; + + BurnAcb = burn_write_state_cb; + write_state_ptr = data; + BurnAreaScan(ACB_VOLATILE | ACB_WRITE, 0); + + return true; +} + +bool snes_unserialize(const uint8_t *data, unsigned size) +{ + if (size != state_size) + return false; + BurnAcb = burn_read_state_cb; + read_state_ptr = data; + BurnAreaScan(ACB_VOLATILE | ACB_READ, 0); + + return true; +} + +void snes_cheat_reset() {} +void snes_cheat_set(unsigned, bool, const char*) {} + +static bool fba_init(unsigned driver) +{ + nBurnDrvActive = driver; + + if (!open_archive()) + return false; + + nFMInterpolation = 3; + nInterpolation = 3; + + BurnDrvInit(); + + if (environ_cb) + { + int width, height; + BurnDrvGetVisibleSize(&width, &height); + snes_geometry geom = { width, height, width, height }; + environ_cb(SNES_ENVIRONMENT_SET_GEOMETRY, &geom); + + unsigned pitch = 2048; + environ_cb(SNES_ENVIRONMENT_SET_PITCH, &pitch); + } + + return true; +} + +static unsigned int HighCol15(int r, int g, int b, int /* i */) +{ + unsigned int t = 0; + t |= (r << 7) & 0x7c00; + t |= (g << 2) & 0x03e0; + t |= (b >> 3) & 0x001f; + return t; +} + +int VidRecalcPal() +{ + return BurnRecalcPal(); +} + +static void init_video() +{ + nBurnBpp = 2; + VidRecalcPal(); + BurnHighCol = HighCol15; +} + +static void init_audio() +{ + pBurnSoundOut = g_audio_buf; + nBurnSoundRate = 32000; + nBurnSoundLen = AUDIO_SEGMENT_LENGTH; +} + +// Infer paths from basename. +bool snes_load_cartridge_normal(const char*, const uint8_t *, unsigned) +{ + unsigned i = BurnDrvGetIndexByName(g_basename); + if (i < nBurnDrvCount) + { + init_video(); + init_audio(); + + if (!fba_init(i)) + return false; + + init_input(); + + return true; + } + else + return false; +} + +void snes_set_cartridge_basename(const char *basename) +{ + snprintf(g_rom_name, sizeof(g_rom_name), "%s.zip", basename); + strcpy(g_rom_dir, g_rom_name); + + char *split = strrchr(g_rom_dir, '/'); + if (!split) + split = strrchr(g_rom_dir, '\\'); + if (split) + *split = '\0'; + + if (split) + { + strcpy(g_basename, split + 1); + split = strrchr(g_basename, '.'); + if (split) + *split = '\0'; + } + + //fprintf(stderr, "PATH: %s\n", g_rom_name); + //fprintf(stderr, "DIR: %s\n", g_rom_dir); + //fprintf(stderr, "BASENAME: %s\n", g_basename); +} + +bool snes_load_cartridge_bsx_slotted( + const char*, const uint8_t*, unsigned, + const char*, const uint8_t*, unsigned +) +{ return false; } + +bool snes_load_cartridge_bsx( + const char*, const uint8_t *, unsigned, + const char*, const uint8_t *, unsigned +) +{ return false; } + +bool snes_load_cartridge_sufami_turbo( + const char*, const uint8_t*, unsigned, + const char*, const uint8_t*, unsigned, + const char*, const uint8_t*, unsigned +) +{ return false; } + +bool snes_load_cartridge_super_game_boy( + const char*, const uint8_t*, unsigned, + const char*, const uint8_t*, unsigned +) +{ return false; } + +void snes_unload_cartridge(void) {} + +bool snes_get_region() { return SNES_REGION_NTSC; } + +uint8_t *snes_get_memory_data(unsigned) { return 0; } +unsigned snes_get_memory_size(unsigned) { return 0; } + +unsigned snes_library_revision_major() { return 1; } +unsigned snes_library_revision_minor() { return 3; } + +const char *snes_library_id() { return "FBANext/libsnes"; } +void snes_set_controller_port_device(bool, unsigned) {} + +// Input stuff. + +// Ref GamcPlayer() in ../gamc.cpp +#define P1_COIN FBK_5 +#define P1_START FBK_1 +#define P1_LEFT FBK_LEFTARROW +#define P1_RIGHT FBK_RIGHTARROW +#define P1_UP FBK_UPARROW +#define P1_DOWN FBK_DOWNARROW +#define P1_FIRE1 FBK_A +#define P1_FIRE2 FBK_S +#define P1_FIRE3 FBK_D +#define P1_FIRE4 FBK_Z +#define P1_FIRE5 FBK_X +#define P1_FIRE6 FBK_C +#define P1_FIRED FBK_V +#define P1_SERVICE FBK_F2 + +#define P2_COIN 0x07 +#define P2_START 0x03 +#define P2_LEFT 0x4000 +#define P2_RIGHT 0x4001 +#define P2_UP 0x4002 +#define P2_DOWN 0x4003 +#define P2_FIRE1 0x4080 +#define P2_FIRE2 0x4081 +#define P2_FIRE3 0x4082 +#define P2_FIRE4 0x4083 +#define P2_FIRE5 0x4084 +#define P2_FIRE6 0x4085 +#define P2_FIRED 0x4086 + +#define P3_COIN 0x08 +#define P3_START 0x04 +#define P3_LEFT 0x4100 +#define P3_RIGHT 0x4101 +#define P3_UP 0x4102 +#define P3_DOWN 0x4103 +#define P3_FIRE1 0x4180 +#define P3_FIRE2 0x4181 +#define P3_FIRE3 0x4182 +#define P3_FIRE4 0x4183 +#define P3_FIRE5 0x4184 +#define P3_FIRE6 0x4185 + +#define P4_COIN 0x09 +#define P4_START 0x05 +#define P4_LEFT 0x4200 +#define P4_RIGHT 0x4201 +#define P4_UP 0x4202 +#define P4_DOWN 0x4203 +#define P4_FIRE1 0x4280 +#define P4_FIRE2 0x4281 +#define P4_FIRE3 0x4282 +#define P4_FIRE4 0x4283 +#define P4_FIRE5 0x4284 +#define P4_FIRE6 0x4285 + +static unsigned char keybinds[0x5000][2]; +#define _B(x) SNES_DEVICE_ID_JOYPAD_##x +#define RESET_BIND 12 +#define SERVICE_BIND 13 +static bool init_input() +{ + GameInpInit(); + GameInpDefault(); + + bool has_analog = false; + struct GameInp* pgi = GameInp; + for (unsigned i = 0; i < nGameInpCount; i++, pgi++) + { + if (pgi->nType == BIT_ANALOG_REL) + { + has_analog = true; + break; + } + } + + //needed for Neo Geo button mappings (and other drivers in future) + const char * boardrom = BurnDrvGetTextA(DRV_BOARDROM); + + // Bind to nothing. + for (unsigned i = 0; i < 0x5000; i++) + keybinds[i][0] = 0xff; + + // Reset + keybinds[FBK_F3 ][0] = RESET_BIND; + keybinds[FBK_F3 ][1] = 0; + keybinds[P1_SERVICE ][0] = SERVICE_BIND; + keybinds[P1_SERVICE ][1] = 0; + + keybinds[P1_COIN ][0] = _B(SELECT); + keybinds[P1_COIN ][1] = 0; + keybinds[P1_START ][0] = _B(START); + keybinds[P1_START ][1] = 0; + keybinds[P1_UP ][0] = _B(UP); + keybinds[P1_UP ][1] = 0; + keybinds[P1_DOWN ][0] = _B(DOWN); + keybinds[P1_DOWN ][1] = 0; + keybinds[P1_LEFT ][0] = _B(LEFT); + keybinds[P1_LEFT ][1] = 0; + keybinds[P1_RIGHT ][0] = _B(RIGHT); + keybinds[P1_RIGHT ][1] = 0; + keybinds[P1_FIRE1 ][0] = _B(Y); + keybinds[P1_FIRE1 ][1] = 0; + keybinds[P1_FIRE2 ][0] = _B(X); + keybinds[P1_FIRE2 ][1] = 0; + keybinds[P1_FIRE3 ][0] = _B(L); + keybinds[P1_FIRE3 ][1] = 0; + keybinds[P1_FIRE4 ][0] = _B(B); + keybinds[P1_FIRE4 ][1] = 0; + keybinds[P1_FIRE5 ][0] = _B(A); + keybinds[P1_FIRE5 ][1] = 0; + + if(boardrom && (strcmp(boardrom,"neogeo") == 0)) + { + keybinds[P1_FIRE6][0] = _B(Y); + keybinds[P1_FIRE6][1] = 0; + keybinds[P1_FIRED][0] = _B(X); + keybinds[P1_FIRED][1] = 0; + } + else + { + keybinds[P1_FIRE6 ][0] = _B(R); + keybinds[P1_FIRE6 ][1] = 0; + } +#if 0 + keybinds[0x88 ][0] = L2; + keybinds[0x88 ][1] = 0; + keybinds[0x8A ][0] = R2; + keybinds[0x8A ][1] = 0; + keybinds[0x3b ][0] = L3; + keybinds[0x3b ][1] = 0; + keybinds[0x21 ][0] = R2; + keybinds[0x21 ][1] = 0; +#endif + + keybinds[P2_COIN ][0] = _B(SELECT); + keybinds[P2_COIN ][1] = 1; + keybinds[P2_START ][0] = _B(START); + keybinds[P2_START ][1] = 1; + keybinds[P2_UP ][0] = _B(UP); + keybinds[P2_UP ][1] = 1; + keybinds[P2_DOWN ][0] = _B(DOWN); + keybinds[P2_DOWN ][1] = 1; + keybinds[P2_LEFT ][0] = _B(LEFT); + keybinds[P2_LEFT ][1] = 1; + keybinds[P2_RIGHT ][0] = _B(RIGHT); + keybinds[P2_RIGHT ][1] = 1; + keybinds[P2_FIRE1 ][0] = _B(Y); + + if (boardrom && (strcmp(boardrom, "neogeo") == 0)) + { + keybinds[P2_FIRE3][0] = _B(Y); + keybinds[P2_FIRE3][1] = 1; + keybinds[P2_FIRE4][0] = _B(X); + keybinds[P2_FIRE4][1] = 1; + keybinds[P2_FIRE1][0] = _B(B); + keybinds[P2_FIRE1][1] = 1; + keybinds[P2_FIRE2][0] = _B(A); + keybinds[P2_FIRE2][1] = 1; + } + else + { + keybinds[P2_FIRE1 ][1] = 1; + keybinds[P2_FIRE2 ][0] = _B(X); + keybinds[P2_FIRE2 ][1] = 1; + keybinds[P2_FIRE3 ][0] = _B(L); + keybinds[P2_FIRE3 ][1] = 1; + keybinds[P2_FIRE4 ][0] = _B(B); + keybinds[P2_FIRE4 ][1] = 1; + keybinds[P2_FIRE5 ][0] = _B(A); + keybinds[P2_FIRE5 ][1] = 1; + keybinds[P2_FIRE6 ][0] = _B(R); + keybinds[P2_FIRE6 ][1] = 1; + } + +#if 0 + keybinds[0x4088 ][0] = L2; + keybinds[0x4088 ][1] = 1; + keybinds[0x408A ][0] = R2; + keybinds[0x408A ][1] = 1; + keybinds[0x408b ][0] = L3; + keybinds[0x408b ][1] = 1; + keybinds[0x408c ][0] = R3; + keybinds[0x408c ][1] = 1; +#endif + + keybinds[P3_COIN ][0] = _B(SELECT); + keybinds[P3_COIN ][1] = 2; + keybinds[P3_START ][0] = _B(START); + keybinds[P3_START ][1] = 2; + keybinds[P3_UP ][0] = _B(UP); + keybinds[P3_UP ][1] = 2; + keybinds[P3_DOWN ][0] = _B(DOWN); + keybinds[P3_DOWN ][1] = 2; + keybinds[P3_LEFT ][0] = _B(LEFT); + keybinds[P3_LEFT ][1] = 2; + keybinds[P3_RIGHT ][0] = _B(RIGHT); + keybinds[P3_RIGHT ][1] = 2; + keybinds[P3_FIRE1 ][0] = _B(Y); + keybinds[P3_FIRE1 ][1] = 2; + keybinds[P3_FIRE2 ][0] = _B(X); + keybinds[P3_FIRE2 ][1] = 2; + keybinds[P3_FIRE3 ][0] = _B(L); + keybinds[P3_FIRE3 ][1] = 2; + keybinds[P3_FIRE4 ][0] = _B(B); + keybinds[P3_FIRE4 ][1] = 2; + keybinds[P3_FIRE5 ][0] = _B(A); + keybinds[P3_FIRE5 ][1] = 2; + keybinds[P3_FIRE6 ][0] = _B(R); + keybinds[P3_FIRE6 ][1] = 2; +#if 0 + keybinds[0x4188 ][0] = L2; + keybinds[0x4188 ][1] = 2; + keybinds[0x418A ][0] = R2; + keybinds[0x418A ][1] = 2; + keybinds[0x418b ][0] = L3; + keybinds[0x418b ][1] = 2; + keybinds[0x418c ][0] = R3; + keybinds[0x418c ][1] = 2; +#endif + + keybinds[P4_COIN ][0] = _B(SELECT); + keybinds[P4_COIN ][1] = 3; + keybinds[P4_START ][0] = _B(START); + keybinds[P4_START ][1] = 3; + keybinds[P4_UP ][0] = _B(UP); + keybinds[P4_UP ][1] = 3; + keybinds[P4_DOWN ][0] = _B(DOWN); + keybinds[P4_DOWN ][1] = 3; + keybinds[P4_LEFT ][0] = _B(LEFT); + keybinds[P4_LEFT ][1] = 3; + keybinds[P4_RIGHT ][0] = _B(RIGHT); + keybinds[P4_RIGHT ][1] = 3; + keybinds[P4_FIRE1 ][0] = _B(Y); + keybinds[P4_FIRE1 ][1] = 3; + keybinds[P4_FIRE2 ][0] = _B(X); + keybinds[P4_FIRE2 ][1] = 3; + keybinds[P4_FIRE3 ][0] = _B(L); + keybinds[P4_FIRE3 ][1] = 3; + keybinds[P4_FIRE4 ][0] = _B(B); + keybinds[P4_FIRE4 ][1] = 3; + keybinds[P4_FIRE5 ][0] = _B(A); + keybinds[P4_FIRE5 ][1] = 3; + keybinds[P4_FIRE6 ][0] = _B(R); + keybinds[P4_FIRE6 ][1] = 3; +#if 0 + keybinds[0x4288 ][0] = L2; + keybinds[0x4288 ][1] = 3; + keybinds[0x428A ][0] = R2; + keybinds[0x428A ][1] = 3; + keybinds[0x428b ][0] = L3; + keybinds[0x428b ][1] = 3; + keybinds[0x428c ][0] = R3; + keybinds[0x428c ][1] = 3; +#endif + + return has_analog; +} + +static void poll_input() +{ + poll_cb(); + + struct GameInp* pgi = GameInp; + unsigned controller_binds_count = nGameInpCount; + + for (int i = 0; i < controller_binds_count; i++, pgi++) + { + int nAdd = 0; + if ((pgi->nInput & GIT_GROUP_SLIDER) == 0) // not a slider + continue; + + if (pgi->nInput == GIT_KEYSLIDER) + { + // Get states of the two keys + if (input_cb(0, SNES_DEVICE_JOYPAD, 0, + keybinds[pgi->Input.Slider.SliderAxis.nSlider[0]][0])) + nAdd -= 0x100; + + if (input_cb(0, SNES_DEVICE_JOYPAD, 0, + keybinds[pgi->Input.Slider.SliderAxis.nSlider[1]][0])) + nAdd += 0x100; + } + + // nAdd is now -0x100 to +0x100 + + // Change to slider speed + nAdd *= pgi->Input.Slider.nSliderSpeed; + nAdd /= 0x100; + + if (pgi->Input.Slider.nSliderCenter) + { // Attact to center + int v = pgi->Input.Slider.nSliderValue - 0x8000; + v *= (pgi->Input.Slider.nSliderCenter - 1); + v /= pgi->Input.Slider.nSliderCenter; + v += 0x8000; + pgi->Input.Slider.nSliderValue = v; + } + + pgi->Input.Slider.nSliderValue += nAdd; + // Limit slider + if (pgi->Input.Slider.nSliderValue < 0x0100) + pgi->Input.Slider.nSliderValue = 0x0100; + if (pgi->Input.Slider.nSliderValue > 0xFF00) + pgi->Input.Slider.nSliderValue = 0xFF00; + } + + pgi = GameInp; + + for (unsigned i = 0; i < controller_binds_count; i++, pgi++) + { + switch (pgi->nInput) + { + case GIT_CONSTANT: // Constant value + pgi->Input.nVal = pgi->Input.Constant.nConst; + *(pgi->Input.pVal) = pgi->Input.nVal; + break; + case GIT_SWITCH: + { + // Digital input + unsigned id = keybinds[pgi->Input.Switch.nCode][0]; + unsigned port = keybinds[pgi->Input.Switch.nCode][1]; + + bool state; + if (id == RESET_BIND) + { + state = g_reset; + g_reset = false; + } + else if (id == SERVICE_BIND) + { + state = + input_cb(0, SNES_DEVICE_JOYPAD, 0, _B(START)) && + input_cb(0, SNES_DEVICE_JOYPAD, 0, _B(SELECT)) && + input_cb(0, SNES_DEVICE_JOYPAD, 0, _B(L)) && + input_cb(0, SNES_DEVICE_JOYPAD, 0, _B(R)); + } + else if (port < 2) + state = input_cb(port, SNES_DEVICE_JOYPAD, 0, id); + else + state = input_cb(true, SNES_DEVICE_MULTITAP, port - 1, id); + + if (pgi->nType & BIT_GROUP_ANALOG) + { + // Set analog controls to full + if (state) + pgi->Input.nVal = 0xFFFF; + else + pgi->Input.nVal = 0x0001; +#ifdef LSB_FIRST + *(pgi->Input.pShortVal) = pgi->Input.nVal; +#else + *((int *)pgi->Input.pShortVal) = pgi->Input.nVal; +#endif + } + else + { + // Binary controls + if (state) + pgi->Input.nVal = 1; + else + pgi->Input.nVal = 0; + *(pgi->Input.pVal) = pgi->Input.nVal; + } + break; + } + case GIT_KEYSLIDER: // Keyboard slider + { + int nSlider = pgi->Input.Slider.nSliderValue; + if (pgi->nType == BIT_ANALOG_REL) { + nSlider -= 0x8000; + nSlider >>= 4; + } + + pgi->Input.nVal = (unsigned short)nSlider; +#ifdef LSB_FIRST + *(pgi->Input.pShortVal) = pgi->Input.nVal; +#else + *((int *)pgi->Input.pShortVal) = pgi->Input.nVal; +#endif + break; + } + } + } +} + diff --git a/src/burner/libsnes/libsnes.hpp b/src/burner/libsnes/libsnes.hpp new file mode 100644 index 000000000..6fb0a1aa5 --- /dev/null +++ b/src/burner/libsnes/libsnes.hpp @@ -0,0 +1,186 @@ +#ifndef LIBSNES_HPP +#define LIBSNES_HPP + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define SNES_PORT_1 0 +#define SNES_PORT_2 1 + +#define SNES_DEVICE_NONE 0 +#define SNES_DEVICE_JOYPAD 1 +#define SNES_DEVICE_MULTITAP 2 +#define SNES_DEVICE_MOUSE 3 +#define SNES_DEVICE_SUPER_SCOPE 4 +#define SNES_DEVICE_JUSTIFIER 5 +#define SNES_DEVICE_JUSTIFIERS 6 +#define SNES_DEVICE_SERIAL_CABLE 7 + +#define SNES_DEVICE_ID_JOYPAD_B 0 +#define SNES_DEVICE_ID_JOYPAD_Y 1 +#define SNES_DEVICE_ID_JOYPAD_SELECT 2 +#define SNES_DEVICE_ID_JOYPAD_START 3 +#define SNES_DEVICE_ID_JOYPAD_UP 4 +#define SNES_DEVICE_ID_JOYPAD_DOWN 5 +#define SNES_DEVICE_ID_JOYPAD_LEFT 6 +#define SNES_DEVICE_ID_JOYPAD_RIGHT 7 +#define SNES_DEVICE_ID_JOYPAD_A 8 +#define SNES_DEVICE_ID_JOYPAD_X 9 +#define SNES_DEVICE_ID_JOYPAD_L 10 +#define SNES_DEVICE_ID_JOYPAD_R 11 + +#define SNES_DEVICE_ID_MOUSE_X 0 +#define SNES_DEVICE_ID_MOUSE_Y 1 +#define SNES_DEVICE_ID_MOUSE_LEFT 2 +#define SNES_DEVICE_ID_MOUSE_RIGHT 3 + +#define SNES_DEVICE_ID_SUPER_SCOPE_X 0 +#define SNES_DEVICE_ID_SUPER_SCOPE_Y 1 +#define SNES_DEVICE_ID_SUPER_SCOPE_TRIGGER 2 +#define SNES_DEVICE_ID_SUPER_SCOPE_CURSOR 3 +#define SNES_DEVICE_ID_SUPER_SCOPE_TURBO 4 +#define SNES_DEVICE_ID_SUPER_SCOPE_PAUSE 5 + +#define SNES_DEVICE_ID_JUSTIFIER_X 0 +#define SNES_DEVICE_ID_JUSTIFIER_Y 1 +#define SNES_DEVICE_ID_JUSTIFIER_TRIGGER 2 +#define SNES_DEVICE_ID_JUSTIFIER_START 3 + +#define SNES_REGION_NTSC 0 +#define SNES_REGION_PAL 1 + +#define SNES_MEMORY_CARTRIDGE_RAM 0 +#define SNES_MEMORY_CARTRIDGE_RTC 1 +#define SNES_MEMORY_BSX_RAM 2 +#define SNES_MEMORY_BSX_PRAM 3 +#define SNES_MEMORY_SUFAMI_TURBO_A_RAM 4 +#define SNES_MEMORY_SUFAMI_TURBO_B_RAM 5 +#define SNES_MEMORY_GAME_BOY_RAM 6 +#define SNES_MEMORY_GAME_BOY_RTC 7 + +#define SNES_MEMORY_WRAM 100 +#define SNES_MEMORY_APURAM 101 +#define SNES_MEMORY_VRAM 102 +#define SNES_MEMORY_OAM 103 +#define SNES_MEMORY_CGRAM 104 + +// SSNES extension. Not required to be implemented for a working implementation. + +#define SNES_ENVIRONMENT_GET_FULLPATH 0 // const char ** -- + // Full path of game loaded. + // +#define SNES_ENVIRONMENT_SET_GEOMETRY 1 // const struct snes_geometry * -- + // Window geometry information for the system/game. + // +#define SNES_ENVIRONMENT_SET_PITCH 2 // const unsigned * -- + // Pitch of game image. + // +#define SNES_ENVIRONMENT_GET_OVERSCAN 3 // bool * -- + // Boolean value whether or not the implementation should use overscan. + // +#define SNES_ENVIRONMENT_SET_TIMING 4 // const struct snes_system_timing * -- + // Set exact timings of the system. Used primarily for video recording. + // +#define SNES_ENVIRONMENT_GET_CAN_DUPE 5 // bool * -- + // Boolean value whether or not SSNES supports frame duping, + // passing NULL to video frame callback. + // + // +#define SNES_ENVIRONMENT_SET_NEED_FULLPATH 6 // const bool * -- + // Boolean value telling if implementation needs a valid fullpath to be able to run. + // If this is the case, SSNES will not open the rom directly, + // and pass NULL to rom data. + // Implementation must then use SNES_ENVIRONMENT_GET_FULLPATH. + // This is useful for implementations with very large roms, + // which are impractical to load fully into RAM. + +struct snes_geometry +{ + unsigned base_width; // Nominal video width of system. + unsigned base_height; // Nominal video height of system. + unsigned max_width; // Maximum possible width of system. + unsigned max_height; // Maximum possible height of system. +}; + +struct snes_system_timing +{ + double fps; + double sample_rate; +}; + +typedef bool (*snes_environment_t)(unsigned cmd, void *data); + +// Must be called before calling snes_init(). +void snes_set_environment(snes_environment_t); +//// + + +typedef void (*snes_video_refresh_t)(const uint16_t *data, unsigned width, unsigned height); +typedef void (*snes_audio_sample_t)(uint16_t left, uint16_t right); +typedef void (*snes_input_poll_t)(void); +typedef int16_t (*snes_input_state_t)(bool port, unsigned device, unsigned index, unsigned id); + +const char* snes_library_id(void); +unsigned snes_library_revision_major(void); +unsigned snes_library_revision_minor(void); + +void snes_set_video_refresh(snes_video_refresh_t); +void snes_set_audio_sample(snes_audio_sample_t); +void snes_set_input_poll(snes_input_poll_t); +void snes_set_input_state(snes_input_state_t); + +void snes_set_controller_port_device(bool port, unsigned device); +void snes_set_cartridge_basename(const char *basename); + +void snes_init(void); +void snes_term(void); +void snes_power(void); +void snes_reset(void); +void snes_run(void); + +unsigned snes_serialize_size(void); +bool snes_serialize(uint8_t *data, unsigned size); +bool snes_unserialize(const uint8_t *data, unsigned size); + +void snes_cheat_reset(void); +void snes_cheat_set(unsigned index, bool enabled, const char *code); + +bool snes_load_cartridge_normal( + const char *rom_xml, const uint8_t *rom_data, unsigned rom_size +); + +bool snes_load_cartridge_bsx_slotted( + const char *rom_xml, const uint8_t *rom_data, unsigned rom_size, + const char *bsx_xml, const uint8_t *bsx_data, unsigned bsx_size +); + +bool snes_load_cartridge_bsx( + const char *rom_xml, const uint8_t *rom_data, unsigned rom_size, + const char *bsx_xml, const uint8_t *bsx_data, unsigned bsx_size +); + +bool snes_load_cartridge_sufami_turbo( + const char *rom_xml, const uint8_t *rom_data, unsigned rom_size, + const char *sta_xml, const uint8_t *sta_data, unsigned sta_size, + const char *stb_xml, const uint8_t *stb_data, unsigned stb_size +); + +bool snes_load_cartridge_super_game_boy( + const char *rom_xml, const uint8_t *rom_data, unsigned rom_size, + const char *dmg_xml, const uint8_t *dmg_data, unsigned dmg_size +); + +void snes_unload_cartridge(void); + +bool snes_get_region(void); +uint8_t* snes_get_memory_data(unsigned id); +unsigned snes_get_memory_size(unsigned id); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/burner/libsnes/link.T b/src/burner/libsnes/link.T new file mode 100644 index 000000000..33a0e38bb --- /dev/null +++ b/src/burner/libsnes/link.T @@ -0,0 +1,5 @@ +{ + global: snes_*; + local: *; +}; + diff --git a/src/burner/libsnes/net.h b/src/burner/libsnes/net.h new file mode 100644 index 000000000..e69de29bb diff --git a/src/burner/libsnes/tchar.h b/src/burner/libsnes/tchar.h new file mode 100644 index 000000000..76bb21d15 --- /dev/null +++ b/src/burner/libsnes/tchar.h @@ -0,0 +1,56 @@ +#ifndef __PORT_TYPEDEFS_H +#define __PORT_TYPEDEFS_H + +#include +#include + +#include "inp_keys.h" + +#define TCHAR char +#undef __cdecl +#define __cdecl + +#define bprintf(...) {} +#define _strnicmp(s1, s2, n) strncasecmp(s1, s2, n) +#define _stricmp(x, y) strcasecmp(x,y) +#define _T(x) x +#define _tcstol strtol +#define _tfopen fopen +#define _fgetts fgets +#define _tcslen strlen +#define _stprintf sprintf +#define _istspace(x) isspace(x) +#define _tcsncmp strncmp +#define _tcsncpy strncpy +#define _tcsstr strstr +#define _stscanf sscanf +#define _ftprintf fprintf +#define _tcsicmp(a, b) strcasecmp(a, b) +#define _tcscpy(to, from) strcpy(to, from) +/*define lstrlen what does lstrlen correspond to?*/ + +#undef __fastcall +#undef _fastcall +#define __fastcall /*what does this correspond to?*/ +#define _fastcall /*same as above - what does this correspond to?*/ +#define ANSIToTCHAR(str, foo, bar) (str) + +/* for Windows / Xbox 360 (below VS2010) - typedefs for missing stdint.h types such as uintptr_t?*/ + +/*FBA defines*/ +#define PUF_TEXT_NO_TRANSLATE (0) +#define PUF_TYPE_ERROR (1) + +extern TCHAR szAppBurnVer[16]; + +typedef int HWND; + +extern int bDrvOkay; +extern int bRunPause; +extern bool bAlwaysProcessKeyboardInput; +extern HWND hScrnWnd; // Handle to the screen window + +extern void InpDIPSWResetDIPs (void); + + +#endif