Merge pull request #11 from audetto/sdl2

Sdl2
This commit is contained in:
Andrea 2020-10-09 19:15:16 +01:00 committed by GitHub
commit 9982ceb36a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
18 changed files with 720 additions and 199 deletions

View file

@ -14,13 +14,25 @@ MESSAGE("CMAKE_CXX_FLAGS_RELWITHDEBINFO: ${CMAKE_CXX_FLAGS_RELWITHDEBINFO}")
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}) set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
include(CheckIPOSupported) execute_process(COMMAND uname -n
check_ipo_supported() OUTPUT_VARIABLE UNAME
set(CMAKE_INTERPROCEDURAL_OPTIMIZATION TRUE) OUTPUT_STRIP_TRAILING_WHITESPACE)
if(${UNAME} STREQUAL raspberrypi)
# it is too slow and might cause out of memory issues
# more forensic is required
MESSAGE("Raspberry Pi detected: IPO disabled")
else()
include(CheckIPOSupported)
check_ipo_supported()
set(CMAKE_INTERPROCEDURAL_OPTIMIZATION FALSE)
endif()
include_directories(source) include_directories(source)
add_subdirectory(source) add_subdirectory(source)
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(test/TestCPU6502) add_subdirectory(test/TestCPU6502)

View file

@ -5,7 +5,6 @@ add_library(appleii SHARED
SoundCore.cpp SoundCore.cpp
AY8910.cpp AY8910.cpp
Mockingboard.cpp Mockingboard.cpp
Pravets.cpp Pravets.cpp
Tape.cpp Tape.cpp
YamlHelper.cpp YamlHelper.cpp
@ -29,7 +28,6 @@ add_library(appleii SHARED
NTSC_CharSet.cpp NTSC_CharSet.cpp
CardManager.cpp CardManager.cpp
Disk2CardManager.cpp Disk2CardManager.cpp
SaveState.cpp # uses g_CardMgr in m_ConfigNew (reverse order)
Riff.cpp Riff.cpp
Configuration/PropertySheetHelper.cpp Configuration/PropertySheetHelper.cpp
@ -64,6 +62,7 @@ add_library(appleii SHARED
linux/duplicates/SerialComms.cpp linux/duplicates/SerialComms.cpp
linux/duplicates/IPropertySheet.cpp linux/duplicates/IPropertySheet.cpp
linux/duplicates/Applewin.cpp # defines g_CardMgr (reverse order) linux/duplicates/Applewin.cpp # defines g_CardMgr (reverse order)
SaveState.cpp # uses g_CardMgr in m_ConfigNew (reverse order)
Z80VICE/z80.cpp Z80VICE/z80.cpp
Z80VICE/z80mem.cpp Z80VICE/z80mem.cpp

View file

@ -0,0 +1,29 @@
include(GNUInstallDirs)
add_library(common2 STATIC
resources.cpp
configuration.cpp
programoptions.cpp
utils.cpp
)
find_package(Boost REQUIRED
COMPONENTS program_options
)
target_include_directories(common2 PRIVATE
${CMAKE_CURRENT_BINARY_DIR}
${Boost_INCLUDE_DIRS}
)
target_link_libraries(common2 PRIVATE
Boost::program_options
)
file(RELATIVE_PATH ROOT_PATH ${CMAKE_BINARY_DIR} ${CMAKE_SOURCE_DIR})
file(RELATIVE_PATH SHARE_PATH ${CMAKE_INSTALL_FULL_BINDIR} ${CMAKE_INSTALL_FULL_DATADIR}/applewin)
configure_file(config.h.in config.h)
install(DIRECTORY ${CMAKE_SOURCE_DIR}/resource
DESTINATION ${CMAKE_INSTALL_DATADIR}/applewin)

View file

@ -1,4 +1,4 @@
#include "frontends/ncurses/configuration.h" #include "frontends/common2/configuration.h"
#include "Log.h" #include "Log.h"
#include "linux/windows/files.h" #include "linux/windows/files.h"

View file

@ -0,0 +1,96 @@
#include <frontends/common2/programoptions.h>
#include <boost/program_options.hpp>
#include "StdAfx.h"
#include "Memory.h"
#include <iostream>
namespace po = boost::program_options;
bool getEmulatorOptions(int argc, const char * argv [], const std::string & version, EmulatorOptions & options)
{
po::options_description desc("AppleWin " + version);
desc.add_options()
("help,h", "Print this help message")
("conf", "Save configuration on exit");
po::options_description diskDesc("Disk");
diskDesc.add_options()
("d1,1", po::value<std::string>(), "Mount disk image in first drive")
("d2,2", po::value<std::string>(), "Mount disk image in second drive")
("create,c", "Create missing disks");
desc.add(diskDesc);
po::options_description snapshotDesc("Snapshot");
snapshotDesc.add_options()
("load-state,ls", po::value<std::string>(), "Load snapshot from file");
desc.add(snapshotDesc);
po::options_description memoryDesc("Memory");
memoryDesc.add_options()
("memclear,m", po::value<int>(), "Memory initialization pattern [0..7]");
desc.add(memoryDesc);
po::options_description emulatorDesc("Emulator");
emulatorDesc.add_options()
("log", "Log to AppleWin.log")
("headless,hl", "Headless: disable video")
("ntsc,nt", "NTSC: execute NTSC code")
("benchmark,b", "Benchmark emulator");
desc.add(emulatorDesc);
po::variables_map vm;
try
{
po::store(po::parse_command_line(argc, argv, desc), vm);
if (vm.count("help"))
{
std::cout << "AppleWin " << version << " edition" << std::endl << std::endl << desc << std::endl;
return false;
}
options.saveConfigurationOnExit = vm.count("conf");
if (vm.count("d1"))
{
options.disk1 = vm["d1"].as<std::string>();
}
if (vm.count("d2"))
{
options.disk2 = vm["d2"].as<std::string>();
}
options.createMissingDisks = vm.count("create") > 0;
if (vm.count("load-state"))
{
options.snapshot = vm["load-state"].as<std::string>();
}
if (vm.count("memclear"))
{
const int memclear = vm["memclear"].as<int>();
if (memclear >=0 && memclear < NUM_MIP)
options.memclear = memclear;
}
options.benchmark = vm.count("benchmark") > 0;
options.headless = vm.count("headless") > 0;
options.log = vm.count("log") > 0;
options.ntsc = vm.count("ntsc") > 0;
return true;
}
catch (const po::error& e)
{
std::cerr << "ERROR: " << e.what() << std::endl << desc << std::endl;
return false;
}
catch (const std::exception & e)
{
std::cerr << "ERROR: " << e.what() << std::endl;
return false;
}
}

View file

@ -0,0 +1,20 @@
#include <string>
struct EmulatorOptions
{
std::string disk1;
std::string disk2;
bool createMissingDisks;
std::string snapshot;
int memclear;
bool log;
bool benchmark;
bool headless;
bool ntsc;
bool saveConfigurationOnExit;
bool run; // false if options include "-h"
};
bool getEmulatorOptions(int argc, const char * argv [], const std::string & version, EmulatorOptions & options);

View file

@ -25,7 +25,7 @@ namespace
} }
} }
std::string getResourcePath() std::string getResourcePathImpl()
{ {
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));
@ -51,7 +51,12 @@ namespace
return std::string(); return std::string();
} }
const std::string resourcePath = getResourcePath(); }
const std::string & getResourcePath()
{
static const std::string path = getResourcePathImpl();
return path;
} }
HRSRC FindResource(void *, const char * filename, const char *) HRSRC FindResource(void *, const char * filename, const char *)
@ -60,7 +65,7 @@ HRSRC FindResource(void *, const char * filename, const char *)
if (filename) if (filename)
{ {
const std::string path = resourcePath + filename; const std::string path = getResourcePath() + filename;
int fd = open(path.c_str(), O_RDONLY); int fd = open(path.c_str(), O_RDONLY);
@ -84,15 +89,3 @@ HRSRC FindResource(void *, const char * filename, const char *)
return result; return result;
} }
HBITMAP LoadBitmap(HINSTANCE hInstance, const char * filename)
{
LogFileOutput("LoadBitmap: not loading resource %s\n", filename);
return nullptr;
}
LONG GetBitmapBits(HBITMAP hbit, LONG cb, LPVOID lpvBits)
{
memset(lpvBits, 0, cb);
return cb;
}

