diff --git a/CMakeLists.txt b/CMakeLists.txt index 442bb30a..b464b8ff 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -12,6 +12,9 @@ MESSAGE("CMAKE_CXX_FLAGS_RELEASE: ${CMAKE_CXX_FLAGS_RELEASE}") MESSAGE("CMAKE_CXX_FLAGS_DEBUG: ${CMAKE_CXX_FLAGS_DEBUG}") MESSAGE("CMAKE_CXX_FLAGS_RELWITHDEBINFO: ${CMAKE_CXX_FLAGS_RELWITHDEBINFO}") +# this only affects common2, the others are already build with fPIC by default +set(CMAKE_POSITION_INDEPENDENT_CODE ON) + set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}) execute_process(COMMAND uname -n @@ -35,4 +38,5 @@ add_subdirectory(source/frontends/common2) add_subdirectory(source/frontends/ncurses) add_subdirectory(source/frontends/qapple) add_subdirectory(source/frontends/sa2) +add_subdirectory(source/frontends/retro) add_subdirectory(test/TestCPU6502) diff --git a/linux.md b/linux.md index ea7a2bc4..4afe0ea3 100644 --- a/linux.md +++ b/linux.md @@ -6,6 +6,7 @@ * [applen](#applen) * [qapple](#qapple) * [sa2](#sa2) + * [libretro](#ra2) * [Build](#build) * [Checkout](#checkout) * [Fedora](#fedora) @@ -88,6 +89,20 @@ This is based on Qt, currently tested with 5.10 See [sa2](source/frontends/sa2/README.md). +### ra2 + +There is an initial [libretro](https://docs.libretro.com/development/cores/developing-cores/) core. + +Keyboard works, but a lot of keys overlap with RetroArch shortcuts. + +Video works, but the vertical flip is done in software. + +Must be manually configured: +``cmake -DLIBRETRO_PATH=/path/to/libretro-common`` + +Easiest way to run from the ``build`` folder: +``retroarch -L source/frontends/retro/libra2.so ../Disks/NoSlotClockTest.dsk`` + ## Build The project can be built using cmake from the top level directory. diff --git a/source/frontends/common2/CMakeLists.txt b/source/frontends/common2/CMakeLists.txt index 434177cb..5f705e16 100644 --- a/source/frontends/common2/CMakeLists.txt +++ b/source/frontends/common2/CMakeLists.txt @@ -18,7 +18,7 @@ target_include_directories(common2 PRIVATE ${Boost_INCLUDE_DIRS} ) -target_link_libraries(common2 PRIVATE +target_link_libraries(common2 PUBLIC Boost::program_options ) diff --git a/source/frontends/common2/config.h.in b/source/frontends/common2/config.h.in index d074ea8d..ffe5c851 100644 --- a/source/frontends/common2/config.h.in +++ b/source/frontends/common2/config.h.in @@ -1,3 +1,6 @@ // relative path from executable to resources #cmakedefine ROOT_PATH "@ROOT_PATH@" #cmakedefine SHARE_PATH "@SHARE_PATH@" + +// this one is a bit of a hack, until resources are embedded in the retro core +#cmakedefine CMAKE_SOURCE_DIR "@CMAKE_SOURCE_DIR@" diff --git a/source/frontends/common2/resources.cpp b/source/frontends/common2/resources.cpp index a2b7699c..325a26e8 100644 --- a/source/frontends/common2/resources.cpp +++ b/source/frontends/common2/resources.cpp @@ -27,6 +27,8 @@ namespace std::string getResourcePathImpl() { + std::vector paths; + char self[1024] = {0}; const int ch = readlink("/proc/self/exe", self, sizeof(self)); if (ch != -1) @@ -34,21 +36,24 @@ namespace const char * path = dirname(self); // case 1: run from the build folder - const std::string path1 = std::string(path) + '/'+ ROOT_PATH + "/resource/"; - if (dirExists(path1)) - { - return path1; - } - + paths.emplace_back(std::string(path) + '/'+ ROOT_PATH); // case 2: run from the installation folder - const std::string path2 = std::string(path) + '/'+ SHARE_PATH + "/resource/"; - if (dirExists(path2)) + paths.emplace_back(std::string(path) + '/'+ SHARE_PATH); + } + + // case 3: use the source folder + paths.emplace_back(CMAKE_SOURCE_DIR); + + for (const std::string & path : paths) + { + const std::string resourcePath = path + "/resource/"; + if (dirExists(resourcePath)) { - return path2; + return resourcePath; } } - // else? - return std::string(); + + throw std::runtime_error("Cannot found the resource path"); } } diff --git a/source/frontends/retro/CMakeLists.txt b/source/frontends/retro/CMakeLists.txt new file mode 100644 index 00000000..c2cf3072 --- /dev/null +++ b/source/frontends/retro/CMakeLists.txt @@ -0,0 +1,27 @@ +# there is no simple package for libretro-common +# this requires user input +set(LIBRETRO_PATH NONE CACHE PATH "path to libretro-common") + +if (IS_DIRECTORY ${LIBRETRO_PATH}) + message("Using LIBRETRO_PATH=${LIBRETRO_PATH}") + + add_library(ra2 SHARED + environment.cpp + libretro.cpp + bitmaps.cpp + rdirectsound.cpp + interface.cpp + game.cpp + ) + + target_include_directories(ra2 PRIVATE + ${LIBRETRO_PATH}/include + ) + + target_link_libraries(ra2 PRIVATE + appleii + common2 + ) +else() + message("Bad LIBRETRO_PATH=${LIBRETRO_PATH}, skipping libretro code") +endif() diff --git a/source/frontends/retro/bitmaps.cpp b/source/frontends/retro/bitmaps.cpp new file mode 100644 index 00000000..5499cbc4 --- /dev/null +++ b/source/frontends/retro/bitmaps.cpp @@ -0,0 +1,151 @@ +#include "frontends/retro/environment.h" + +#include +#include +#include + +#include +#include + +namespace +{ + + void readFileToBuffer(const std::string & filename, std::vector & buffer) + { + std::ifstream file(filename.c_str(), std::ios::binary | std::ios::ate); + const std::streamsize size = file.tellg(); + file.seekg(0, std::ios::beg); + + buffer.resize(size); + file.read(buffer.data(), size); + } + + template + T getAs(const std::vector & buffer, const size_t offset) + { + if (offset + sizeof(T) > buffer.size()) + { + throw std::runtime_error("Invalid bitmap"); + } + const T * ptr = reinterpret_cast(buffer.data() + offset); + return * ptr; + } + + // libretro cannot parse BMP with 1 bpp + // simple version implemented here + bool getBitmapData(const std::vector & buffer, int32_t & width, int32_t & height, uint16_t & bpp, const char * & data, uint32_t & size) + { + if (buffer.size() < 2) + { + return false; + } + + if (buffer[0] != 0x42 || buffer[1] != 0x4D) + { + return false; + } + + const uint32_t fileSize = getAs(buffer, 2); + if (fileSize != buffer.size()) + { + return false; + } + + const uint32_t offset = getAs(buffer, 10); + const uint32_t header = getAs(buffer, 14); + if (header != 40) + { + return false; + } + + width = getAs(buffer, 18); + height = getAs(buffer, 22); + bpp = getAs(buffer, 28); + const uint32_t imageSize = getAs(buffer, 34); + if (offset + imageSize > fileSize) + { + return false; + } + data = buffer.data() + offset; + size = imageSize; + return true; + } + +} + +struct CBITMAP : public CHANDLE +{ + std::vector image; +}; + +std::string getFilename(const std::string & resource) +{ + if (resource == "CHARSET40") return "CHARSET4.BMP"; + if (resource == "CHARSET82") return "CHARSET82.bmp"; + if (resource == "CHARSET8M") return "CHARSET8M.bmp"; + if (resource == "CHARSET8C") return "CHARSET8C.bmp"; + + return resource; +} + +HBITMAP LoadBitmap(HINSTANCE hInstance, const char * resource) +{ + if (resource) + { + const std::string filename = getFilename(resource); + const std::string path = getResourcePath() + filename; + + std::vector buffer; + readFileToBuffer(path, buffer); + + if (!buffer.empty()) + { + int32_t width, height; + uint16_t bpp; + const char * data; + uint32_t size; + const bool res = getBitmapData(buffer, width, height, bpp, data, size); + + log_cb(RETRO_LOG_INFO, "RA2: %s. %s = %dx%d, %dbpp\n", __FUNCTION__, path.c_str(), + width, height, bpp); + + if (res && height > 0) + { + CBITMAP * bitmap = new CBITMAP; + bitmap->image.resize(size); + const size_t length = size / height; + // rows are stored upside down + for (size_t row = 0; row < height; ++row) + { + const char * src = data + row * length; + char * dst = bitmap->image.data() + (height - row - 1) * length; + memcpy(dst, src, length); + } + return bitmap; + } + } + else + { + log_cb(RETRO_LOG_INFO, "RA2: %s. Cannot load: %s with path: %s\n", __FUNCTION__, resource, path.c_str()); + return nullptr; + } + } + + log_cb(RETRO_LOG_INFO, "RA2: %s. Cannot load invaid resource\n", __FUNCTION__); + return nullptr; +} + +LONG GetBitmapBits(HBITMAP hbit, LONG cb, LPVOID lpvBits) +{ + const CBITMAP & bitmap = dynamic_cast(*hbit); + const char * bits = bitmap.image.data(); + const size_t size = bitmap.image.size(); + const size_t requested = cb; + + const size_t copied = std::min(requested, size); + + char * dest = static_cast(lpvBits); + memcpy(dest, bits, copied); + + return copied; +} diff --git a/source/frontends/retro/environment.cpp b/source/frontends/retro/environment.cpp new file mode 100644 index 00000000..1355b256 --- /dev/null +++ b/source/frontends/retro/environment.cpp @@ -0,0 +1,28 @@ +#include "frontends/retro/environment.h" + +#include +#include + + +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); +} + +retro_log_callback logging; +retro_log_printf_t log_cb = fallback_log; +retro_input_poll_t input_poll_cb; +retro_input_state_t input_state_cb; + +retro_environment_t environ_cb; +retro_video_refresh_t video_cb; +retro_audio_sample_t audio_cb; +retro_audio_sample_batch_t audio_batch_cb; + +std::string retro_base_directory; + +unsigned int retro_devices[RETRO_DEVICES] = {}; diff --git a/source/frontends/retro/environment.h b/source/frontends/retro/environment.h new file mode 100644 index 00000000..da36b741 --- /dev/null +++ b/source/frontends/retro/environment.h @@ -0,0 +1,19 @@ +#include "libretro.h" + +#include + +void fallback_log(enum retro_log_level level, const char *fmt, ...); +extern retro_log_callback logging; +extern retro_log_printf_t log_cb; +extern retro_input_poll_t input_poll_cb; +extern retro_input_state_t input_state_cb; +extern retro_environment_t environ_cb; +extern retro_video_refresh_t video_cb; +extern retro_audio_sample_t audio_cb; +extern retro_audio_sample_batch_t audio_batch_cb; + +extern std::string retro_base_directory; + +#define RETRO_DEVICES 5 + +extern unsigned int retro_devices[RETRO_DEVICES]; diff --git a/source/frontends/retro/game.cpp b/source/frontends/retro/game.cpp new file mode 100644 index 00000000..174cf093 --- /dev/null +++ b/source/frontends/retro/game.cpp @@ -0,0 +1,297 @@ +#include "StdAfx.h" +#include "frontends/retro/game.h" + +#include "Frame.h" +#include "Video.h" + +#include "Common.h" +#include "CardManager.h" +#include "Core.h" +#include "Disk.h" +#include "Mockingboard.h" +#include "SoundCore.h" +#include "Harddisk.h" +#include "Speaker.h" +#include "Log.h" +#include "CPU.h" +#include "Memory.h" +#include "LanguageCard.h" +#include "MouseInterface.h" +#include "ParallelPrinter.h" +#include "NTSC.h" +#include "SaveState.h" +#include "RGBMonitor.h" +#include "Riff.h" +#include "Utilities.h" + +#include "linux/videobuffer.h" +#include "linux/keyboard.h" +#include "linux/paddle.h" +#include "frontends/common2/programoptions.h" +#include "frontends/common2/configuration.h" +#include "frontends/retro/environment.h" + +#include "libretro.h" + +namespace +{ + + void initialiseEmulator() + { +#ifdef RIFF_SPKR + RiffInitWriteFile("/tmp/Spkr.wav", SPKR_SAMPLE_RATE, 1); +#endif +#ifdef RIFF_MB + RiffInitWriteFile("/tmp/Mockingboard.wav", 44100, 2); +#endif + + g_nAppMode = MODE_RUNNING; + LogFileOutput("Initialisation\n"); + + g_bFullSpeed = false; + + LoadConfiguration(); + SetCurrentCLK6502(); + GetAppleWindowTitle(); + + DSInit(); + MB_Initialize(); + SpkrInitialize(); + + MemInitialize(); + VideoBufferInitialize(); + VideoSwitchVideocardPalette(RGB_GetVideocard(), GetVideoType()); + + GetCardMgr().GetDisk2CardMgr().Reset(); + HD_Reset(); + Snapshot_Startup(); + } + + void uninitialiseEmulator() + { + Snapshot_Shutdown(); + CMouseInterface* pMouseCard = GetCardMgr().GetMouseCard(); + if (pMouseCard) + { + pMouseCard->Reset(); + } + VideoBufferDestroy(); + MemDestroy(); + + SpkrDestroy(); + MB_Destroy(); + DSUninit(); + + HD_Destroy(); + PrintDestroy(); + CpuDestroy(); + + GetCardMgr().GetDisk2CardMgr().Destroy(); + LogDone(); + RiffFinishWriteFile(); + } + + void runOneFrame(Speed & speed) + { + if (g_nAppMode == MODE_RUNNING) + { + const size_t cyclesToExecute = speed.getCyclesTillNext(16); + + const bool bVideoUpdate = true; + const UINT dwClksPerFrame = NTSC_GetCyclesPerFrame(); + + const DWORD executedCycles = CpuExecute(cyclesToExecute, bVideoUpdate); + // log_cb(RETRO_LOG_INFO, "RA2: %s %d\n", __FUNCTION__, executedCycles); + + g_dwCyclesThisFrame = (g_dwCyclesThisFrame + executedCycles) % dwClksPerFrame; + GetCardMgr().GetDisk2CardMgr().UpdateDriveState(executedCycles); + MB_PeriodicUpdate(executedCycles); + SpkrUpdate(executedCycles); + } + } + +} + +Game::Game() + : mySpeed(true) + , myWidth(GetFrameBufferWidth()) + , myHeight(GetFrameBufferHeight()) +{ + EmulatorOptions options; + options.memclear = g_nMemoryClearType; + options.log = true; + + if (options.log) + { + LogInit(); + } + + InitializeRegistry(options); + initialiseEmulator(); + + const size_t size = myWidth * myHeight * sizeof(bgra_t); + myVideoBuffer.resize(size); +} + +Game::~Game() +{ + uninitialiseEmulator(); +} + +void Game::executeOneFrame() +{ + runOneFrame(mySpeed); +} + +void Game::processInputEvents() +{ + input_poll_cb(); +} + +void Game::keyboardCallback(bool down, unsigned keycode, uint32_t character, uint16_t key_modifiers) +{ + if (down) + { + processKeyDown(keycode, character, key_modifiers); + } + else + { + processKeyUp(keycode, character, key_modifiers); + } +} + +void Game::processKeyDown(unsigned keycode, uint32_t character, uint16_t key_modifiers) +{ + BYTE ch = 0; + switch (keycode) + { + case RETROK_RETURN: + { + ch = 0x0d; + break; + } + case RETROK_BACKSPACE: // same as AppleWin + case RETROK_LEFT: + { + ch = 0x08; + break; + } + case RETROK_RIGHT: + { + ch = 0x15; + break; + } + case RETROK_UP: + { + ch = 0x0b; + break; + } + case RETROK_DOWN: + { + ch = 0x0a; + break; + } + case RETROK_DELETE: + { + ch = 0x7f; + break; + } + case RETROK_ESCAPE: + { + ch = 0x1b; + break; + } + case RETROK_TAB: + { + ch = 0x09; + break; + } + case RETROK_LALT: + { + Paddle::setButtonPressed(Paddle::ourOpenApple); + break; + } + case RETROK_RALT: + { + Paddle::setButtonPressed(Paddle::ourSolidApple); + break; + } + case RETROK_a ... RETROK_z: + { + ch = (keycode - RETROK_a) + 0x01; + if (key_modifiers & RETROKMOD_CTRL) + { + // ok + } + else if (key_modifiers & RETROKMOD_SHIFT) + { + ch += 0x60; + } + else + { + ch += 0x40; + } + break; + } + } + + if (!ch) + { + switch (character) { + case 0x20 ... 0x40: + case 0x5b ... 0x60: + case 0x7b ... 0x7e: + { + // not the letters + // this is very simple, but one cannot handle CRTL-key combination. + ch = character; + break; + } + } + } + + if (ch) + { + addKeyToBuffer(ch); + log_cb(RETRO_LOG_INFO, "RA2: %s - %02x\n", __FUNCTION__, ch); + } +} + +void Game::processKeyUp(unsigned keycode, uint32_t character, uint16_t key_modifiers) +{ + switch (keycode) + { + case RETROK_LALT: + { + Paddle::setButtonReleased(Paddle::ourOpenApple); + break; + } + case RETROK_RALT: + { + Paddle::setButtonReleased(Paddle::ourSolidApple); + break; + } + } +} + +void Game::drawVideoBuffer() +{ + const size_t pitch = myWidth * sizeof(bgra_t); + // this should not be necessary + // either libretro handles it + // or we should change AW + // but for now, there is no alternative + for (size_t row = 0; row < myHeight; ++row) + { + const uint8_t * src = g_pFramebufferbits + row * pitch; + uint8_t * dst = myVideoBuffer.data() + (myHeight - row - 1) * pitch; + memcpy(dst, src, pitch); + } + video_cb(myVideoBuffer.data(), myWidth, myHeight, pitch); +} + +bool Game::loadGame(const char * path) +{ + const bool ok = DoDiskInsert(SLOT6, DRIVE_1, path); + return ok; +} diff --git a/source/frontends/retro/game.h b/source/frontends/retro/game.h new file mode 100644 index 00000000..e68337da --- /dev/null +++ b/source/frontends/retro/game.h @@ -0,0 +1,30 @@ +#pragma once + +#include "frontends/common2/speed.h" + +class Game +{ +public: + Game(); + ~Game(); + + bool loadGame(const char * path); + + void executeOneFrame(); + void processInputEvents(); + + void drawVideoBuffer(); + + static void keyboardCallback(bool down, unsigned keycode, uint32_t character, uint16_t key_modifiers); + +private: + Speed mySpeed; // fixed speed + + const size_t myHeight; + const size_t myWidth; + + static void processKeyDown(unsigned keycode, uint32_t character, uint16_t key_modifiers); + static void processKeyUp(unsigned keycode, uint32_t character, uint16_t key_modifiers); + + std::vector myVideoBuffer; +}; diff --git a/source/frontends/retro/interface.cpp b/source/frontends/retro/interface.cpp new file mode 100644 index 00000000..923aafae --- /dev/null +++ b/source/frontends/retro/interface.cpp @@ -0,0 +1,22 @@ +#include "linux/interface.h" + +#include "frontends/retro/environment.h" +#include "linux/win.h" + +int MessageBox(HWND, const char * text, const char * caption, UINT type) +{ + log_cb(RETRO_LOG_INFO, "RA2: %s: %s - %s\n", __FUNCTION__, caption, text); + return IDOK; +} + +void FrameDrawDiskLEDS(HDC x) +{ +} + +void FrameDrawDiskStatus(HDC x) +{ +} + +void FrameRefreshStatus(int x, bool) +{ +} diff --git a/source/frontends/retro/libretro.cpp b/source/frontends/retro/libretro.cpp new file mode 100644 index 00000000..7d80e46f --- /dev/null +++ b/source/frontends/retro/libretro.cpp @@ -0,0 +1,231 @@ +#include "libretro.h" +#include +#include + +#include "StdAfx.h" +#include "Frame.h" + +#include "linux/version.h" + +#include "frontends/retro/game.h" +#include "frontends/retro/environment.h" + +namespace +{ + std::unique_ptr game; +} + +void retro_init(void) +{ + log_cb(RETRO_LOG_INFO, "RA2: %s\n", __FUNCTION__); + const char *dir = NULL; + if (environ_cb(RETRO_ENVIRONMENT_GET_SYSTEM_DIRECTORY, &dir) && dir) + { + retro_base_directory = dir; + } +} + +void retro_deinit(void) +{ + log_cb(RETRO_LOG_INFO, "RA2: %s\n", __FUNCTION__); +} + +unsigned retro_api_version(void) +{ + log_cb(RETRO_LOG_INFO, "RA2: %s\n", __FUNCTION__); + return RETRO_API_VERSION; +} + +void retro_set_controller_port_device(unsigned port, unsigned device) +{ + log_cb(RETRO_LOG_INFO, "RA2: %s\n", __FUNCTION__); + log_cb(RETRO_LOG_INFO, "Plugging device %u into port %u.\n", device, port); + + if (port < RETRO_DEVICES) + retro_devices[port] = device; +} + +void retro_get_system_info(retro_system_info *info) +{ + log_cb(RETRO_LOG_INFO, "RA2: %s\n", __FUNCTION__); + static std::string version = getVersion(); + + memset(info, 0, sizeof(*info)); + info->library_name = "AppleWin"; + info->library_version = version.c_str(); + info->need_fullpath = true; + info->valid_extensions = "bin|do|dsk|nib|po|gz|woz|zip|2mg|2img|iie|apl|hdv"; +} + + +void retro_get_system_av_info(retro_system_av_info *info) +{ + log_cb(RETRO_LOG_INFO, "RA2: %s\n", __FUNCTION__); + + info->geometry.base_width = GetFrameBufferWidth(); + info->geometry.base_height = GetFrameBufferHeight(); + info->geometry.max_width = GetFrameBufferWidth(); + info->geometry.max_height = GetFrameBufferHeight(); + info->geometry.aspect_ratio = 0; + + info->timing.fps = 60; + info->timing.sample_rate = 0; +} + +void retro_set_environment(retro_environment_t cb) +{ + log_cb(RETRO_LOG_INFO, "RA2: %s\n", __FUNCTION__); + environ_cb = cb; + + if (cb(RETRO_ENVIRONMENT_GET_LOG_INTERFACE, &logging)) + log_cb = logging.log; + else + log_cb = fallback_log; + /* + static const retro_controller_description controllers[] = + { + { "Apple Keyboard", RETRO_DEVICE_SUBCLASS(RETRO_DEVICE_KEYBOARD, 0) }, + }; + + static const retro_controller_info ports[] = + { + { controllers, 1 }, + { NULL, 0 }, + }; + + cb(RETRO_ENVIRONMENT_SET_CONTROLLER_INFO, (void*)ports);*/ + retro_keyboard_callback callback = {&Game::keyboardCallback}; + cb(RETRO_ENVIRONMENT_SET_KEYBOARD_CALLBACK, &callback); +} + +void retro_set_audio_sample(retro_audio_sample_t cb) +{ + log_cb(RETRO_LOG_INFO, "RA2: %s\n", __FUNCTION__); + audio_cb = cb; +} + +void retro_set_audio_sample_batch(retro_audio_sample_batch_t cb) +{ + log_cb(RETRO_LOG_INFO, "RA2: %s\n", __FUNCTION__); + audio_batch_cb = cb; +} + +void retro_set_input_poll(retro_input_poll_t cb) +{ + log_cb(RETRO_LOG_INFO, "RA2: %s\n", __FUNCTION__); + input_poll_cb = cb; +} + +void retro_set_input_state(retro_input_state_t cb) +{ + log_cb(RETRO_LOG_INFO, "RA2: %s\n", __FUNCTION__); + input_state_cb = cb; +} + +void retro_set_video_refresh(retro_video_refresh_t cb) +{ + log_cb(RETRO_LOG_INFO, "RA2: %s\n", __FUNCTION__); + video_cb = cb; +} + +void retro_run(void) +{ + game->processInputEvents(); + game->executeOneFrame(); + game->drawVideoBuffer(); +} + +bool retro_load_game(const retro_game_info *info) +{ + log_cb(RETRO_LOG_INFO, "RA2: %s\n", __FUNCTION__); + + enum retro_pixel_format fmt = RETRO_PIXEL_FORMAT_XRGB8888; + if (!environ_cb(RETRO_ENVIRONMENT_SET_PIXEL_FORMAT, &fmt)) + { + log_cb(RETRO_LOG_INFO, "XRGB8888 is not supported.\n"); + return false; + } + + try + { + game.reset(new Game); + const bool ok = game->loadGame(info->path); + + log_cb(RETRO_LOG_INFO, "Game path: %s:%d\n", info->path, ok); + + return ok; + } + catch (const std::exception & e) + { + log_cb(RETRO_LOG_INFO, "Exception: %s\n", e.what()); + } + catch (const std::string & s) + { + log_cb(RETRO_LOG_INFO, "Exception: %s\n", s.c_str()); + } + + return false; +} + +void retro_unload_game(void) +{ + game.reset(); + log_cb(RETRO_LOG_INFO, "RA2: %s\n", __FUNCTION__); +} + +unsigned retro_get_region(void) +{ + log_cb(RETRO_LOG_INFO, "RA2: %s\n", __FUNCTION__); + return RETRO_REGION_NTSC; +} + +void retro_reset(void) +{ + log_cb(RETRO_LOG_INFO, "RA2: %s\n", __FUNCTION__); +} + +bool retro_load_game_special(unsigned type, const struct retro_game_info *info, size_t num) +{ + log_cb(RETRO_LOG_INFO, "RA2: %s\n", __FUNCTION__); + return false; +} + +size_t retro_serialize_size(void) +{ + log_cb(RETRO_LOG_INFO, "RA2: %s\n", __FUNCTION__); + return 0; +} + +bool retro_serialize(void *data, size_t size) +{ + log_cb(RETRO_LOG_INFO, "RA2: %s\n", __FUNCTION__); + return false; +} + +bool retro_unserialize(const void *data, size_t size) +{ + log_cb(RETRO_LOG_INFO, "RA2: %s\n", __FUNCTION__); + return false; +} + +void retro_cheat_reset(void) +{ + log_cb(RETRO_LOG_INFO, "RA2: %s\n", __FUNCTION__); +} + +void retro_cheat_set(unsigned index, bool enabled, const char *code) +{ + log_cb(RETRO_LOG_INFO, "RA2: %s\n", __FUNCTION__); +} + +void *retro_get_memory_data(unsigned id) +{ + log_cb(RETRO_LOG_INFO, "RA2: %s\n", __FUNCTION__); + return nullptr; +} + +size_t retro_get_memory_size(unsigned id) +{ + log_cb(RETRO_LOG_INFO, "RA2: %s\n", __FUNCTION__); + return 0; +} diff --git a/source/frontends/retro/rdirectsound.cpp b/source/frontends/retro/rdirectsound.cpp new file mode 100644 index 00000000..2d5b6493 --- /dev/null +++ b/source/frontends/retro/rdirectsound.cpp @@ -0,0 +1,10 @@ +#include + +// Mockingboard +void registerSoundBuffer(IDirectSoundBuffer * buffer) +{ +} + +void unregisterSoundBuffer(IDirectSoundBuffer * buffer) +{ +} diff --git a/source/frontends/retro/run b/source/frontends/retro/run new file mode 100644 index 00000000..423882cf --- /dev/null +++ b/source/frontends/retro/run @@ -0,0 +1 @@ +retroarch -L source/frontends/retro/libra2.so ../Disks/NoSlotClockTest.dsk diff --git a/source/frontends/sa2/CMakeLists.txt b/source/frontends/sa2/CMakeLists.txt index aab73692..eab44af5 100644 --- a/source/frontends/sa2/CMakeLists.txt +++ b/source/frontends/sa2/CMakeLists.txt @@ -9,23 +9,17 @@ add_executable(sa2 utils.cpp ) -find_package(Boost REQUIRED - COMPONENTS program_options - ) - find_package(SDL2 REQUIRED) pkg_search_module(SDL2_IMAGE REQUIRED SDL2_image) target_compile_features(sa2 PUBLIC cxx_std_17) target_include_directories(sa2 PRIVATE - ${Boost_INCLUDE_DIRS} ${SDL2_INCLUDE_DIRS} ${SDL2_IMAGE_INCLUDE_DIRS} ) target_link_libraries(sa2 PRIVATE - Boost::program_options ${SDL2_LIBRARIES} ${SDL2_IMAGE_LIBRARIES} appleii diff --git a/source/linux/build.sh b/source/linux/build.sh index 105ee221..977d4702 100755 --- a/source/linux/build.sh +++ b/source/linux/build.sh @@ -2,8 +2,10 @@ set -euxo pipefail +wget https://raw.githubusercontent.com/libretro/RetroArch/master/libretro-common/include/libretro.h -P build/libretro-common/include + mkdir -p build cd build -cmake -DCMAKE_BUILD_TYPE=RELEASE .. +cmake -DCMAKE_BUILD_TYPE=RELEASE -DLIBRETRO_PATH=libretro-common .. make