Merge pull request #15 from audetto/retro2

Implement a libretro core.
This commit is contained in:
Andrea 2020-12-12 20:17:01 +00:00 committed by GitHub
commit db7e0625bd
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
17 changed files with 858 additions and 19 deletions

View file

@ -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_DEBUG: ${CMAKE_CXX_FLAGS_DEBUG}")
MESSAGE("CMAKE_CXX_FLAGS_RELWITHDEBINFO: ${CMAKE_CXX_FLAGS_RELWITHDEBINFO}") 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}) set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
execute_process(COMMAND uname -n execute_process(COMMAND uname -n
@ -35,4 +38,5 @@ add_subdirectory(source/frontends/common2)
add_subdirectory(source/frontends/ncurses) add_subdirectory(source/frontends/ncurses)
add_subdirectory(source/frontends/qapple) add_subdirectory(source/frontends/qapple)
add_subdirectory(source/frontends/sa2) add_subdirectory(source/frontends/sa2)
add_subdirectory(source/frontends/retro)
add_subdirectory(test/TestCPU6502) add_subdirectory(test/TestCPU6502)

View file

@ -6,6 +6,7 @@
* [applen](#applen) * [applen](#applen)
* [qapple](#qapple) * [qapple](#qapple)
* [sa2](#sa2) * [sa2](#sa2)
* [libretro](#ra2)
* [Build](#build) * [Build](#build)
* [Checkout](#checkout) * [Checkout](#checkout)
* [Fedora](#fedora) * [Fedora](#fedora)
@ -88,6 +89,20 @@ This is based on Qt, currently tested with 5.10
See [sa2](source/frontends/sa2/README.md). 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 ## Build
The project can be built using cmake from the top level directory. The project can be built using cmake from the top level directory.

View file

@ -18,7 +18,7 @@ target_include_directories(common2 PRIVATE
${Boost_INCLUDE_DIRS} ${Boost_INCLUDE_DIRS}
) )
target_link_libraries(common2 PRIVATE target_link_libraries(common2 PUBLIC
Boost::program_options Boost::program_options
) )

View file

@ -1,3 +1,6 @@
// relative path from executable to resources // relative path from executable to resources
#cmakedefine ROOT_PATH "@ROOT_PATH@" #cmakedefine ROOT_PATH "@ROOT_PATH@"
#cmakedefine SHARE_PATH "@SHARE_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@"

View file

@ -27,6 +27,8 @@ namespace
std::string getResourcePathImpl() std::string getResourcePathImpl()
{ {
std::vector<std::string> paths;
char self[1024] = {0}; char self[1024] = {0};
const int ch = readlink("/proc/self/exe", self, sizeof(self)); const int ch = readlink("/proc/self/exe", self, sizeof(self));
if (ch != -1) if (ch != -1)
@ -34,21 +36,24 @@ namespace
const char * path = dirname(self); const char * path = dirname(self);
// case 1: run from the build folder // case 1: run from the build folder
const std::string path1 = std::string(path) + '/'+ ROOT_PATH + "/resource/"; paths.emplace_back(std::string(path) + '/'+ ROOT_PATH);
if (dirExists(path1))
{
return path1;
}
// case 2: run from the installation folder // case 2: run from the installation folder
const std::string path2 = std::string(path) + '/'+ SHARE_PATH + "/resource/"; paths.emplace_back(std::string(path) + '/'+ SHARE_PATH);
if (dirExists(path2)) }
// 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");
} }
} }

View file

@ -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()

View file

@ -0,0 +1,151 @@
#include "frontends/retro/environment.h"
#include <linux/interface.h>
#include <linux/windows/misc.h>
#include <frontends/common2/resources.h>
#include <fstream>
#include <cstring>
namespace
{
void readFileToBuffer(const std::string & filename, std::vector<char> & 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<typename T>
T getAs(const std::vector<char> & buffer, const size_t offset)
{
if (offset + sizeof(T) > buffer.size())
{
throw std::runtime_error("Invalid bitmap");
}
const T * ptr = reinterpret_cast<const T *>(buffer.data() + offset);
return * ptr;
}
// libretro cannot parse BMP with 1 bpp
// simple version implemented here
bool getBitmapData(const std::vector<char> & 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<uint32_t>(buffer, 2);
if (fileSize != buffer.size())
{
return false;
}
const uint32_t offset = getAs<uint32_t>(buffer, 10);
const uint32_t header = getAs<uint32_t>(buffer, 14);
if (header != 40)
{
return false;
}
width = getAs<int32_t>(buffer, 18);
height = getAs<int32_t>(buffer, 22);
bpp = getAs<uint16_t>(buffer, 28);
const uint32_t imageSize = getAs<uint32_t>(buffer, 34);
if (offset + imageSize > fileSize)
{
return false;
}
data = buffer.data() + offset;
size = imageSize;
return true;
}
}
struct CBITMAP : public CHANDLE
{
std::vector<char> 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<char> 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<CBITMAP&>(*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<char *>(lpvBits);
memcpy(dest, bits, copied);
return copied;
}

View file

@ -0,0 +1,28 @@
#include "frontends/retro/environment.h"
#include <cstdarg>
#include <iostream>
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] = {};

View file

@ -0,0 +1,19 @@
#include "libretro.h"
#include <string>
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];

View file

@ -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;
}

View file

@ -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<uint8_t> myVideoBuffer;
};

View file

@ -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)
{
}

View file

@ -0,0 +1,231 @@
#include "libretro.h"
#include <memory>
#include <cstring>
#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> 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;
}

View file

@ -0,0 +1,10 @@
#include <linux/interface.h>
// Mockingboard
void registerSoundBuffer(IDirectSoundBuffer * buffer)
{
}
void unregisterSoundBuffer(IDirectSoundBuffer * buffer)
{
}

View file

@ -0,0 +1 @@
retroarch -L source/frontends/retro/libra2.so ../Disks/NoSlotClockTest.dsk

View file

@ -9,23 +9,17 @@ add_executable(sa2
utils.cpp utils.cpp
) )
find_package(Boost REQUIRED
COMPONENTS program_options
)
find_package(SDL2 REQUIRED) find_package(SDL2 REQUIRED)
pkg_search_module(SDL2_IMAGE REQUIRED SDL2_image) pkg_search_module(SDL2_IMAGE REQUIRED SDL2_image)
target_compile_features(sa2 PUBLIC cxx_std_17) target_compile_features(sa2 PUBLIC cxx_std_17)
target_include_directories(sa2 PRIVATE target_include_directories(sa2 PRIVATE
${Boost_INCLUDE_DIRS}
${SDL2_INCLUDE_DIRS} ${SDL2_INCLUDE_DIRS}
${SDL2_IMAGE_INCLUDE_DIRS} ${SDL2_IMAGE_INCLUDE_DIRS}
) )
target_link_libraries(sa2 PRIVATE target_link_libraries(sa2 PRIVATE
Boost::program_options
${SDL2_LIBRARIES} ${SDL2_LIBRARIES}
${SDL2_IMAGE_LIBRARIES} ${SDL2_IMAGE_LIBRARIES}
appleii appleii

View file

@ -2,8 +2,10 @@
set -euxo pipefail set -euxo pipefail
wget https://raw.githubusercontent.com/libretro/RetroArch/master/libretro-common/include/libretro.h -P build/libretro-common/include
mkdir -p build mkdir -p build
cd build cd build
cmake -DCMAKE_BUILD_TYPE=RELEASE .. cmake -DCMAKE_BUILD_TYPE=RELEASE -DLIBRETRO_PATH=libretro-common ..
make make