View file

@ -0,0 +1,3 @@
#include <string>
const std::string & getResourcePath();

View file

@ -0,0 +1,63 @@
#include <frontends/common2/utils.h>
#include "StdAfx.h"
#include "Common.h"
#include "Applewin.h"
#include "CardManager.h"
#include "Disk.h"
#include "SaveState.h"
#include <libgen.h>
#include <unistd.h>
bool DoDiskInsert(const UINT slot, const int nDrive, const std::string & fileName, const bool createMissingDisk)
{
std::string strPathName;
if (fileName.empty())
{
return false;
}
if (fileName[0] == '/')
{
// Abs pathname
strPathName = fileName;
}
else
{
// Rel pathname
char szCWD[MAX_PATH] = {0};
if (!GetCurrentDirectory(sizeof(szCWD), szCWD))
return false;
strPathName = szCWD;
strPathName.append("/");
strPathName.append(fileName);
}
Disk2InterfaceCard* pDisk2Card = dynamic_cast<Disk2InterfaceCard*> (g_CardMgr.GetObj(slot));
ImageError_e Error = pDisk2Card->InsertDisk(nDrive, strPathName.c_str(), IMAGE_USE_FILES_WRITE_PROTECT_STATUS, createMissingDisk);
return Error == eIMAGE_ERROR_NONE;
}
void setSnapshotFilename(const std::string & filename)
{
// same logic as qapple
// setting chdir allows to load relative disks from the snapshot file (tests?)
// but if the snapshot file itself is relative, it wont work after a chdir
// so we convert to absolute first
char * absPath = realpath(filename.c_str(), nullptr);
if (absPath)
{
char * temp = strdup(absPath);
const char * dir = dirname(temp);
// dir points inside temp!
chdir(dir);
Snapshot_SetFilename(absPath);
free(temp);
free(absPath);
Snapshot_LoadState();
}
}

View file

@ -0,0 +1,6 @@
#include <string>
#include <linux/windows/wincompat.h>
bool DoDiskInsert(const UINT slot, const int nDrive, const std::string & fileName, const bool createMissingDisk);
void setSnapshotFilename(const std::string & filename);

View file

@ -1,5 +1,4 @@
include(FindPkgConfig) include(FindPkgConfig)
include(GNUInstallDirs)
add_executable(applen add_executable(applen
main.cpp main.cpp
@ -8,18 +7,13 @@ add_executable(applen
evdevpaddle.cpp evdevpaddle.cpp
nframe.cpp nframe.cpp
asciiart.cpp asciiart.cpp
resources.cpp bitmaps.cpp
configuration.cpp
) )
pkg_search_module(NCURSESW REQUIRED ncursesw) pkg_search_module(NCURSESW REQUIRED ncursesw)
pkg_search_module(LIBEVDEV REQUIRED libevdev) pkg_search_module(LIBEVDEV REQUIRED libevdev)
find_package(Boost REQUIRED
COMPONENTS program_options
)
target_include_directories(applen PRIVATE target_include_directories(applen PRIVATE
${CMAKE_CURRENT_BINARY_DIR}
${NCURSESW_INCLUDE_DIRS} ${NCURSESW_INCLUDE_DIRS}
${LIBEVDEV_INCLUDE_DIRS} ${LIBEVDEV_INCLUDE_DIRS}
${Boost_INCLUDE_DIRS} ${Boost_INCLUDE_DIRS}
@ -33,17 +27,9 @@ target_compile_options(applen PRIVATE
target_link_libraries(applen PRIVATE target_link_libraries(applen PRIVATE
${NCURSESW_LIBRARIES} ${NCURSESW_LIBRARIES}
${LIBEVDEV_LIBRARIES} ${LIBEVDEV_LIBRARIES}
Boost::program_options
appleii appleii
common2
) )
file(RELATIVE_PATH ROOT_PATH ${CMAKE_BINARY_DIR} ${CMAKE_SOURCE_DIR})
file(RELATIVE_PATH SHARE_PATH ${CMAKE_INSTALL_FULL_BINDIR} ${CMAKE_INSTALL_FULL_DATADIR}/applewin)
configure_file(config.h.in config.h)
install(TARGETS applen install(TARGETS applen
DESTINATION bin) DESTINATION bin)
install(DIRECTORY ${CMAKE_SOURCE_DIR}/resource
DESTINATION ${CMAKE_INSTALL_DATADIR}/applewin)

View file

@ -0,0 +1,14 @@
#include "StdAfx.h"
#include "Log.h"
HBITMAP LoadBitmap(HINSTANCE hInstance, const char * filename)
{
LogFileOutput("LoadBitmap: not loading resource %s\n", filename);
return nullptr;
}
LONG GetBitmapBits(HBITMAP hbit, LONG cb, LPVOID lpvBits)
{
memset(lpvBits, 0, cb);
return cb;
}

View file

@ -4,9 +4,6 @@
#include <thread> #include <thread>
#include <iostream> #include <iostream>
#include <ncurses.h> #include <ncurses.h>
#include <libgen.h>
#include <boost/program_options.hpp>
#include "Common.h" #include "Common.h"
#include "CardManager.h" #include "CardManager.h"
@ -27,116 +24,13 @@
#include "linux/data.h" #include "linux/data.h"
#include "linux/benchmark.h" #include "linux/benchmark.h"
#include "frontends/ncurses/configuration.h" #include "frontends/common2/configuration.h"
#include "frontends/common2/programoptions.h"
#include "frontends/common2/utils.h"
#include "frontends/ncurses/world.h" #include "frontends/ncurses/world.h"
namespace namespace
{ {
namespace po = boost::program_options;
struct EmulatorOptions
{
std::string disk1;
std::string disk2;
bool createMissingDisks;
std::string snapshot;
int memclear;
bool log;
bool benchmark;
bool headless;
bool ntsc;
bool saveConfigurationOnExit;
bool run; // false if options include "-h"
};
bool getEmulatorOptions(int argc, const char * argv [], EmulatorOptions & options)
{
po::options_description desc("AppleWin ncurses");
desc.add_options()
("help,h", "Print this help message")
("conf", "Save configuration on exit");
po::options_description diskDesc("Disk");
diskDesc.add_options()
("d1,1", po::value<std::string>(), "Mount disk image in first drive")
("d2,2", po::value<std::string>(), "Mount disk image in second drive")
("create,c", "Create missing disks");
desc.add(diskDesc);
po::options_description snapshotDesc("Snapshot");
snapshotDesc.add_options()
("load-state,ls", po::value<std::string>(), "Load snapshot from file");
desc.add(snapshotDesc);
po::options_description memoryDesc("Memory");
memoryDesc.add_options()
("memclear,m", po::value<int>(), "Memory initialization pattern [0..7]");
desc.add(memoryDesc);
po::options_description emulatorDesc("Emulator");
emulatorDesc.add_options()
("log", "Log to AppleWin.log")
("headless,hl", "Headless: disable video")
("ntsc,nt", "NTSC: execute NTSC code")
("benchmark,b", "Benchmark emulator");
desc.add(emulatorDesc);
po::variables_map vm;
try
{
po::store(po::parse_command_line(argc, argv, desc), vm);
if (vm.count("help"))
{
std::cout << "AppleWin ncurses edition" << std::endl << std::endl << desc << std::endl;
return false;
}
options.saveConfigurationOnExit = vm.count("conf");
if (vm.count("d1"))
{
options.disk1 = vm["d1"].as<std::string>();
}
if (vm.count("d2"))
{
options.disk2 = vm["d2"].as<std::string>();
}
options.createMissingDisks = vm.count("create") > 0;
if (vm.count("load-state"))
{
options.snapshot = vm["load-state"].as<std::string>();
}
if (vm.count("memclear"))
{
const int memclear = vm["memclear"].as<int>();
if (memclear >=0 && memclear < NUM_MIP)
options.memclear = memclear;
}
options.benchmark = vm.count("benchmark") > 0;
options.headless = vm.count("headless") > 0;
options.log = vm.count("log") > 0;
options.ntsc = vm.count("ntsc") > 0;
return true;
}
catch (const po::error& e)
{
std::cerr << "ERROR: " << e.what() << std::endl << desc << std::endl;
return false;
}
catch (const std::exception & e)
{
std::cerr << "ERROR: " << e.what() << std::endl;
return false;
}
}
bool ContinueExecution(const EmulatorOptions & options) bool ContinueExecution(const EmulatorOptions & options)
{ {
@ -229,63 +123,11 @@ namespace
} }
} }
bool DoDiskInsert(const UINT slot, const int nDrive, const std::string & fileName, const bool createMissingDisk)
{
std::string strPathName;
if (fileName.empty())
{
return false;
}
if (fileName[0] == '/')
{
// Abs pathname
strPathName = fileName;
}
else
{
// Rel pathname
char szCWD[MAX_PATH] = {0};
if (!GetCurrentDirectory(sizeof(szCWD), szCWD))
return false;
strPathName = szCWD;
strPathName.append("/");
strPathName.append(fileName);
}
Disk2InterfaceCard* pDisk2Card = dynamic_cast<Disk2InterfaceCard*> (g_CardMgr.GetObj(slot));
ImageError_e Error = pDisk2Card->InsertDisk(nDrive, strPathName.c_str(), IMAGE_USE_FILES_WRITE_PROTECT_STATUS, createMissingDisk);
return Error == eIMAGE_ERROR_NONE;
}
void setSnapshotFilename(const std::string & filename)
{
// same logic as qapple
// setting chdir allows to load relative disks from the snapshot file (tests?)
// but if the snapshot file itself is relative, it wont work after a chdir
// so we convert to absolute first
char * absPath = realpath(filename.c_str(), nullptr);
if (absPath)
{
char * temp = strdup(absPath);
const char * dir = dirname(temp);
// dir points inside temp!
chdir(dir);
Snapshot_SetFilename(absPath);
free(temp);
free(absPath);
Snapshot_LoadState();
}
}
int foo(int argc, const char * argv []) int foo(int argc, const char * argv [])
{ {
EmulatorOptions options; EmulatorOptions options;
options.memclear = g_nMemoryClearType; options.memclear = g_nMemoryClearType;
const bool run = getEmulatorOptions(argc, argv, options); const bool run = getEmulatorOptions(argc, argv, "ncurses", options);
if (!run) if (!run)
return 1; return 1;

View file

@ -0,0 +1,29 @@
include(FindPkgConfig)
add_executable(sa2
main.cpp
bitmaps.cpp
)
find_package(Boost REQUIRED
COMPONENTS program_options
)
find_package(SDL2 REQUIRED)
target_compile_features(sa2 PUBLIC cxx_std_17)
target_include_directories(sa2 PRIVATE
${Boost_INCLUDE_DIRS}
${SDL2_INCLUDE_DIRS}
)
target_link_libraries(sa2 PRIVATE
Boost::program_options
${SDL2_LIBRARIES}
appleii
common2
)
install(TARGETS sa2
DESTINATION bin)

View file

@ -0,0 +1,82 @@
#include <SDL.h>
#include <memory>
#include <iostream>
#include <linux/interface.h>
#include <linux/windows/misc.h>
#include <frontends/common2/resources.h>
struct CBITMAP : public CHANDLE
{
std::shared_ptr<SDL_Surface> surface;
};
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::shared_ptr<SDL_Surface> surface(SDL_LoadBMP(path.c_str()), SDL_FreeSurface);
if (surface)
{
CBITMAP * bitmap = new CBITMAP;
bitmap->surface = surface;
return bitmap;
}
else
{
std::cerr << "Cannot load: " << resource << " with path: " << path << std::endl;
return nullptr;
}
}
else
{
std::cerr << "Cannot load invalid resource." << std::endl;
return nullptr;
}
}
LONG GetBitmapBits(HBITMAP hbit, LONG cb, LPVOID lpvBits)
{
const CBITMAP & bitmap = dynamic_cast<CBITMAP&>(*hbit);
SDL_LockSurface(bitmap.surface.get());
const SDL_Surface * surface = bitmap.surface.get();
const char * source = static_cast<char *>(surface->pixels);
const size_t size = surface->h * surface->w / 8;
const size_t requested = cb;
const size_t copied = std::min(requested, size);
char * dest = static_cast<char *>(lpvBits);
for (size_t i = 0; i < copied; ++i)
{
const size_t offset = i * 8;
char val = 0;
for (size_t j = 0; j < 8; ++j)
{
const char pixel = *(source + offset + j);
val = (val << 1) | pixel;
}
dest[i] = val;
}
SDL_UnlockSurface(bitmap.surface.get());
return copied;
}

View file

@ -0,0 +1,347 @@
#include <iostream>
#include <SDL.h>
#include <memory>
#include "linux/interface.h"
#include "linux/windows/misc.h"
#include "linux/data.h"
#include "frontends/common2/configuration.h"
#include "frontends/common2/utils.h"
#include "frontends/common2/programoptions.h"
#include "StdAfx.h"
#include "Common.h"
#include "CardManager.h"
#include "Applewin.h"
#include "Disk.h"
#include "Harddisk.h"
#include "Log.h"
#include "CPU.h"
#include "Frame.h"
#include "Memory.h"
#include "LanguageCard.h"
#include "MouseInterface.h"
#include "ParallelPrinter.h"
#include "Video.h"
#include "NTSC.h"
#include "SaveState.h"
#include "RGBMonitor.h"
namespace
{
void initialiseEmulator()
{
InitializeRegistry("applen.conf");
g_fh = fopen("/tmp/applewin.txt", "w");
setbuf(g_fh, nullptr);
LogFileOutput("Initialisation\n");
ImageInitialize();
g_bFullSpeed = false;
}
void loadEmulator()
{
LoadConfiguration();
CheckCpu();
SetWindowTitle();
FrameRefreshStatus(DRAW_LEDS | DRAW_BUTTON_DRIVES);
ResetDefaultMachineMemTypes();
MemInitialize();
VideoInitialize();
VideoSwitchVideocardPalette(RGB_GetVideocard(), GetVideoType());
g_CardMgr.GetDisk2CardMgr().Reset();
HD_Reset();
}
void applyOptions(const EmulatorOptions & options)
{
if (options.log)
{
LogInit();
}
bool disksOk = true;
if (!options.disk1.empty())
{
const bool ok = DoDiskInsert(SLOT6, DRIVE_1, options.disk1, options.createMissingDisks);
disksOk = disksOk && ok;
LogFileOutput("Init: DoDiskInsert(D1), res=%d\n", ok);
}
if (!options.disk2.empty())
{
const bool ok = DoDiskInsert(SLOT6, DRIVE_2, options.disk2, options.createMissingDisks);
disksOk = disksOk && ok;
LogFileOutput("Init: DoDiskInsert(D2), res=%d\n", ok);
}
if (!options.snapshot.empty())
{
setSnapshotFilename(options.snapshot);
}
}
void stopEmulator()
{
CMouseInterface* pMouseCard = g_CardMgr.GetMouseCard();
if (pMouseCard)
{
pMouseCard->Reset();
}
MemDestroy();
}
void uninitialiseEmulator()
{
HD_Destroy();
PrintDestroy();
CpuDestroy();
g_CardMgr.GetDisk2CardMgr().Destroy();
ImageDestroy();
fclose(g_fh);
g_fh = nullptr;
}
SDL_Rect refreshTexture(const std::shared_ptr<SDL_Texture> & tex)
{
uint8_t * data;
int width;
int height;
int sx, sy;
int sw, sh;
getScreenData(data, width, height, sx, sy, sw, sh);
void * pixels;
int pitch;
SDL_LockTexture(tex.get(), nullptr, &pixels, &pitch);
memcpy(pixels, data, width * height * 4);
SDL_UnlockTexture(tex.get());
SDL_Rect srect;
srect.x = sx;
srect.y = sy;
srect.w = sw;
srect.h = sh;
return srect;
}
void renderScreen(const std::shared_ptr<SDL_Renderer> & ren, const std::shared_ptr<SDL_Texture> & tex, const SDL_Rect & srect)
{
SDL_RenderCopyEx(ren.get(), tex.get(), &srect, nullptr, 0.0, nullptr, SDL_FLIP_VERTICAL);
SDL_RenderPresent(ren.get());
}
void cycleVideoType(const std::shared_ptr<SDL_Window> & win)
{
g_eVideoType++;
if (g_eVideoType >= NUM_VIDEO_MODES)
g_eVideoType = 0;
SetWindowTitle();
SDL_SetWindowTitle(win.get(), g_pAppTitle.c_str());
Config_Save_Video();
VideoReinitialize();
VideoRedrawScreen();
}
void cycle50ScanLines(const std::shared_ptr<SDL_Window> & win)
{
VideoStyle_e videoStyle = GetVideoStyle();
videoStyle = VideoStyle_e(videoStyle ^ VS_HALF_SCANLINES);
SetVideoStyle(videoStyle);
SetWindowTitle();
SDL_SetWindowTitle(win.get(), g_pAppTitle.c_str());
Config_Save_Video();
VideoReinitialize();
VideoRedrawScreen();
}
int getFPS()
{
SDL_DisplayMode current;
int should_be_zero = SDL_GetCurrentDisplayMode(0, &current);
if (should_be_zero)
{
throw std::string(SDL_GetError());
}
return current.refresh_rate;
}
}
int MessageBox(HWND, const char * text, const char * caption, UINT type)
{
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_INFORMATION, caption, text, nullptr);
return IDOK;
}
void FrameDrawDiskLEDS(HDC x)
{
}
void FrameDrawDiskStatus(HDC x)
{
}
void FrameRefreshStatus(int x, bool)
{
}
BYTE SpkrToggle (WORD pc, WORD addr, BYTE bWrite, BYTE d, ULONG uExecutedCycles)
{
return MemReadFloatingBus(uExecutedCycles);
}
// Mockingboard
void registerSoundBuffer(IDirectSoundBuffer * buffer)
{
}
void unregisterSoundBuffer(IDirectSoundBuffer * buffer)
{
}
void run_sdl(int argc, const char * argv [])
{
EmulatorOptions options;
options.memclear = g_nMemoryClearType;
const bool run = getEmulatorOptions(argc, argv, "SDL2", options);
if (!run)
return;
initialiseEmulator();
loadEmulator();
const int width = GetFrameBufferWidth();
const int height = GetFrameBufferHeight();
const int sx = GetFrameBufferBorderWidth();
const int sy = GetFrameBufferBorderHeight();
const int sw = GetFrameBufferBorderlessWidth();
const int sh = GetFrameBufferBorderlessHeight();
int multiplier = 1;
std::shared_ptr<SDL_Window> win(SDL_CreateWindow(g_pAppTitle.c_str(), SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, sw, sh, SDL_WINDOW_SHOWN), SDL_DestroyWindow);
if (!win)
{
std::cerr << "SDL_CreateWindow Error: " << SDL_GetError() << std::endl;
return;
}
std::shared_ptr<SDL_Renderer> ren(SDL_CreateRenderer(win.get(), -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC), SDL_DestroyRenderer);
if (!ren)
{
std::cout << "SDL_CreateRenderer Error: " << SDL_GetError() << std::endl;
return;
}
const Uint32 format = SDL_PIXELFORMAT_BGRA32;
std::shared_ptr<SDL_Texture> tex(SDL_CreateTexture(ren.get(), format, SDL_TEXTUREACCESS_STREAMING, width, height), SDL_DestroyTexture);
const int fps = getFPS();
const DWORD uCyclesToExecute = int(g_fCurrentCLK6502 / fps);
const UINT dwClksPerFrame = NTSC_GetCyclesPerFrame();
bool quit = false;
do
{
SDL_Event e;
while (SDL_PollEvent(&e) != 0)
{
if (e.type == SDL_QUIT)
{
quit = true;
}
else if (e.type == SDL_KEYDOWN)
{
if (!e.key.repeat)
{
switch (e.key.keysym.scancode)
{
case SDL_SCANCODE_F9:
{
cycleVideoType(win);
break;
}
case SDL_SCANCODE_F6:
{
if ((e.key.keysym.mod & KMOD_CTRL) && (e.key.keysym.mod & KMOD_SHIFT))
{
cycle50ScanLines(win);
}
else if (e.key.keysym.mod & KMOD_CTRL)
{
multiplier = multiplier == 1 ? 2 : 1;
SDL_SetWindowSize(win.get(), sw * multiplier, sh * multiplier);
}
break;
}
}
}
std::cerr << e.key.keysym.scancode << "," << e.key.keysym.sym << "," << e.key.keysym.mod << "," << bool(e.key.repeat) << ",AAA" << std::endl;
}
}
const bool bVideoUpdate = true;
const DWORD uActualCyclesExecuted = CpuExecute(uCyclesToExecute, bVideoUpdate);
g_dwCyclesThisFrame += uActualCyclesExecuted;
g_CardMgr.GetDisk2CardMgr().UpdateDriveState(uActualCyclesExecuted);
// SDL2 seems to synch with screen refresh rate so we do not need to worry about timers
const SDL_Rect srect = refreshTexture(tex);
renderScreen(ren, tex, srect);
g_dwCyclesThisFrame = (g_dwCyclesThisFrame + g_dwCyclesThisFrame) % dwClksPerFrame;
} while (!quit);
stopEmulator();
uninitialiseEmulator();
}
int main(int argc, const char * argv [])
{
//First we need to start up SDL, and make sure it went ok
if (SDL_Init(SDL_INIT_VIDEO) != 0)
{
std::cerr << "SDL_Init Error: " << SDL_GetError() << std::endl;
return 1;
}
int exit = 0;
try
{
run_sdl(argc, argv);
}
catch (const std::exception & e)
{
exit = 2;
std::cerr << e.what() << std::endl;
}
SDL_Quit();
return exit;
}