From be4c650238857e0827498dd40d9518434c0bc2c9 Mon Sep 17 00:00:00 2001 From: Matthew Budd Date: Tue, 23 Jun 2020 20:40:43 -0400 Subject: [PATCH] Starting new QT gui. --- src/drivers/Qt/.qmake.stash | 22 + src/drivers/Qt/GameApp.cpp | 88 ++ src/drivers/Qt/GameApp.h | 50 + src/drivers/Qt/GameViewer.cpp | 64 + src/drivers/Qt/GameViewer.h | 26 + src/drivers/Qt/config.cpp | 485 +++++++ src/drivers/Qt/config.h | 28 + src/drivers/Qt/dface.h | 37 + src/drivers/Qt/fceuWrapper.cpp | 300 ++++ src/drivers/Qt/fceuWrapper.h | 23 + src/drivers/Qt/gl_win.cpp | 54 + src/drivers/Qt/gl_win.h | 68 + src/drivers/Qt/input.cpp | 2355 +++++++++++++++++++++++++++++++ src/drivers/Qt/input.h | 62 + src/drivers/Qt/keyscan.h | 44 + src/drivers/Qt/main.cpp | 15 + src/drivers/Qt/main.h | 100 ++ src/drivers/Qt/sdl-joystick.cpp | 123 ++ src/drivers/Qt/sdl-sound.cpp | 280 ++++ src/drivers/Qt/sdl-throttle.cpp | 154 ++ src/drivers/Qt/sdl-video.cpp | 464 ++++++ src/drivers/Qt/sdl-video.h | 17 + src/drivers/Qt/sdl.h | 32 + src/drivers/Qt/throttle.h | 2 + src/drivers/Qt/unix-netplay.cpp | 366 +++++ src/drivers/Qt/unix-netplay.h | 6 + src/fceux.pro | 305 ++++ 27 files changed, 5570 insertions(+) create mode 100644 src/drivers/Qt/.qmake.stash create mode 100644 src/drivers/Qt/GameApp.cpp create mode 100644 src/drivers/Qt/GameApp.h create mode 100644 src/drivers/Qt/GameViewer.cpp create mode 100644 src/drivers/Qt/GameViewer.h create mode 100644 src/drivers/Qt/config.cpp create mode 100644 src/drivers/Qt/config.h create mode 100644 src/drivers/Qt/dface.h create mode 100644 src/drivers/Qt/fceuWrapper.cpp create mode 100644 src/drivers/Qt/fceuWrapper.h create mode 100644 src/drivers/Qt/gl_win.cpp create mode 100644 src/drivers/Qt/gl_win.h create mode 100644 src/drivers/Qt/input.cpp create mode 100644 src/drivers/Qt/input.h create mode 100644 src/drivers/Qt/keyscan.h create mode 100644 src/drivers/Qt/main.cpp create mode 100644 src/drivers/Qt/main.h create mode 100644 src/drivers/Qt/sdl-joystick.cpp create mode 100644 src/drivers/Qt/sdl-sound.cpp create mode 100644 src/drivers/Qt/sdl-throttle.cpp create mode 100644 src/drivers/Qt/sdl-video.cpp create mode 100644 src/drivers/Qt/sdl-video.h create mode 100644 src/drivers/Qt/sdl.h create mode 100644 src/drivers/Qt/throttle.h create mode 100644 src/drivers/Qt/unix-netplay.cpp create mode 100644 src/drivers/Qt/unix-netplay.h create mode 100644 src/fceux.pro diff --git a/src/drivers/Qt/.qmake.stash b/src/drivers/Qt/.qmake.stash new file mode 100644 index 00000000..c753fda7 --- /dev/null +++ b/src/drivers/Qt/.qmake.stash @@ -0,0 +1,22 @@ +QMAKE_CXX.INCDIRS = \ + /usr/include/c++/8 \ + /usr/include/c++/8/x86_64-redhat-linux \ + /usr/include/c++/8/backward \ + /usr/lib/gcc/x86_64-redhat-linux/8/include \ + /usr/local/include \ + /usr/include +QMAKE_CXX.LIBDIRS = \ + /usr/lib/gcc/x86_64-redhat-linux/8 \ + /usr/lib64 \ + /lib64 \ + /usr/lib \ + /lib +QMAKE_CXX.QT_COMPILER_STDCXX = 201402L +QMAKE_CXX.QMAKE_GCC_MAJOR_VERSION = 8 +QMAKE_CXX.QMAKE_GCC_MINOR_VERSION = 3 +QMAKE_CXX.QMAKE_GCC_PATCH_VERSION = 1 +QMAKE_CXX.COMPILER_MACROS = \ + QT_COMPILER_STDCXX \ + QMAKE_GCC_MAJOR_VERSION \ + QMAKE_GCC_MINOR_VERSION \ + QMAKE_GCC_PATCH_VERSION diff --git a/src/drivers/Qt/GameApp.cpp b/src/drivers/Qt/GameApp.cpp new file mode 100644 index 00000000..de15835f --- /dev/null +++ b/src/drivers/Qt/GameApp.cpp @@ -0,0 +1,88 @@ +// GameApp.cpp +// +#include "GameApp.h" + +gameWin_t::gameWin_t(QWidget *parent) + : QMainWindow( parent ) +{ + QWidget *widget = new QWidget( this ); + + setCentralWidget(widget); + + QVBoxLayout *layout = new QVBoxLayout; + layout->setMargin(5); + + createMainMenu(); + + viewport = new gameView_t(); + //viewport.resize( 200, 200 ); + + layout->addWidget(viewport); + + widget->setLayout(layout); + + gameTimer = new QTimer( this ); + + connect( gameTimer, &QTimer::timeout, this, &gameWin_t::runGameFrame ); + + gameTimer->setTimerType( Qt::PreciseTimer ); + gameTimer->start( 10 ); +} + +gameWin_t::~gameWin_t(void) +{ + delete viewport; +} + +void gameWin_t::createMainMenu(void) +{ + menuBar()->setNativeMenuBar(false); + fileMenu = menuBar()->addMenu(tr("&File")); + + openAct = new QAction(tr("&Open"), this); + openAct->setShortcuts(QKeySequence::Open); + openAct->setStatusTip(tr("Open an Existing File")); + connect(openAct, SIGNAL(triggered()), this, SLOT(openFile(void)) ); + + fileMenu->addAction(openAct); + + quitAct = new QAction(tr("&Quit"), this); + quitAct->setStatusTip(tr("Quit the Application")); + connect(quitAct, SIGNAL(triggered()), qApp, SLOT(quit())); + + fileMenu->addAction(quitAct); + + helpMenu = menuBar()->addMenu(tr("&Help")); + + aboutAct = new QAction(tr("&About"), this); + aboutAct->setStatusTip(tr("About Qplot")); + connect(aboutAct, SIGNAL(triggered()), this, SLOT(aboutQPlot(void)) ); + + helpMenu->addAction(aboutAct); +}; + +void gameWin_t::openFile(void) +{ + printf("Open File\n"); + return; +} +void gameWin_t::aboutQPlot(void) +{ + printf("About QPlot\n"); + return; +} + +void gameWin_t::runGameFrame(void) +{ + struct timespec ts; + double t; + + clock_gettime( CLOCK_REALTIME, &ts ); + + t = (double)ts.tv_sec + (double)(ts.tv_nsec * 1.0e-9); + //printf("Run Frame %f\n", t); + // + viewport->repaint(); + + return; +} diff --git a/src/drivers/Qt/GameApp.h b/src/drivers/Qt/GameApp.h new file mode 100644 index 00000000..44f9529c --- /dev/null +++ b/src/drivers/Qt/GameApp.h @@ -0,0 +1,50 @@ + +// + +#ifndef __GameAppH__ +#define __GameAppH__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "GameViewer.h" + +class gameWin_t : public QMainWindow +{ + Q_OBJECT + + public: + gameWin_t(QWidget *parent = 0); + ~gameWin_t(void); + + gameView_t *viewport; + //QPushButton hello( "Hello world!", 0 ); + // + + QMenu *fileMenu; + QMenu *helpMenu; + + QAction *openAct; + QAction *quitAct; + QAction *aboutAct; + + QTimer *gameTimer; + + private: + void createMainMenu(void); + + private slots: + void openFile(void); + void aboutQPlot(void); + void runGameFrame(void); + +}; + +#endif diff --git a/src/drivers/Qt/GameViewer.cpp b/src/drivers/Qt/GameViewer.cpp new file mode 100644 index 00000000..ef32e331 --- /dev/null +++ b/src/drivers/Qt/GameViewer.cpp @@ -0,0 +1,64 @@ +// GameViewer.cpp +// +#include + +#include "GameViewer.h" + +gameView_t::gameView_t(QWidget *parent) + : QOpenGLWidget( parent ) +{ + +} + +gameView_t::~gameView_t(void) +{ + // Make sure the context is current and then explicitly + // destroy all underlying OpenGL resources. + makeCurrent(); + + // Free GL texture + + doneCurrent(); +} + +void gameView_t::initializeGL(void) +{ + initializeOpenGLFunctions(); + // Set up the rendering context, load shaders and other resources, etc.: + //QOpenGLFunctions *gl = QOpenGLContext::currentContext()->functions(); + glClearColor(0.0f, 0.0f, 0.0f, 0.0f); + + printf("GL Init!\n"); +} + +void gameView_t::resizeGL(int w, int h) +{ + printf("GL Resize: %i x %i \n", w, h ); + glViewport(0, 0, w, h); + +} + +void gameView_t::paintGL(void) +{ + float x1, y1, x2, y2; + + angle += (2.0 * 3.14 * 0.01); + + glClearColor(0.0f, 0.0f, 0.0f, 0.0f); + + x1 = cos( angle ); + y1 = sin( angle ); + + x2 = -x1; + y2 = -y1; + + glColor4f( 1.0, 1.0, 1.0, 1.0 ); + glLineWidth(5.0); + + glBegin(GL_LINES); + glVertex2f( x1, y1 ); + glVertex2f( x2, y2 ); + glEnd(); + + //printf("Paint GL!\n"); +} diff --git a/src/drivers/Qt/GameViewer.h b/src/drivers/Qt/GameViewer.h new file mode 100644 index 00000000..655eb9de --- /dev/null +++ b/src/drivers/Qt/GameViewer.h @@ -0,0 +1,26 @@ +// GameViewer.h +// + +#pragma once + +#include +#include + +class gameView_t : public QOpenGLWidget, protected QOpenGLFunctions +{ + Q_OBJECT + + public: + gameView_t(QWidget *parent = 0); + ~gameView_t(void); + + float angle; + + protected: + void initializeGL(void); + void resizeGL(int w, int h); + void paintGL(void); + + private slots: +}; + diff --git a/src/drivers/Qt/config.cpp b/src/drivers/Qt/config.cpp new file mode 100644 index 00000000..4856cbb2 --- /dev/null +++ b/src/drivers/Qt/config.cpp @@ -0,0 +1,485 @@ +#include "main.h" +#include "throttle.h" +#include "config.h" + +#include "../common/cheat.h" + +#include "input.h" +#include "dface.h" + +#include "sdl.h" +#include "sdl-video.h" +#include "unix-netplay.h" + +#ifdef WIN32 +#include +#endif + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +static const char* HotkeyStrings[HK_MAX] = { + "CheatMenu", + "BindState", + "LoadLua", + "ToggleBG", + "SaveState", + "FDSSelect", + "LoadState", + "FDSEject", + "VSInsertCoin", + "VSToggleDip", + "MovieToggleFrameDisplay", + "SubtitleDisplay", + "Reset", + "Screenshot", + "Pause", + "DecreaseSpeed", + "IncreaseSpeed", + "FrameAdvance", + "Turbo", + "ToggleInputDisplay", + "ToggleMovieRW", + "MuteCapture", + "Quit", + "FrameAdvanceLagSkip", + "LagCounterDisplay", + "SelectState0", "SelectState1", "SelectState2", "SelectState3", + "SelectState4", "SelectState5", "SelectState6", "SelectState7", + "SelectState8", "SelectState9", "SelectStateNext", "SelectStatePrev", + "VolumeDown", "VolumeUp" }; + +const char *getHotkeyString( int i ) +{ + if ( (i>=0) && (iaddOption('s', "sound", "SDL.Sound", 1); + config->addOption("volume", "SDL.Sound.Volume", 150); + config->addOption("trianglevol", "SDL.Sound.TriangleVolume", 256); + config->addOption("square1vol", "SDL.Sound.Square1Volume", 256); + config->addOption("square2vol", "SDL.Sound.Square2Volume", 256); + config->addOption("noisevol", "SDL.Sound.NoiseVolume", 256); + config->addOption("pcmvol", "SDL.Sound.PCMVolume", 256); + config->addOption("soundrate", "SDL.Sound.Rate", 44100); + config->addOption("soundq", "SDL.Sound.Quality", 1); + config->addOption("soundrecord", "SDL.Sound.RecordFile", ""); + config->addOption("soundbufsize", "SDL.Sound.BufSize", 128); + config->addOption("lowpass", "SDL.Sound.LowPass", 0); + + config->addOption('g', "gamegenie", "SDL.GameGenie", 0); + config->addOption("pal", "SDL.PAL", 0); + config->addOption("frameskip", "SDL.Frameskip", 0); + config->addOption("clipsides", "SDL.ClipSides", 0); + config->addOption("nospritelim", "SDL.DisableSpriteLimit", 1); + config->addOption("swapduty", "SDL.SwapDuty", 0); + + // color control + config->addOption('p', "palette", "SDL.Palette", ""); + config->addOption("tint", "SDL.Tint", 56); + config->addOption("hue", "SDL.Hue", 72); + config->addOption("ntsccolor", "SDL.NTSCpalette", 0); + + // scanline settings + config->addOption("slstart", "SDL.ScanLineStart", 0); + config->addOption("slend", "SDL.ScanLineEnd", 239); + + // video controls + config->addOption('f', "fullscreen", "SDL.Fullscreen", 0); + + // set x/y res to 0 for automatic fullscreen resolution detection (no change) + config->addOption('x', "xres", "SDL.XResolution", 0); + config->addOption('y', "yres", "SDL.YResolution", 0); + config->addOption("SDL.LastXRes", 0); + config->addOption("SDL.LastYRes", 0); + config->addOption('b', "bpp", "SDL.BitsPerPixel", 32); + config->addOption("doublebuf", "SDL.DoubleBuffering", 1); + config->addOption("autoscale", "SDL.AutoScale", 1); + config->addOption("keepratio", "SDL.KeepRatio", 1); + config->addOption("xscale", "SDL.XScale", 1.0); + config->addOption("yscale", "SDL.YScale", 1.0); + config->addOption("xstretch", "SDL.XStretch", 0); + config->addOption("ystretch", "SDL.YStretch", 0); + config->addOption("noframe", "SDL.NoFrame", 0); + config->addOption("special", "SDL.SpecialFilter", 0); + config->addOption("showfps", "SDL.ShowFPS", 0); + config->addOption("togglemenu", "SDL.ToggleMenu", 0); + + // OpenGL options + config->addOption("opengl", "SDL.OpenGL", 1); + config->addOption("openglip", "SDL.OpenGLip", 1); + config->addOption("SDL.SpecialFilter", 0); + config->addOption("SDL.SpecialFX", 0); + config->addOption("SDL.Vsync", 1); + + // network play options - netplay is broken + config->addOption("server", "SDL.NetworkIsServer", 0); + config->addOption('n', "net", "SDL.NetworkIP", ""); + config->addOption('u', "user", "SDL.NetworkUsername", ""); + config->addOption('w', "pass", "SDL.NetworkPassword", ""); + config->addOption('k', "netkey", "SDL.NetworkGameKey", ""); + config->addOption("port", "SDL.NetworkPort", 4046); + config->addOption("players", "SDL.NetworkPlayers", 1); + + // input configuration options + config->addOption("input1", "SDL.Input.0", "GamePad.0"); + config->addOption("input2", "SDL.Input.1", "GamePad.1"); + config->addOption("input3", "SDL.Input.2", "Gamepad.2"); + config->addOption("input4", "SDL.Input.3", "Gamepad.3"); + + // allow for input configuration + config->addOption('i', "inputcfg", "SDL.InputCfg", InputCfg); + + // display input + config->addOption("inputdisplay", "SDL.InputDisplay", 0); + + // enable / disable opposite directionals (left + right or up + down simultaneously) + config->addOption("opposite-directionals", "SDL.Input.EnableOppositeDirectionals", 1); + + // pause movie playback at frame x + config->addOption("pauseframe", "SDL.PauseFrame", 0); + config->addOption("recordhud", "SDL.RecordHUD", 1); + config->addOption("moviemsg", "SDL.MovieMsg", 1); + + // overwrite the config file? + config->addOption("no-config", "SDL.NoConfig", 0); + + config->addOption("autoresume", "SDL.AutoResume", 0); + + // video playback + config->addOption("playmov", "SDL.Movie", ""); + config->addOption("subtitles", "SDL.SubtitleDisplay", 1); + config->addOption("movielength", "SDL.MovieLength", 0); + + config->addOption("fourscore", "SDL.FourScore", 0); + + config->addOption("nofscursor", "SDL.NoFullscreenCursor", 1); + + #ifdef _S9XLUA_H + // load lua script + config->addOption("loadlua", "SDL.LuaScript", ""); + #endif + + #ifdef CREATE_AVI + config->addOption("videolog", "SDL.VideoLog", ""); + config->addOption("mute", "SDL.MuteCapture", 0); + #endif + + // auto load/save on gameload/close + config->addOption("loadstate", "SDL.AutoLoadState", INVALID_STATE); + config->addOption("savestate", "SDL.AutoSaveState", INVALID_STATE); + + //TODO implement this + config->addOption("periodicsaves", "SDL.PeriodicSaves", 0); + + + #ifdef _GTK + char* home_dir = getenv("HOME"); + // prefixed with _ because they are internal (not cli options) + config->addOption("_lastopenfile", "SDL.LastOpenFile", home_dir); + config->addOption("_laststatefrom", "SDL.LastLoadStateFrom", home_dir); + config->addOption("_lastopennsf", "SDL.LastOpenNSF", home_dir); + config->addOption("_lastsavestateas", "SDL.LastSaveStateAs", home_dir); + config->addOption("_lastloadlua", "SDL.LastLoadLua", ""); + #endif + + // fcm -> fm2 conversion + config->addOption("fcmconvert", "SDL.FCMConvert", ""); + + // fm2 -> srt conversion + config->addOption("ripsubs", "SDL.RipSubs", ""); + + // enable new PPU core + config->addOption("newppu", "SDL.NewPPU", 0); + + // quit when a+b+select+start is pressed + config->addOption("4buttonexit", "SDL.ABStartSelectExit", 0); + + // GamePad 0 - 3 + for(unsigned int i = 0; i < GAMEPAD_NUM_DEVICES; i++) + { + char buf[64]; + snprintf(buf, sizeof(buf)-1, "SDL.Input.GamePad.%u.", i); + prefix = buf; + + config->addOption(prefix + "DeviceType", DefaultGamePadDevice[i]); + config->addOption(prefix + "DeviceNum", 0); + for(unsigned int j = 0; j < GAMEPAD_NUM_BUTTONS; j++) { + config->addOption(prefix + GamePadNames[j], DefaultGamePad[i][j]); + } + } + + // PowerPad 0 - 1 + for(unsigned int i = 0; i < POWERPAD_NUM_DEVICES; i++) { + char buf[64]; + snprintf(buf, sizeof(buf)-1, "SDL.Input.PowerPad.%u.", i); + prefix = buf; + + config->addOption(prefix + "DeviceType", DefaultPowerPadDevice[i]); + config->addOption(prefix + "DeviceNum", 0); + for(unsigned int j = 0; j < POWERPAD_NUM_BUTTONS; j++) { + config->addOption(prefix +PowerPadNames[j], DefaultPowerPad[i][j]); + } + } + + // QuizKing + prefix = "SDL.Input.QuizKing."; + config->addOption(prefix + "DeviceType", DefaultQuizKingDevice); + config->addOption(prefix + "DeviceNum", 0); + for(unsigned int j = 0; j < QUIZKING_NUM_BUTTONS; j++) { + config->addOption(prefix + QuizKingNames[j], DefaultQuizKing[j]); + } + + // HyperShot + prefix = "SDL.Input.HyperShot."; + config->addOption(prefix + "DeviceType", DefaultHyperShotDevice); + config->addOption(prefix + "DeviceNum", 0); + for(unsigned int j = 0; j < HYPERSHOT_NUM_BUTTONS; j++) { + config->addOption(prefix + HyperShotNames[j], DefaultHyperShot[j]); + } + + // Mahjong + prefix = "SDL.Input.Mahjong."; + config->addOption(prefix + "DeviceType", DefaultMahjongDevice); + config->addOption(prefix + "DeviceNum", 0); + for(unsigned int j = 0; j < MAHJONG_NUM_BUTTONS; j++) { + config->addOption(prefix + MahjongNames[j], DefaultMahjong[j]); + } + + // TopRider + prefix = "SDL.Input.TopRider."; + config->addOption(prefix + "DeviceType", DefaultTopRiderDevice); + config->addOption(prefix + "DeviceNum", 0); + for(unsigned int j = 0; j < TOPRIDER_NUM_BUTTONS; j++) { + config->addOption(prefix + TopRiderNames[j], DefaultTopRider[j]); + } + + // FTrainer + prefix = "SDL.Input.FTrainer."; + config->addOption(prefix + "DeviceType", DefaultFTrainerDevice); + config->addOption(prefix + "DeviceNum", 0); + for(unsigned int j = 0; j < FTRAINER_NUM_BUTTONS; j++) { + config->addOption(prefix + FTrainerNames[j], DefaultFTrainer[j]); + } + + // FamilyKeyBoard + prefix = "SDL.Input.FamilyKeyBoard."; + config->addOption(prefix + "DeviceType", DefaultFamilyKeyBoardDevice); + config->addOption(prefix + "DeviceNum", 0); + for(unsigned int j = 0; j < FAMILYKEYBOARD_NUM_BUTTONS; j++) { + config->addOption(prefix + FamilyKeyBoardNames[j], + DefaultFamilyKeyBoard[j]); + } + + // for FAMICOM microphone in pad 2 pad 1 didn't have it + // Takeshi no Chousenjou uses it for example. + prefix = "SDL.Input.FamicomPad2."; + config->addOption("rp2mic", prefix + "EnableMic", 0); + + // TODO: use a better data structure to store the hotkeys or something + // improve this code overall in the future to make it + // easier to maintain + const int Hotkeys[HK_MAX] = { + SDLK_F1, // cheat menu + SDLK_F2, // bind state + SDLK_F3, // load lua + SDLK_F4, // toggleBG + SDLK_F5, // save state + SDLK_F6, // fds select + SDLK_F7, // load state + SDLK_F8, // fds eject + SDLK_F6, // VS insert coin + SDLK_F8, // VS toggle dipswitch + SDLK_PERIOD, // toggle frame display + SDLK_F10, // toggle subtitle + SDLK_F11, // reset + SDLK_F12, // screenshot + SDLK_PAUSE, // pause + SDLK_MINUS, // speed++ + SDLK_EQUALS, // speed-- + SDLK_BACKSLASH, //frame advnace + SDLK_TAB, // turbo + SDLK_COMMA, // toggle input display + SDLK_q, // toggle movie RW + SDLK_QUOTE, // toggle mute capture + 0, // quit // edit 10/11/11 - don't map to escape, it causes ugly things to happen to sdl. can be manually appended to config + SDLK_DELETE, // frame advance lag skip + SDLK_SLASH, // lag counter display + SDLK_0, SDLK_1, SDLK_2, SDLK_3, SDLK_4, SDLK_5, + SDLK_6, SDLK_7, SDLK_8, SDLK_9, + SDLK_PAGEUP, // select state next + SDLK_PAGEDOWN}; // select state prev + + prefix = "SDL.Hotkeys."; + for(int i=0; i < HK_MAX; i++) + config->addOption(prefix + HotkeyStrings[i], Hotkeys[i]); + // All mouse devices + config->addOption("SDL.OekaKids.0.DeviceType", "Mouse"); + config->addOption("SDL.OekaKids.0.DeviceNum", 0); + + config->addOption("SDL.Arkanoid.0.DeviceType", "Mouse"); + config->addOption("SDL.Arkanoid.0.DeviceNum", 0); + + config->addOption("SDL.Shadow.0.DeviceType", "Mouse"); + config->addOption("SDL.Shadow.0.DeviceNum", 0); + + config->addOption("SDL.Zapper.0.DeviceType", "Mouse"); + config->addOption("SDL.Zapper.0.DeviceNum", 0); + + return config; +} + +void +UpdateEMUCore(Config *config) +{ + int ntsccol, ntsctint, ntschue, flag, region, start, end; + std::string cpalette; + + config->getOption("SDL.NTSCpalette", &ntsccol); + config->getOption("SDL.Tint", &ntsctint); + config->getOption("SDL.Hue", &ntschue); + FCEUI_SetNTSCTH(ntsccol, ntsctint, ntschue); + + config->getOption("SDL.Palette", &cpalette); + if(cpalette.size()) { + LoadCPalette(cpalette); + } + + config->getOption("SDL.PAL", ®ion); + FCEUI_SetRegion(region); + + config->getOption("SDL.GameGenie", &flag); + FCEUI_SetGameGenie(flag ? 1 : 0); + + config->getOption("SDL.Sound.LowPass", &flag); + FCEUI_SetLowPass(flag ? 1 : 0); + + config->getOption("SDL.DisableSpriteLimit", &flag); + FCEUI_DisableSpriteLimitation(flag ? 1 : 0); + + config->getOption("SDL.ScanLineStart", &start); + config->getOption("SDL.ScanLineEnd", &end); + +#if DOING_SCANLINE_CHECKS + for(int i = 0; i < 2; x++) { + if(srendlinev[x]<0 || srendlinev[x]>239) srendlinev[x]=0; + if(erendlinev[x]239) erendlinev[x]=239; + } +#endif + + FCEUI_SetRenderedLines(start + 8, end - 8, start, end); +} + diff --git a/src/drivers/Qt/config.h b/src/drivers/Qt/config.h new file mode 100644 index 00000000..dbf6a0b6 --- /dev/null +++ b/src/drivers/Qt/config.h @@ -0,0 +1,28 @@ +#ifndef CONFIG_H_HF128 +#define CONFIG_H_HF128 + +#include "../common/configSys.h" + +Config *InitConfig(void); +void UpdateEMUCore(Config *); +int LoadCPalette(const std::string &file); + +// hotkey definitions +// TODO: encapsulate this in an improved data structure +enum HOTKEY { HK_CHEAT_MENU=0, HK_BIND_STATE, HK_LOAD_LUA, HK_TOGGLE_BG, + HK_SAVE_STATE, HK_FDS_SELECT, HK_LOAD_STATE, HK_FDS_EJECT , + HK_VS_INSERT_COIN, HK_VS_TOGGLE_DIPSWITCH, + HK_TOGGLE_FRAME_DISPLAY, HK_TOGGLE_SUBTITLE, HK_RESET, HK_SCREENSHOT, + HK_PAUSE, HK_DECREASE_SPEED, HK_INCREASE_SPEED, HK_FRAME_ADVANCE, HK_TURBO, + HK_TOGGLE_INPUT_DISPLAY, HK_MOVIE_TOGGLE_RW, HK_MUTE_CAPTURE, HK_QUIT, + HK_FA_LAG_SKIP, HK_LAG_COUNTER_DISPLAY, + HK_SELECT_STATE_0, HK_SELECT_STATE_1, HK_SELECT_STATE_2, HK_SELECT_STATE_3, + HK_SELECT_STATE_4, HK_SELECT_STATE_5, HK_SELECT_STATE_6, HK_SELECT_STATE_7, + HK_SELECT_STATE_8, HK_SELECT_STATE_9, + HK_SELECT_STATE_NEXT, HK_SELECT_STATE_PREV, HK_VOLUME_DOWN, HK_VOLUME_UP, + HK_MAX}; + +const char *getHotkeyString( int i ); + +#endif + diff --git a/src/drivers/Qt/dface.h b/src/drivers/Qt/dface.h new file mode 100644 index 00000000..f753f3ca --- /dev/null +++ b/src/drivers/Qt/dface.h @@ -0,0 +1,37 @@ +#include "../common/args.h" +#include "../common/config.h" + +#include "input.h" + +extern CFGSTRUCT DriverConfig[]; +extern ARGPSTRUCT DriverArgs[]; + +void DoDriverArgs(void); + +int InitSound(); +void WriteSound(int32 *Buffer, int Count); +int KillSound(void); +uint32 GetMaxSound(void); +uint32 GetWriteSound(void); + +void SilenceSound(int s); /* DOS and SDL */ + +int InitJoysticks(void); +int KillJoysticks(void); +uint32 *GetJSOr(void); + +int InitVideo(FCEUGI *gi); +int KillVideo(void); +void BlitScreen(uint8 *XBuf); +void LockConsole(void); +void UnlockConsole(void); +void ToggleFS(); /* SDL */ + +int LoadGame(const char *path); +//int CloseGame(void); + +void Giggles(int); +void DoFun(void); + +int FCEUD_NetworkConnect(void); + diff --git a/src/drivers/Qt/fceuWrapper.cpp b/src/drivers/Qt/fceuWrapper.cpp new file mode 100644 index 00000000..61d7812b --- /dev/null +++ b/src/drivers/Qt/fceuWrapper.cpp @@ -0,0 +1,300 @@ +// fceuWrapper.cpp +// +#include +#include + +#include "main.h" +#include "throttle.h" +#include "config.h" +#include "dface.h" +#include "fceuWrapper.h" +#include "input.h" +#include "sdl-video.h" +#include "unix-netplay.h" + +#include "../common/cheat.h" +#include "../../fceu.h" +#include "../../movie.h" +#include "../../version.h" + +#ifdef _S9XLUA_H +#include "../../fceulua.h" +#endif + +#include "../common/configSys.h" +#include "../../oldmovie.h" +#include "../../types.h" + +#ifdef CREATE_AVI +#include "../videolog/nesvideos-piece.h" +#endif + +//***************************************************************** +// Define Global Variables to be shared with FCEU Core +//***************************************************************** +int dendy = 0; +int eoptions=0; +int isloaded=0; +int pal_emulation=0; +int gametype = 0; +int closeFinishedMovie = 0; +int KillFCEUXonFrame = 0; + +bool swapDuty = 0; +bool turbo = false; +unsigned int gui_draw_area_width = 256; +unsigned int gui_draw_area_height = 256; + +// global configuration object +Config *g_config = NULL; + +static int inited = 0; +static int noconfig=0; + +//***************************************************************** +// Define Global Functions to be shared with FCEU Core +//***************************************************************** +// + +/** +* Prints a textual message without adding a newline at the end. +* +* @param text The text of the message. +* +* TODO: This function should have a better name. +**/ +void FCEUD_Message(const char *text) +{ + fputs(text, stdout); +} + +/** +* Shows an error message in a message box. +* (For now: prints to stderr.) +* +* If running in GTK mode, display a dialog message box of the error. +* +* @param errormsg Text of the error message. +**/ +void FCEUD_PrintError(const char *errormsg) +{ + fprintf(stderr, "%s\n", errormsg); +} + +/** + * Opens a file, C++ style, to be read a byte at a time. + */ +FILE *FCEUD_UTF8fopen(const char *fn, const char *mode) +{ + return(fopen(fn,mode)); +} + +/** + * Opens a file to be read a byte at a time. + */ +EMUFILE_FILE* FCEUD_UTF8_fstream(const char *fn, const char *m) +{ + std::ios_base::openmode mode = std::ios_base::binary; + if(!strcmp(m,"r") || !strcmp(m,"rb")) + mode |= std::ios_base::in; + else if(!strcmp(m,"w") || !strcmp(m,"wb")) + mode |= std::ios_base::out | std::ios_base::trunc; + else if(!strcmp(m,"a") || !strcmp(m,"ab")) + mode |= std::ios_base::out | std::ios_base::app; + else if(!strcmp(m,"r+") || !strcmp(m,"r+b")) + mode |= std::ios_base::in | std::ios_base::out; + else if(!strcmp(m,"w+") || !strcmp(m,"w+b")) + mode |= std::ios_base::in | std::ios_base::out | std::ios_base::trunc; + else if(!strcmp(m,"a+") || !strcmp(m,"a+b")) + mode |= std::ios_base::in | std::ios_base::out | std::ios_base::app; + return new EMUFILE_FILE(fn, m); + //return new std::fstream(fn,mode); +} + +static const char *s_linuxCompilerString = "g++ " __VERSION__; +/** + * Returns the compiler string. + */ +const char *FCEUD_GetCompilerString(void) +{ + return s_linuxCompilerString; +} + +/** + * Get the time in ticks. + */ +uint64 +FCEUD_GetTime(void) +{ + return SDL_GetTicks(); +} + +/** + * Get the tick frequency in Hz. + */ +uint64 +FCEUD_GetTimeFreq(void) +{ + // SDL_GetTicks() is in milliseconds + return 1000; +} + +void FCEUD_DebugBreakpoint( int addr ) +{ + // TODO +} + +/** + * Initialize all of the subsystem drivers: video, audio, and joystick. + */ +static int +DriverInitialize(FCEUGI *gi) +{ + if(InitVideo(gi) < 0) return 0; + inited|=4; + + if(InitSound()) + inited|=1; + + if(InitJoysticks()) + inited|=2; + + int fourscore=0; + g_config->getOption("SDL.FourScore", &fourscore); + eoptions &= ~EO_FOURSCORE; + if(fourscore) + eoptions |= EO_FOURSCORE; + + InitInputInterface(); + return 1; +} + +/** + * Shut down all of the subsystem drivers: video, audio, and joystick. + */ +static void +DriverKill() +{ + if (!noconfig) + g_config->save(); + + if(inited&2) + KillJoysticks(); + if(inited&4) + KillVideo(); + if(inited&1) + KillSound(); + inited=0; +} + +/** + * Loads a game, given a full path/filename. The driver code must be + * initialized after the game is loaded, because the emulator code + * provides data necessary for the driver code(number of scanlines to + * render, what virtual input devices to use, etc.). + */ +int LoadGame(const char *path) +{ + if (isloaded){ + CloseGame(); + } + if(!FCEUI_LoadGame(path, 1)) { + return 0; + } + + int state_to_load; + g_config->getOption("SDL.AutoLoadState", &state_to_load); + if (state_to_load >= 0 && state_to_load < 10){ + FCEUI_SelectState(state_to_load, 0); + FCEUI_LoadState(NULL, false); + } + + ParseGIInput(GameInfo); + RefreshThrottleFPS(); + + if(!DriverInitialize(GameInfo)) { + return(0); + } + + // set pal/ntsc + int id; + g_config->getOption("SDL.PAL", &id); + FCEUI_SetRegion(id); + + g_config->getOption("SDL.SwapDuty", &id); + swapDuty = id; + + std::string filename; + g_config->getOption("SDL.Sound.RecordFile", &filename); + if(filename.size()) { + if(!FCEUI_BeginWaveRecord(filename.c_str())) { + g_config->setOption("SDL.Sound.RecordFile", ""); + } + } + isloaded = 1; + + FCEUD_NetworkConnect(); + return 1; +} + +/** + * Closes a game. Frees memory, and deinitializes the drivers. + */ +int +CloseGame(void) +{ + std::string filename; + + if(!isloaded) { + return(0); + } + + int state_to_save; + g_config->getOption("SDL.AutoSaveState", &state_to_save); + if (state_to_save < 10 && state_to_save >= 0){ + FCEUI_SelectState(state_to_save, 0); + FCEUI_SaveState(NULL, false); + } + FCEUI_CloseGame(); + + DriverKill(); + isloaded = 0; + GameInfo = 0; + + g_config->getOption("SDL.Sound.RecordFile", &filename); + if(filename.size()) { + FCEUI_EndWaveRecord(); + } + + InputUserActiveFix(); + return(1); +} + +// dummy functions + +#define DUMMY(__f) \ + void __f(void) {\ + printf("%s\n", #__f);\ + FCEU_DispMessage("Not implemented.",0);\ + } +DUMMY(FCEUD_HideMenuToggle) +DUMMY(FCEUD_MovieReplayFrom) +DUMMY(FCEUD_ToggleStatusIcon) +DUMMY(FCEUD_AviRecordTo) +DUMMY(FCEUD_AviStop) +void FCEUI_AviVideoUpdate(const unsigned char* buffer) { } +int FCEUD_ShowStatusIcon(void) {return 0;} +bool FCEUI_AviIsRecording(void) {return false;} +void FCEUI_UseInputPreset(int preset) { } +bool FCEUD_PauseAfterPlayback() { return false; } + +void FCEUD_TurboOn (void) { /* TODO */ }; +void FCEUD_TurboOff (void) { /* TODO */ }; +void FCEUD_TurboToggle(void) { /* TODO */ }; + +FCEUFILE* FCEUD_OpenArchiveIndex(ArchiveScanRecord& asr, std::string &fname, int innerIndex) { return 0; } +FCEUFILE* FCEUD_OpenArchive(ArchiveScanRecord& asr, std::string& fname, std::string* innerFilename) { return 0; } +FCEUFILE* FCEUD_OpenArchiveIndex(ArchiveScanRecord& asr, std::string &fname, int innerIndex, int* userCancel) { return 0; } +FCEUFILE* FCEUD_OpenArchive(ArchiveScanRecord& asr, std::string& fname, std::string* innerFilename, int* userCancel) { return 0; } +ArchiveScanRecord FCEUD_ScanArchive(std::string fname) { return ArchiveScanRecord(); } + diff --git a/src/drivers/Qt/fceuWrapper.h b/src/drivers/Qt/fceuWrapper.h new file mode 100644 index 00000000..0c279144 --- /dev/null +++ b/src/drivers/Qt/fceuWrapper.h @@ -0,0 +1,23 @@ +// fceuWrapper.h +// +#include "config.h" + +//***************************************************************** +// Define Global Variables to be shared with FCEU Core +//***************************************************************** +extern int dendy; +extern int eoptions; +extern int isLoaded; +extern int pal_emulation; +extern int gametype; +extern int closeFinishedMovie; +extern bool turbo; +extern bool swapDuty; +extern unsigned int gui_draw_area_width; +extern unsigned int gui_draw_area_height; + +// global configuration object +extern Config *g_config; + +int LoadGame(const char *path); +int CloseGame(void); diff --git a/src/drivers/Qt/gl_win.cpp b/src/drivers/Qt/gl_win.cpp new file mode 100644 index 00000000..111e7fb6 --- /dev/null +++ b/src/drivers/Qt/gl_win.cpp @@ -0,0 +1,54 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "gl_win.h" + +gl_win_shm_t *gl_shm = NULL; + +//************************************************************************ +gl_win_shm_t *open_video_shm(void) +{ + int shmId; + gl_win_shm_t *vaddr; + struct shmid_ds ds; + + shmId = shmget( IPC_PRIVATE, sizeof(struct gl_win_shm_t), IPC_CREAT | S_IRWXU | S_IRWXG ); + + if ( shmId == -1 ) + { + perror("Error: GL shmget Failed:"); + return NULL; + } + printf("Created ShmID: %i \n", shmId ); + + vaddr = (gl_win_shm_t*)shmat( shmId, NULL, 0); + + if ( vaddr == (gl_win_shm_t*)-1 ) + { + perror("Error: GLX shmat Failed:"); + return NULL; + } + memset( vaddr, 0, sizeof(struct gl_win_shm_t)); + + if ( shmctl( shmId, IPC_RMID, &ds ) != 0 ) + { + perror("Error: GLX shmctl IPC_RMID Failed:"); + } + + //sem_init( &vaddr->sem, 1, 1 ); + + vaddr->ncol = 256; + vaddr->nrow = 256; + vaddr->pitch = 256 * 4; + + return vaddr; +} +//************************************************************************ diff --git a/src/drivers/Qt/gl_win.h b/src/drivers/Qt/gl_win.h new file mode 100644 index 00000000..552c70a9 --- /dev/null +++ b/src/drivers/Qt/gl_win.h @@ -0,0 +1,68 @@ +// glxwin.cpp +// + +#ifndef __GLXWIN_H__ +#define __GLXWIN_H__ + +#include + +#define GL_WIN_PIXEL_LINEAR_FILTER 0x0001 +#define GL_WIN_DOUBLE_BUFFER 0x0002 + +#define GL_NES_WIDTH 256 +#define GL_NES_HEIGHT 256 + +struct gl_win_shm_t +{ + int pid; + int run; + uint32_t render_count; + uint32_t blit_count; + + int ncol; + int nrow; + int pitch; + + // Pass Key Events back to QT Gui + struct + { + int head; + int tail; + + struct { + int type; + int keycode; + int state; + } data[64]; + + } keyEventBuf; + + // Gui Command Event Queue + struct + { + int head; + int tail; + + struct { + int id; + + union { + int i32[4]; + float f32[4]; + } param; + } cmd[64]; + } guiEvent; + + uint32_t pixbuf[65536]; // 256 x 256 + + void clear_pixbuf(void) + { + memset( pixbuf, 0, sizeof(pixbuf) ); + } +}; + +extern gl_win_shm_t *gl_shm; + +gl_win_shm_t *open_video_shm(void); + +#endif diff --git a/src/drivers/Qt/input.cpp b/src/drivers/Qt/input.cpp new file mode 100644 index 00000000..d384136f --- /dev/null +++ b/src/drivers/Qt/input.cpp @@ -0,0 +1,2355 @@ +/* FCE Ultra - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2002 Xodnizel + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "main.h" +#include "dface.h" +#include "input.h" +#include "config.h" + + +#include "sdl-video.h" +#include "sdl.h" + +#include "../common/cheat.h" +#include "../../movie.h" +#include "../../fceu.h" +#include "../../driver.h" +#include "../../state.h" +#include "../../utils/xstring.h" +#ifdef _S9XLUA_H +#include "../../fceulua.h" +#endif + +#include +#include + +/** GLOBALS **/ +int NoWaiting = 0; +extern Config *g_config; +extern bool bindSavestate, frameAdvanceLagSkip, lagCounterDisplay; + + +/* UsrInputType[] is user-specified. CurInputType[] is current + (game loading can override user settings) +*/ +static int UsrInputType[NUM_INPUT_DEVICES]; +static int CurInputType[NUM_INPUT_DEVICES]; +static int cspec = 0; + +extern int gametype; + +/** + * Necessary for proper GUI functioning (configuring when a game isn't loaded). + */ +void +InputUserActiveFix () +{ + int x; + for (x = 0; x < 3; x++) + { + CurInputType[x] = UsrInputType[x]; + } +} + +/** + * Parse game information and configure the input devices accordingly. + */ +void +ParseGIInput (FCEUGI * gi) +{ + gametype = gi->type; + + CurInputType[0] = UsrInputType[0]; + CurInputType[1] = UsrInputType[1]; + CurInputType[2] = UsrInputType[2]; + + if (gi->input[0] >= 0) + { + CurInputType[0] = gi->input[0]; + } + if (gi->input[1] >= 0) + { + CurInputType[1] = gi->input[1]; + } + if (gi->inputfc >= 0) + { + CurInputType[2] = gi->inputfc; + } + cspec = gi->cspecial; +} + + +static uint8 QuizKingData = 0; +static uint8 HyperShotData = 0; +static uint32 MahjongData = 0; +static uint32 FTrainerData = 0; +static uint8 TopRiderData = 0; +static uint8 BWorldData[1 + 13 + 1]; + +static void UpdateFKB (void); +static void UpdateGamepad (void); +static void UpdateQuizKing (void); +static void UpdateHyperShot (void); +static void UpdateMahjong (void); +static void UpdateFTrainer (void); +static void UpdateTopRider (void); + +static uint32 JSreturn = 0; + +/** + * Configure cheat devices (game genie, etc.). Restarts the keyboard + * and video subsystems. + */ +static void +DoCheatSeq () +{ + SilenceSound (1); + KillVideo (); + + DoConsoleCheatConfig (); + InitVideo (GameInfo); + SilenceSound (0); +} + +#include "keyscan.h" +static uint8 g_keyState[SDL_NUM_SCANCODES]; +static int DIPS = 0; + +static uint8 keyonce[SDL_NUM_SCANCODES]; +#define KEY(__a) g_keyState[MKK(__a)] + +int getKeyState( int k ) +{ + if ( (k >= 0) && (k < SDL_NUM_SCANCODES) ) + { + return g_keyState[k]; + } + return 0; +} + +static int +_keyonly (int a) +{ + int sc; + + if ( a < 0 ) + { + return 0; + } + + sc = SDL_GetScancodeFromKey(a); + + // check for valid key + if (sc >= SDL_NUM_SCANCODES || sc < 0) + { + return 0; + } + + if (g_keyState[sc]) + { + if (!keyonce[sc]) + { + keyonce[sc] = 1; + return 1; + } + } + else + { + keyonce[sc] = 0; + } + return 0; +} + +#define keyonly(__a) _keyonly(MKK(__a)) + +static int g_fkbEnabled = 0; + +// this function loads the sdl hotkeys from the config file into the +// global scope. this elimates the need for accessing the config file + +int Hotkeys[HK_MAX] = { 0 }; + +// on every cycle of keyboardinput() +void +setHotKeys (void) +{ + std::string prefix = "SDL.Hotkeys."; + for (int i = 0; i < HK_MAX; i++) + { + g_config->getOption (prefix + getHotkeyString(i), &Hotkeys[i]); + } + return; +} + +/*** + * This function is a wrapper for FCEUI_ToggleEmulationPause that handles + * releasing/capturing mouse pointer during pause toggles + * */ +void +TogglePause () +{ + FCEUI_ToggleEmulationPause (); + + int no_cursor; + g_config->getOption("SDL.NoFullscreenCursor", &no_cursor); + int fullscreen; + g_config->getOption ("SDL.Fullscreen", &fullscreen); + + return; +} + +/*** + * This function opens a file chooser dialog and returns the filename the + * user selected. + * */ +std::string GetFilename (const char *title, bool save, const char *filter) +{ + if (FCEUI_EmulationPaused () == 0) + FCEUI_ToggleEmulationPause (); + std::string fname = ""; + +#ifdef WIN32 + OPENFILENAME ofn; // common dialog box structure + char szFile[260]; // buffer for file name + HWND hwnd; // owner window + HANDLE hf; // file handle + + // Initialize OPENFILENAME + memset (&ofn, 0, sizeof (ofn)); + ofn.lStructSize = sizeof (ofn); + ofn.hwndOwner = hwnd; + ofn.lpstrFile = szFile; + // Set lpstrFile[0] to '\0' so that GetOpenFileName does not + // use the contents of szFile to initialize itself. + ofn.lpstrFile[0] = '\0'; + ofn.nMaxFile = sizeof (szFile); + ofn.lpstrFilter = "All\0*.*\0"; + ofn.nFilterIndex = 1; + ofn.lpstrFileTitle = NULL; + ofn.nMaxFileTitle = 0; + ofn.lpstrInitialDir = NULL; + ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST; + + // Display the Open dialog box. + fname = GetOpenFileName (&ofn); + +#endif +#ifdef _GTK + int fullscreen = 0; + g_config->getOption ("SDL.Fullscreen", &fullscreen); + if (fullscreen) + ToggleFS (); + + GtkWidget *fileChooser; + + GtkFileFilter *filterX; + GtkFileFilter *filterAll; + + filterX = gtk_file_filter_new (); + gtk_file_filter_add_pattern (filterX, filter); + gtk_file_filter_set_name (filterX, filter); + + + filterAll = gtk_file_filter_new (); + gtk_file_filter_add_pattern (filterAll, "*"); + gtk_file_filter_set_name (filterAll, "All Files"); + + if (save) + fileChooser = gtk_file_chooser_dialog_new ("Save as", NULL, + GTK_FILE_CHOOSER_ACTION_SAVE, + "_Cancel", + GTK_RESPONSE_CANCEL, + "_Save", + GTK_RESPONSE_ACCEPT, NULL); + else + fileChooser = gtk_file_chooser_dialog_new ("Open", NULL, + GTK_FILE_CHOOSER_ACTION_OPEN, + "_Cancel", + GTK_RESPONSE_CANCEL, + "_Open", + GTK_RESPONSE_ACCEPT, NULL); + + // TODO: make file filters case insensitive + //gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(fileChooser), filterX); + gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (fileChooser), filterAll); + int response = gtk_dialog_run (GTK_DIALOG (fileChooser)); + + // flush gtk events + while (gtk_events_pending ()) + gtk_main_iteration_do (TRUE); + + if (response == GTK_RESPONSE_ACCEPT) + fname = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (fileChooser)); + + gtk_widget_destroy (fileChooser); + + while (gtk_events_pending ()) + gtk_main_iteration_do (TRUE); +#endif + FCEUI_ToggleEmulationPause (); + return fname; +} + +/** + * This function opens a text entry dialog and returns the user's input + */ +std::string GetUserText (const char *title) +{ +#ifdef _GTK +/* prg318 - 10/13/11 - this is broken in recent build and causes + * segfaults/very weird behavior i'd rather remove it for now than it cause + * accidental segfaults + * TODO fix it +*/ +#if 0 + + GtkWidget* d; + GtkWidget* entry; + + d = gtk_dialog_new_with_buttons(title, NULL, GTK_DIALOG_MODAL, GTK_STOCK_OK, GTK_RESPONSE_OK); + + entry = gtk_entry_new(); + + GtkWidget* vbox = gtk_dialog_get_content_area(GTK_DIALOG(d)); + + gtk_container_add(GTK_CONTAINER(vbox), entry); + + gtk_widget_show_all(d); + + gtk_dialog_run(GTK_DIALOG(d)); + + // flush gtk events + while(gtk_events_pending()) + gtk_main_iteration_do(TRUE); + + std::string input = gtk_entry_get_text(GTK_ENTRY(entry)); + + if (FCEUI_EmulationPaused() == 0) + FCEUI_ToggleEmulationPause(); // pause emulation + + int fullscreen = 0; + g_config->getOption("SDL.Fullscreen", &fullscreen); + if(fullscreen) + ToggleFS(); // disable fullscreen emulation + + FILE *fpipe; + std::string command = "zenity --entry --title=\""; + command.append(title); + command.append("\" --text=\""); + command.append(title); + command.append(":\""); + + if (!(fpipe = (FILE*)popen(command.c_str(),"r"))) // If fpipe is NULL + FCEUD_PrintError("Pipe error on opening zenity"); + int c; + std::string input; + while((c = fgetc(fpipe))) + { + if (c == EOF || c == '\n') + break; + input += c; + } + pclose(fpipe); + gtk_widget_destroy(d); + + + while(gtk_events_pending()) + gtk_main_iteration_do(TRUE); + + FCEUI_ToggleEmulationPause(); // unpause emulation + return input; +#endif // #if 0 +#endif + return ""; +} + + +/** +* Lets the user start a new .fm2 movie file +**/ +void FCEUD_MovieRecordTo () +{ + std::string fname = GetFilename ("Save FM2 movie for recording", true, "FM2 movies|*.fm2"); + if (!fname.size ()) + return; // no filename selected, quit the whole thing + std::wstring author = mbstowcs (GetUserText ("Author name")); // the author can be empty, so no need to check here + + FCEUI_SaveMovie (fname.c_str (), MOVIE_FLAG_FROM_POWERON, author); +} + + +/** +* Lets the user save a savestate to a specific file +**/ +void FCEUD_SaveStateAs () +{ + std::string fname = GetFilename ("Save savestate as...", true, "Savestates|*.fc0"); + if (!fname.size ()) + return; // no filename selected, quit the whole thing + + FCEUI_SaveState (fname.c_str ()); +} + +/** +* Lets the user load a savestate from a specific file +*/ +void FCEUD_LoadStateFrom () +{ + std::string fname = GetFilename ("Load savestate from...", false, "Savestates|*.fc?"); + if (!fname.size ()) + return; // no filename selected, quit the whole thing + + FCEUI_LoadState (fname.c_str ()); +} + +/** +* Hook for transformer board +*/ +unsigned int *GetKeyboard(void) +{ + int size = 256; + + Uint8* keystate = (Uint8*)SDL_GetKeyboardState(&size); + + return (unsigned int*)(keystate); +} + +/** + * Parse keyboard commands and execute accordingly. + */ +static void KeyboardCommands (void) +{ + int is_shift, is_alt; + + // get the keyboard input + + // check if the family keyboard is enabled + if (CurInputType[2] == SIFC_FKB) + { + if ( g_keyState[SDL_SCANCODE_SCROLLLOCK] ) + { + g_fkbEnabled ^= 1; + FCEUI_DispMessage ("Family Keyboard %sabled.", 0, + g_fkbEnabled ? "en" : "dis"); + } + if (g_fkbEnabled) + { + return; + } + } + + if (g_keyState[SDL_SCANCODE_LSHIFT] || g_keyState[SDL_SCANCODE_RSHIFT]) + { + is_shift = 1; + } + else + { + is_shift = 0; + } + + if (g_keyState[SDL_SCANCODE_LALT] || g_keyState[SDL_SCANCODE_RALT]) + { + is_alt = 1; + } + else + { + is_alt = 0; + } + + + if (_keyonly (Hotkeys[HK_TOGGLE_BG])) + { + if (is_shift) + { + FCEUI_SetRenderPlanes (true, false); + } + else + { + FCEUI_SetRenderPlanes (true, true); + } + } + + // Alt-Enter to toggle full-screen + // This is already handled by GTK Accelerator + //if (keyonly (ENTER) && is_alt) + //{ + // ToggleFS (); + //} + // + + // Alt-M to toggle Main Menu Visibility + //if ( is_alt ) + //{ + // if (keyonly (M)) + // { + // toggleMenuVis(); // TODO + // } + //} + + // Toggle Movie auto-backup + if ( is_shift ) + { + if (keyonly (M)) + { + autoMovieBackup ^= 1; + FCEUI_DispMessage ("Automatic movie backup %sabled.", 0, + autoMovieBackup ? "en" : "dis"); + } + } + + if ( is_alt ) + { + // Start recording an FM2 movie on Alt+R + if (keyonly (R)) + { + FCEUD_MovieRecordTo (); + } + // Save a state from a file + if (keyonly (S)) + { + FCEUD_SaveStateAs (); + } + // Load a state from a file + if (keyonly (L)) + { + FCEUD_LoadStateFrom (); + } + } + + // Famicom disk-system games + if (gametype == GIT_FDS) + { + if (_keyonly (Hotkeys[HK_FDS_SELECT])) + { + FCEUI_FDSSelect (); + } + if (_keyonly (Hotkeys[HK_FDS_EJECT])) + { + FCEUI_FDSInsert (); + } + } + + if (_keyonly (Hotkeys[HK_SCREENSHOT])) + { + FCEUI_SaveSnapshot (); + } + + // if not NES Sound Format + if (gametype != GIT_NSF) + { + if (_keyonly (Hotkeys[HK_CHEAT_MENU])) + { + DoCheatSeq (); + } + + // f5 (default) save key, hold shift to save movie + if (_keyonly (Hotkeys[HK_SAVE_STATE])) + { + if (is_shift) + { + std::string movie_fname = FCEU_MakeFName (FCEUMKF_MOVIE, 0, 0); + FCEUI_printf ("Recording movie to %s\n", movie_fname.c_str() ); + FCEUI_SaveMovie(movie_fname.c_str() , MOVIE_FLAG_NONE, L""); + } + else + { + FCEUI_SaveState (NULL); + } + } + + // f7 to load state, Shift-f7 to load movie + if (_keyonly (Hotkeys[HK_LOAD_STATE])) + { + if (is_shift) + { + FCEUI_StopMovie (); + std::string fname; + fname = + GetFilename ("Open FM2 movie for playback...", false, + "FM2 movies|*.fm2"); + if (fname != "") + { + if (fname.find (".fm2") != std::string::npos + || fname.find (".fm3") != std::string::npos) + { + FCEUI_printf ("Playing back movie located at %s\n", + fname.c_str ()); + FCEUI_LoadMovie (fname.c_str (), false, false); + } + else + { + FCEUI_printf + ("Only .fm2 and .fm3 movies are supported.\n"); + } + } + } + else + { + FCEUI_LoadState(NULL); + } + } + } + + + if (_keyonly (Hotkeys[HK_DECREASE_SPEED])) + { + DecreaseEmulationSpeed (); + } + + if (_keyonly (Hotkeys[HK_INCREASE_SPEED])) + { + IncreaseEmulationSpeed (); + } + + if (_keyonly (Hotkeys[HK_TOGGLE_FRAME_DISPLAY])) + { + FCEUI_MovieToggleFrameDisplay (); + } + + if (_keyonly (Hotkeys[HK_TOGGLE_INPUT_DISPLAY])) + { + FCEUI_ToggleInputDisplay (); + extern int input_display; + g_config->setOption ("SDL.InputDisplay", input_display); + } + + if (_keyonly (Hotkeys[HK_MOVIE_TOGGLE_RW])) + { + FCEUI_SetMovieToggleReadOnly (!FCEUI_GetMovieToggleReadOnly ()); + } + +#ifdef CREATE_AVI + if (_keyonly (Hotkeys[HK_MUTE_CAPTURE])) + { + extern int mutecapture; + mutecapture ^= 1; + } +#endif + + if (_keyonly (Hotkeys[HK_PAUSE])) + { + //FCEUI_ToggleEmulationPause(); + // use the wrapper function instead of the fceui function directly + // so we can handle cursor grabbage + TogglePause (); + } + + // Toggle throttling + if ( _keyonly(Hotkeys[HK_TURBO]) ) + { + NoWaiting ^= 1; + //printf("NoWaiting: 0x%04x\n", NoWaiting ); + } + + static bool frameAdvancing = false; + if ( _keyonly(Hotkeys[HK_FRAME_ADVANCE])) + { + if (frameAdvancing == false) + { + FCEUI_FrameAdvance (); + frameAdvancing = true; + } + } + else + { + if (frameAdvancing) + { + FCEUI_FrameAdvanceEnd (); + frameAdvancing = false; + } + } + + if (_keyonly (Hotkeys[HK_RESET])) + { + FCEUI_ResetNES (); + } + //if(_keyonly(Hotkeys[HK_POWER])) { + // FCEUI_PowerNES(); + //} + if (_keyonly (Hotkeys[HK_QUIT])) + { + CloseGame(); + FCEUI_Kill(); + SDL_Quit(); + exit(0); + } + else +#ifdef _S9XLUA_H + if (_keyonly (Hotkeys[HK_LOAD_LUA])) + { + std::string fname; + fname = GetFilename ("Open LUA script...", false, "Lua scripts|*.lua"); + if (fname != "") + FCEU_LoadLuaCode (fname.c_str ()); + } +#endif + + for (int i = 0; i < 10; i++) + { + if (_keyonly (Hotkeys[HK_SELECT_STATE_0 + i])) + { +#ifdef _GTK + setStateMenuItem(i); +#endif + FCEUI_SelectState (i, 1); + } + } + + if (_keyonly (Hotkeys[HK_SELECT_STATE_NEXT])) + { + FCEUI_SelectStateNext (1); +#ifdef _GTK + setStateMenuItem( CurrentState ); +#endif + } + + if (_keyonly (Hotkeys[HK_SELECT_STATE_PREV])) + { + FCEUI_SelectStateNext (-1); +#ifdef _GTK + setStateMenuItem( CurrentState ); +#endif + } + + if (_keyonly (Hotkeys[HK_BIND_STATE])) + { + bindSavestate ^= 1; + FCEUI_DispMessage ("Savestate binding to movie %sabled.", 0, + bindSavestate ? "en" : "dis"); + } + + if (_keyonly (Hotkeys[HK_FA_LAG_SKIP])) + { + frameAdvanceLagSkip ^= 1; + FCEUI_DispMessage ("Skipping lag in Frame Advance %sabled.", 0, + frameAdvanceLagSkip ? "en" : "dis"); + } + + if (_keyonly (Hotkeys[HK_LAG_COUNTER_DISPLAY])) + { + lagCounterDisplay ^= 1; + } + + if (_keyonly (Hotkeys[HK_TOGGLE_SUBTITLE])) + { + extern int movieSubtitles; + movieSubtitles ^= 1; + FCEUI_DispMessage ("Movie subtitles o%s.", 0, + movieSubtitles ? "n" : "ff"); + } + + if (_keyonly (Hotkeys[HK_VOLUME_DOWN])) + { + FCEUD_SoundVolumeAdjust(-1); + } + + if (_keyonly (Hotkeys[HK_VOLUME_UP])) + { + FCEUD_SoundVolumeAdjust(1); + } + + // VS Unisystem games + if (gametype == GIT_VSUNI) + { + // insert coin + if (_keyonly (Hotkeys[HK_VS_INSERT_COIN])) + FCEUI_VSUniCoin (); + + // toggle dipswitch display + if (_keyonly (Hotkeys[HK_VS_TOGGLE_DIPSWITCH])) + { + DIPS ^= 1; + FCEUI_VSUniToggleDIPView (); + } + if (!(DIPS & 1)) + goto DIPSless; + + // toggle the various dipswitches + for(int i=1; i<=8;i++) + { + if(keyonly(i)) + FCEUI_VSUniToggleDIP(i-1); + } + } + else + { + static uint8 bbuf[32]; + static int bbuft; + static int barcoder = 0; + + if (keyonly (H)) + FCEUI_NTSCSELHUE (); + if (keyonly (T)) + FCEUI_NTSCSELTINT (); + + if (_keyonly (Hotkeys[HK_DECREASE_SPEED])) + FCEUI_NTSCDEC (); + if (_keyonly (Hotkeys[HK_INCREASE_SPEED])) + FCEUI_NTSCINC (); + + if ((CurInputType[2] == SIFC_BWORLD) || (cspec == SIS_DATACH)) + { + if (keyonly (F8)) + { + barcoder ^= 1; + if (!barcoder) + { + if (CurInputType[2] == SIFC_BWORLD) + { + strcpy ((char *) &BWorldData[1], (char *) bbuf); + BWorldData[0] = 1; + } + else + { + FCEUI_DatachSet (bbuf); + } + FCEUI_DispMessage ("Barcode Entered", 0); + } + else + { + bbuft = 0; + FCEUI_DispMessage ("Enter Barcode", 0); + } + } + } + else + { + barcoder = 0; + } + +#define SSM(x) \ +do { \ + if(barcoder) { \ + if(bbuft < 13) { \ + bbuf[bbuft++] = '0' + x; \ + bbuf[bbuft] = 0; \ + } \ + FCEUI_DispMessage("Barcode: %s",0, bbuf); \ + } \ +} while(0) + + DIPSless: + for(int i=0; i<10;i++) + { + if (keyonly (i)) + SSM (i); + } +#undef SSM + } +} + +/** + * Return the state of the mouse buttons. Input 'd' is an array of 3 + * integers that store . + */ +void // removed static for a call in lua-engine.cpp +GetMouseData (uint32 (&d)[3]) +{ + int x, y; + uint32 t; + + // retrieve the state of the mouse from SDL + t = SDL_GetMouseState (&x, &y); + + d[2] = 0; + if (t & SDL_BUTTON (1)) + { + d[2] |= 0x1; + } + if (t & SDL_BUTTON (3)) + { + d[2] |= 0x2; + } + + // get the mouse position from the SDL video driver + t = PtoV (x, y); + d[0] = t & 0xFFFF; + d[1] = (t >> 16) & 0xFFFF; + // debug print + // printf("mouse %d %d %d\n", d[0], d[1], d[2]); +} + +void GetMouseRelative (int32 (&d)[3]) +{ + // converts absolute mouse positions to relative ones for input devices that require this + + // The windows version additionally in fullscreen will constantly return the mouse to center screen + // after reading it, so that the user can endlessly keep moving the mouse. + // The same should eventually be implemented here, but this version should minimally provide + // the necessary relative input, piggybacking on the already implemented GetMouseData. + + static int cx = -1; + static int cy = -1; + + uint32 md[3]; + GetMouseData (md); + + if (cx < 0 || cy < 0) + { + cx = md[0]; + cy = md[1]; + } + + int dx = md[0] - cx; + int dy = md[1] - cy; + + d[0] = dx; + d[1] = dy; + d[2] = md[2]; // buttons +} + +//static void checkKeyBoardState( int scanCode ) +//{ +// printf("Key State is: %i \n", g_keyState[ scanCode ] ); +//} +/** + * Handles outstanding SDL events. + */ +static void +UpdatePhysicalInput () +{ + SDL_Event event; + + // loop, handling all pending events + while (SDL_PollEvent (&event)) + { + switch (event.type) + { + case SDL_QUIT: + CloseGame (); + puts ("Quit"); + break; + case SDL_FCEU_HOTKEY_EVENT: + switch (event.user.code) + { + case HK_PAUSE: + TogglePause (); + break; + default: + FCEU_printf ("Warning: unknown hotkey event %d\n", + event.user.code); + } + break; + case SDL_KEYDOWN: + case SDL_KEYUP: + //printf("SDL_Event.type: %i Keysym: %i ScanCode: %i\n", + // event.type, event.key.keysym.sym, event.key.keysym.scancode ); + + g_keyState[ event.key.keysym.scancode ] = (event.type == SDL_KEYDOWN) ? 1 : 0; + //checkKeyBoardState( event.key.keysym.scancode ); + break; + default: + break; + } + } + //SDL_PumpEvents(); +} + + +static int bcpv, bcpj; + +/** + * Begin configuring the buttons by placing the video and joystick + * subsystems into a well-known state. Button configuration really + * needs to be cleaned up after the new config system is in place. + */ +int ButtonConfigBegin () +{ + // shut down the joystick subsystems + //SDL_Surface *screen; + + bcpj = KillJoysticks (); + + // XXX soules - why did we shut this down? + // initialize the joystick subsystem + InitJoysticks (); + + return 1; +} + +/** + * Finish configuring the buttons by reverting the video and joystick + * subsystems to their previous state. Button configuration really + * needs to be cleaned up after the new config system is in place. + */ +void +ButtonConfigEnd () +{ + // shutdown the joystick and video subsystems + KillJoysticks (); + //SDL_QuitSubSystem(SDL_INIT_VIDEO); + + // re-initialize joystick and video subsystems if they were active before + /*if(!bcpv) { + InitVideo(GameInfo); + } */ + if (!bcpj) + { + InitJoysticks (); + } +} + +/** + * Tests to see if a specified button is currently pressed. + */ +static int +DTestButton (ButtConfig * bc) +{ + int x; + + for (x = 0; x < bc->NumC; x++) + { + if (bc->ButtType[x] == BUTTC_KEYBOARD) + { + if (g_keyState[SDL_GetScancodeFromKey (bc->ButtonNum[x])]) + { + return 1; + } + } + else if (bc->ButtType[x] == BUTTC_JOYSTICK) + { + if (DTestButtonJoy (bc)) + { + return 1; + } + } + } + return 0; +} + + +#define MK(x) {{BUTTC_KEYBOARD},{0},{MKK(x)},1} +#define MK2(x1,x2) {{BUTTC_KEYBOARD},{0},{MKK(x1),MKK(x2)},2} +#define MKZ() {{0},{0},{0},0} +#define GPZ() {MKZ(), MKZ(), MKZ(), MKZ()} + +ButtConfig GamePadConfig[4][10] = { +/* Gamepad 1 */ + {MK (KP_3), MK (KP_2), MK (SLASH), MK (ENTER), + MK (W), MK (Z), MK (A), MK (S), MKZ (), MKZ ()}, + + /* Gamepad 2 */ + GPZ (), + + /* Gamepad 3 */ + GPZ (), + + /* Gamepad 4 */ + GPZ () +}; + +/** + * Update the status of the gamepad input devices. + */ +static void +UpdateGamepad(void) +{ + // don't update during movie playback + if (FCEUMOV_Mode (MOVIEMODE_PLAY)) + { + return; + } + + static int rapid = 0; + uint32 JS = 0; + int x; + int wg; + + rapid ^= 1; + + int opposite_dirs; + g_config->getOption("SDL.Input.EnableOppositeDirectionals", &opposite_dirs); + + // go through each of the four game pads + for (wg = 0; wg < 4; wg++) + { + bool left = false; + bool up = false; + // a, b, select, start, up, down, left, right + for (x = 0; x < 8; x++) + { + if (DTestButton (&GamePadConfig[wg][x])) + { + //printf("GamePad%i Button Hit: %i \n", wg, x ); + if(opposite_dirs == 0) + { + // test for left+right and up+down + if(x == 4){ + up = true; + } + if((x == 5) && (up == true)){ + continue; + } + if(x == 6){ + left = true; + } + if((x == 7) && (left == true)){ + continue; + } + } + JS |= (1 << x) << (wg << 3); + } + } + + int four_button_exit; + g_config->getOption("SDL.ABStartSelectExit", &four_button_exit); + // if a+b+start+select is pressed, exit + if (four_button_exit && JS == 15) { + FCEUI_printf("all buttons pressed, exiting\n"); + CloseGame(); + FCEUI_Kill(); + exit(0); + } + + // rapid-fire a, rapid-fire b + if (rapid) + { + for (x = 0; x < 2; x++) + { + if (DTestButton (&GamePadConfig[wg][8 + x])) + { + JS |= (1 << x) << (wg << 3); + } + } + } + } + +// for(x=0;x<32;x+=8) /* Now, test to see if anything weird(up+down at same time) +// is happening, and correct */ +// { +// if((JS & (0xC0<ButtType[which]) + { + case BUTTC_KEYBOARD: + return SDL_GetKeyName (bc->ButtonNum[which]); + break; + case BUTTC_JOYSTICK: + { + int joyNum, inputNum; + const char *inputType, *inputDirection; + + joyNum = bc->DeviceNum[which]; + + if (bc->ButtonNum[which] & 0x8000) + { + inputType = "Axis"; + inputNum = bc->ButtonNum[which] & 0x3FFF; + inputDirection = bc->ButtonNum[which] & 0x4000 ? "-" : "+"; + } + else if (bc->ButtonNum[which] & 0x2000) + { + int inputValue; + char direction[128] = ""; + + inputType = "Hat"; + inputNum = (bc->ButtonNum[which] >> 8) & 0x1F; + inputValue = bc->ButtonNum[which] & 0xF; + + if (inputValue & SDL_HAT_UP) + strncat (direction, "Up ", sizeof (direction)-1); + if (inputValue & SDL_HAT_DOWN) + strncat (direction, "Down ", sizeof (direction)-1); + if (inputValue & SDL_HAT_LEFT) + strncat (direction, "Left ", sizeof (direction)-1); + if (inputValue & SDL_HAT_RIGHT) + strncat (direction, "Right ", sizeof (direction)-1); + + if (direction[0]) + inputDirection = direction; + else + inputDirection = "Center"; + } + else + { + inputType = "Button"; + inputNum = bc->ButtonNum[which]; + inputDirection = ""; + } + sprintf( name, "js%i:%s%i%s", joyNum, inputType, inputNum, inputDirection ); + } + break; + } + + return name; +} + +/** + * Waits for a button input and returns the information as to which + * button was pressed. Used in button configuration. + */ +int DWaitButton (const uint8 * text, ButtConfig * bc, int wb, int *buttonConfigStatus ) +{ + SDL_Event event; + static int32 LastAx[64][64]; + int x, y; + + if (text) + { + std::string title = "Press a key for "; + title += (const char *) text; + // TODO - SDL2 + //SDL_WM_SetCaption (title.c_str (), 0); + puts ((const char *) text); + } + + for (x = 0; x < 64; x++) + { + for (y = 0; y < 64; y++) + { + LastAx[x][y] = 0x100000; + } + } + + while (1) + { + int done = 0; +#ifdef _GTK + while (gtk_events_pending ()) + gtk_main_iteration_do (FALSE); +#endif + while (SDL_PollEvent (&event)) + { + done++; + switch (event.type) + { + case SDL_KEYDOWN: + bc->ButtType[wb] = BUTTC_KEYBOARD; + bc->DeviceNum[wb] = 0; + bc->ButtonNum[wb] = event.key.keysym.sym; + return (1); + case SDL_JOYBUTTONDOWN: + bc->ButtType[wb] = BUTTC_JOYSTICK; + bc->DeviceNum[wb] = event.jbutton.which; + bc->ButtonNum[wb] = event.jbutton.button; + return (1); + case SDL_JOYHATMOTION: + if (event.jhat.value == SDL_HAT_CENTERED) + done--; + else + { + bc->ButtType[wb] = BUTTC_JOYSTICK; + bc->DeviceNum[wb] = event.jhat.which; + bc->ButtonNum[wb] = + (0x2000 | ((event.jhat.hat & 0x1F) << 8) | event. + jhat.value); + return (1); + } + break; + case SDL_JOYAXISMOTION: + if (LastAx[event.jaxis.which][event.jaxis.axis] == 0x100000) + { + if (abs (event.jaxis.value) < 1000) + { + LastAx[event.jaxis.which][event.jaxis.axis] = + event.jaxis.value; + } + done--; + } + else + { + if (abs + (LastAx[event.jaxis.which][event.jaxis.axis] - + event.jaxis.value) >= 8192) + { + bc->ButtType[wb] = BUTTC_JOYSTICK; + bc->DeviceNum[wb] = event.jaxis.which; + bc->ButtonNum[wb] = (0x8000 | event.jaxis.axis | + ((event.jaxis.value < 0) + ? 0x4000 : 0)); + return (1); + } + else + done--; + } + break; + default: + done--; + } + } + if (done) + break; + + // If the button config window is Closed, + // get out of loop. + if ( buttonConfigStatus != NULL ) + { + if ( *buttonConfigStatus == 0 ) + { + break; + } + } + } + + return (0); +} + +/** + * This function takes in button inputs until either it sees two of + * the same button presses in a row or gets four inputs and then saves + * the total number of button presses. Each of the keys pressed is + * used as input for the specified button, thus allowing up to four + * possible settings for each input button. + */ + void +ConfigButton (char *text, ButtConfig * bc) +{ + uint8 buf[256]; + int wc; + + for (wc = 0; wc < MAXBUTTCONFIG; wc++) + { + sprintf ((char *) buf, "%s (%d)", text, wc + 1); + DWaitButton (buf, bc, wc, NULL); + + if (wc && + bc->ButtType[wc] == bc->ButtType[wc - 1] && + bc->DeviceNum[wc] == bc->DeviceNum[wc - 1] && + bc->ButtonNum[wc] == bc->ButtonNum[wc - 1]) + { + break; + } + } + bc->NumC = wc; +} + +/** + * Update the button configuration for a specified device. + */ +extern Config *g_config; + +void ConfigDevice (int which, int arg) +{ + char buf[256]; + int x; + std::string prefix; + const char *str[10] = + { "A", "B", "SELECT", "START", "UP", "DOWN", "LEFT", "RIGHT", "Rapid A", + "Rapid B" + }; + + // XXX soules - set the configuration options so that later calls + // don't override these. This is a temp hack until I + // can clean up this file. + + ButtonConfigBegin (); + switch (which) + { + case FCFGD_QUIZKING: + prefix = "SDL.Input.QuizKing."; + for (x = 0; x < 6; x++) + { + sprintf (buf, "Quiz King Buzzer #%d", x + 1); + ConfigButton (buf, &QuizKingButtons[x]); + + g_config->setOption (prefix + QuizKingNames[x], + QuizKingButtons[x].ButtonNum[0]); + } + + if (QuizKingButtons[0].ButtType[0] == BUTTC_KEYBOARD) + { + g_config->setOption (prefix + "DeviceType", "Keyboard"); + } + else if (QuizKingButtons[0].ButtType[0] == BUTTC_JOYSTICK) + { + g_config->setOption (prefix + "DeviceType", "Joystick"); + } + else + { + g_config->setOption (prefix + "DeviceType", "Unknown"); + } + g_config->setOption (prefix + "DeviceNum", + QuizKingButtons[0].DeviceNum[0]); + break; + case FCFGD_HYPERSHOT: + prefix = "SDL.Input.HyperShot."; + for (x = 0; x < 4; x++) + { + sprintf (buf, "Hyper Shot %d: %s", + ((x & 2) >> 1) + 1, (x & 1) ? "JUMP" : "RUN"); + ConfigButton (buf, &HyperShotButtons[x]); + + g_config->setOption (prefix + HyperShotNames[x], + HyperShotButtons[x].ButtonNum[0]); + } + + if (HyperShotButtons[0].ButtType[0] == BUTTC_KEYBOARD) + { + g_config->setOption (prefix + "DeviceType", "Keyboard"); + } + else if (HyperShotButtons[0].ButtType[0] == BUTTC_JOYSTICK) + { + g_config->setOption (prefix + "DeviceType", "Joystick"); + } + else + { + g_config->setOption (prefix + "DeviceType", "Unknown"); + } + g_config->setOption (prefix + "DeviceNum", + HyperShotButtons[0].DeviceNum[0]); + break; + case FCFGD_POWERPAD: + snprintf (buf, 256, "SDL.Input.PowerPad.%d", (arg & 1)); + prefix = buf; + for (x = 0; x < 12; x++) + { + sprintf (buf, "PowerPad %d: %d", (arg & 1) + 1, x + 11); + ConfigButton (buf, &powerpadsc[arg & 1][x]); + + g_config->setOption (prefix + PowerPadNames[x], + powerpadsc[arg & 1][x].ButtonNum[0]); + } + + if (powerpadsc[arg & 1][0].ButtType[0] == BUTTC_KEYBOARD) + { + g_config->setOption (prefix + "DeviceType", "Keyboard"); + } + else if (powerpadsc[arg & 1][0].ButtType[0] == BUTTC_JOYSTICK) + { + g_config->setOption (prefix + "DeviceType", "Joystick"); + } + else + { + g_config->setOption (prefix + "DeviceType", "Unknown"); + } + g_config->setOption (prefix + "DeviceNum", + powerpadsc[arg & 1][0].DeviceNum[0]); + break; + + case FCFGD_GAMEPAD: + snprintf (buf, 256, "SDL.Input.GamePad.%d", arg); + prefix = buf; + for (x = 0; x < 10; x++) + { + sprintf (buf, "GamePad #%d: %s", arg + 1, str[x]); + ConfigButton (buf, &GamePadConfig[arg][x]); + + g_config->setOption (prefix + GamePadNames[x], + GamePadConfig[arg][x].ButtonNum[0]); + } + + if (GamePadConfig[arg][0].ButtType[0] == BUTTC_KEYBOARD) + { + g_config->setOption (prefix + "DeviceType", "Keyboard"); + } + else if (GamePadConfig[arg][0].ButtType[0] == BUTTC_JOYSTICK) + { + g_config->setOption (prefix + "DeviceType", "Joystick"); + } + else + { + g_config->setOption (prefix + "DeviceType", "Unknown"); + } + g_config->setOption (prefix + "DeviceNum", + GamePadConfig[arg][0].DeviceNum[0]); + break; + } + + ButtonConfigEnd (); +} + + +/** + * Update the button configuration for a device, specified by a text string. + */ +void InputCfg (const std::string & text) +{ + +// if (noGui) +// { +// if (text.find ("gamepad") != std::string::npos) +// { +// int device = (text[strlen ("gamepad")] - '1'); +// if (device < 0 || device > 3) +// { +// FCEUD_PrintError +// ("Invalid gamepad device specified; must be one of gamepad1 through gamepad4"); +// exit (-1); +// } +// ConfigDevice (FCFGD_GAMEPAD, device); +// } +// else if (text.find ("powerpad") != std::string::npos) +// { +// int device = (text[strlen ("powerpad")] - '1'); +// if (device < 0 || device > 1) +// { +// FCEUD_PrintError +// ("Invalid powerpad device specified; must be powerpad1 or powerpad2"); +// exit (-1); +// } +// ConfigDevice (FCFGD_POWERPAD, device); +// } +// else if (text.find ("hypershot") != std::string::npos) +// { +// ConfigDevice (FCFGD_HYPERSHOT, 0); +// } +// else if (text.find ("quizking") != std::string::npos) +// { +// ConfigDevice (FCFGD_QUIZKING, 0); +// } +// } +// else +// printf ("Please run \"fceux --nogui\" before using --inputcfg\n"); + +} + + +/** + * Hack to map the new configuration onto the existing button + * configuration management. Will probably want to change this in the + * future - soules. + */ + void +UpdateInput (Config * config) +{ + char buf[64]; + std::string device, prefix; + + for (unsigned int i = 0; i < 3; i++) + { + snprintf (buf, 64, "SDL.Input.%u", i); + config->getOption (buf, &device); + + if (device == "None") + { + UsrInputType[i] = SI_NONE; + } + else if (device.find ("GamePad") != std::string::npos) + { + UsrInputType[i] = (i < 2) ? (int) SI_GAMEPAD : (int) SIFC_NONE; + } + else if (device.find ("PowerPad.0") != std::string::npos) + { + UsrInputType[i] = (i < 2) ? (int) SI_POWERPADA : (int) SIFC_NONE; + } + else if (device.find ("PowerPad.1") != std::string::npos) + { + UsrInputType[i] = (i < 2) ? (int) SI_POWERPADB : (int) SIFC_NONE; + } + else if (device.find ("QuizKing") != std::string::npos) + { + UsrInputType[i] = (i < 2) ? (int) SI_NONE : (int) SIFC_QUIZKING; + } + else if (device.find ("HyperShot") != std::string::npos) + { + UsrInputType[i] = (i < 2) ? (int) SI_NONE : (int) SIFC_HYPERSHOT; + } + else if (device.find ("Mahjong") != std::string::npos) + { + UsrInputType[i] = (i < 2) ? (int) SI_NONE : (int) SIFC_MAHJONG; + } + else if (device.find ("TopRider") != std::string::npos) + { + UsrInputType[i] = (i < 2) ? (int) SI_NONE : (int) SIFC_TOPRIDER; + } + else if (device.find ("FTrainer") != std::string::npos) + { + UsrInputType[i] = (i < 2) ? (int) SI_NONE : (int) SIFC_FTRAINERA; + } + else if (device.find ("FamilyKeyBoard") != std::string::npos) + { + UsrInputType[i] = (i < 2) ? (int) SI_NONE : (int) SIFC_FKB; + } + else if (device.find ("OekaKids") != std::string::npos) + { + UsrInputType[i] = (i < 2) ? (int) SI_NONE : (int) SIFC_OEKAKIDS; + } + else if (device.find ("Arkanoid") != std::string::npos) + { + UsrInputType[i] = (i < 2) ? (int) SI_ARKANOID : (int) SIFC_ARKANOID; + } + else if (device.find ("Shadow") != std::string::npos) + { + UsrInputType[i] = (i < 2) ? (int) SI_NONE : (int) SIFC_SHADOW; + } + else if (device.find ("Zapper") != std::string::npos) + { + UsrInputType[i] = (i < 2) ? (int) SI_ZAPPER : (int) SIFC_NONE; + } + else if (device.find ("BWorld") != std::string::npos) + { + UsrInputType[i] = (i < 2) ? (int) SI_NONE : (int) SIFC_BWORLD; + } + else if (device.find ("4Player") != std::string::npos) + { + UsrInputType[i] = (i < 2) ? (int) SI_NONE : (int) SIFC_4PLAYER; + } + else + { + // Unknown device + UsrInputType[i] = SI_NONE; + } + } + + // update each of the devices' configuration structure + // XXX soules - this is temporary until this file is cleaned up to + // simplify the interface between configuration and + // structure data. This will likely include the + // removal of multiple input buttons for a single + // input device key. + int type, devnum, button; + + // gamepad 0 - 3 + for (unsigned int i = 0; i < GAMEPAD_NUM_DEVICES; i++) + { + char buf[64]; + snprintf (buf, sizeof(buf)-1, "SDL.Input.GamePad.%u.", i); + prefix = buf; + + config->getOption (prefix + "DeviceType", &device); + if (device.find ("Keyboard") != std::string::npos) + { + type = BUTTC_KEYBOARD; + } + else if (device.find ("Joystick") != std::string::npos) + { + type = BUTTC_JOYSTICK; + } + else + { + type = 0; + } + + config->getOption (prefix + "DeviceNum", &devnum); + for (unsigned int j = 0; j < GAMEPAD_NUM_BUTTONS; j++) + { + config->getOption (prefix + GamePadNames[j], &button); + + GamePadConfig[i][j].ButtType[0] = type; + GamePadConfig[i][j].DeviceNum[0] = devnum; + GamePadConfig[i][j].ButtonNum[0] = button; + GamePadConfig[i][j].NumC = 1; + } + } + + // PowerPad 0 - 1 + for (unsigned int i = 0; i < POWERPAD_NUM_DEVICES; i++) + { + char buf[64]; + snprintf (buf, 32, "SDL.Input.PowerPad.%u.", i); + prefix = buf; + + config->getOption (prefix + "DeviceType", &device); + if (device.find ("Keyboard") != std::string::npos) + { + type = BUTTC_KEYBOARD; + } + else if (device.find ("Joystick") != std::string::npos) + { + type = BUTTC_JOYSTICK; + } + else + { + type = 0; + } + + config->getOption (prefix + "DeviceNum", &devnum); + for (unsigned int j = 0; j < POWERPAD_NUM_BUTTONS; j++) + { + config->getOption (prefix + PowerPadNames[j], &button); + + powerpadsc[i][j].ButtType[0] = type; + powerpadsc[i][j].DeviceNum[0] = devnum; + powerpadsc[i][j].ButtonNum[0] = button; + powerpadsc[i][j].NumC = 1; + } + } + + // QuizKing + prefix = "SDL.Input.QuizKing."; + config->getOption (prefix + "DeviceType", &device); + if (device.find ("Keyboard") != std::string::npos) + { + type = BUTTC_KEYBOARD; + } + else if (device.find ("Joystick") != std::string::npos) + { + type = BUTTC_JOYSTICK; + } + else + { + type = 0; + } + config->getOption (prefix + "DeviceNum", &devnum); + for (unsigned int j = 0; j < QUIZKING_NUM_BUTTONS; j++) + { + config->getOption (prefix + QuizKingNames[j], &button); + + QuizKingButtons[j].ButtType[0] = type; + QuizKingButtons[j].DeviceNum[0] = devnum; + QuizKingButtons[j].ButtonNum[0] = button; + QuizKingButtons[j].NumC = 1; + } + + // HyperShot + prefix = "SDL.Input.HyperShot."; + config->getOption (prefix + "DeviceType", &device); + if (device.find ("Keyboard") != std::string::npos) + { + type = BUTTC_KEYBOARD; + } + else if (device.find ("Joystick") != std::string::npos) + { + type = BUTTC_JOYSTICK; + } + else + { + type = 0; + } + config->getOption (prefix + "DeviceNum", &devnum); + for (unsigned int j = 0; j < HYPERSHOT_NUM_BUTTONS; j++) + { + config->getOption (prefix + HyperShotNames[j], &button); + + HyperShotButtons[j].ButtType[0] = type; + HyperShotButtons[j].DeviceNum[0] = devnum; + HyperShotButtons[j].ButtonNum[0] = button; + HyperShotButtons[j].NumC = 1; + } + + // Mahjong + prefix = "SDL.Input.Mahjong."; + config->getOption (prefix + "DeviceType", &device); + if (device.find ("Keyboard") != std::string::npos) + { + type = BUTTC_KEYBOARD; + } + else if (device.find ("Joystick") != std::string::npos) + { + type = BUTTC_JOYSTICK; + } + else + { + type = 0; + } + config->getOption (prefix + "DeviceNum", &devnum); + for (unsigned int j = 0; j < MAHJONG_NUM_BUTTONS; j++) + { + config->getOption (prefix + MahjongNames[j], &button); + + MahjongButtons[j].ButtType[0] = type; + MahjongButtons[j].DeviceNum[0] = devnum; + MahjongButtons[j].ButtonNum[0] = button; + MahjongButtons[j].NumC = 1; + } + + // TopRider + prefix = "SDL.Input.TopRider."; + config->getOption (prefix + "DeviceType", &device); + if (device.find ("Keyboard") != std::string::npos) + { + type = BUTTC_KEYBOARD; + } + else if (device.find ("Joystick") != std::string::npos) + { + type = BUTTC_JOYSTICK; + } + else + { + type = 0; + } + config->getOption (prefix + "DeviceNum", &devnum); + for (unsigned int j = 0; j < TOPRIDER_NUM_BUTTONS; j++) + { + config->getOption (prefix + TopRiderNames[j], &button); + + TopRiderButtons[j].ButtType[0] = type; + TopRiderButtons[j].DeviceNum[0] = devnum; + TopRiderButtons[j].ButtonNum[0] = button; + TopRiderButtons[j].NumC = 1; + } + + // FTrainer + prefix = "SDL.Input.FTrainer."; + config->getOption (prefix + "DeviceType", &device); + if (device.find ("Keyboard") != std::string::npos) + { + type = BUTTC_KEYBOARD; + } + else if (device.find ("Joystick") != std::string::npos) + { + type = BUTTC_JOYSTICK; + } + else + { + type = 0; + } + config->getOption (prefix + "DeviceNum", &devnum); + for (unsigned int j = 0; j < FTRAINER_NUM_BUTTONS; j++) + { + config->getOption (prefix + FTrainerNames[j], &button); + + FTrainerButtons[j].ButtType[0] = type; + FTrainerButtons[j].DeviceNum[0] = devnum; + FTrainerButtons[j].ButtonNum[0] = button; + FTrainerButtons[j].NumC = 1; + } + + // FamilyKeyBoard + prefix = "SDL.Input.FamilyKeyBoard."; + config->getOption (prefix + "DeviceType", &device); + if (device.find ("Keyboard") != std::string::npos) + { + type = BUTTC_KEYBOARD; + } + else if (device.find ("Joystick") != std::string::npos) + { + type = BUTTC_JOYSTICK; + } + else + { + type = 0; + } + config->getOption (prefix + "DeviceNum", &devnum); + for (unsigned int j = 0; j < FAMILYKEYBOARD_NUM_BUTTONS; j++) + { + config->getOption (prefix + FamilyKeyBoardNames[j], &button); + + fkbmap[j].ButtType[0] = type; + fkbmap[j].DeviceNum[0] = devnum; + fkbmap[j].ButtonNum[0] = button; + fkbmap[j].NumC = 1; + } +} + +// Definitions from main.h: +// GamePad defaults +const char *GamePadNames[GAMEPAD_NUM_BUTTONS] = { "A", "B", "Select", "Start", + "Up", "Down", "Left", "Right", "TurboA", "TurboB" +}; +const char *DefaultGamePadDevice[GAMEPAD_NUM_DEVICES] = +{ "Keyboard", "None", "None", "None" }; +const int DefaultGamePad[GAMEPAD_NUM_DEVICES][GAMEPAD_NUM_BUTTONS] = +{ {SDLK_F, SDLK_D, SDLK_S, SDLK_RETURN, + SDLK_UP, SDLK_DOWN, SDLK_LEFT, SDLK_RIGHT, 0, 0}, +{0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0, 0, 0, 0} +}; + +// PowerPad defaults +const char *PowerPadNames[POWERPAD_NUM_BUTTONS] = +{ "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B" }; +const char *DefaultPowerPadDevice[POWERPAD_NUM_DEVICES] = +{ "Keyboard", "None" }; +const int DefaultPowerPad[POWERPAD_NUM_DEVICES][POWERPAD_NUM_BUTTONS] = +{ {SDLK_o, SDLK_p, SDLK_LEFTBRACKET, SDLK_RIGHTBRACKET, + SDLK_k, SDLK_l, SDLK_SEMICOLON, SDLK_QUOTE, + SDLK_m, SDLK_COMMA, SDLK_PERIOD, SDLK_SLASH}, +{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} +}; + +// QuizKing defaults +const char *QuizKingNames[QUIZKING_NUM_BUTTONS] = +{ "0", "1", "2", "3", "4", "5" }; +const char *DefaultQuizKingDevice = "Keyboard"; +const int DefaultQuizKing[QUIZKING_NUM_BUTTONS] = +{ SDLK_q, SDLK_w, SDLK_e, SDLK_r, SDLK_t, SDLK_y }; + +// HyperShot defaults +const char *HyperShotNames[HYPERSHOT_NUM_BUTTONS] = { "0", "1", "2", "3" }; + +const char *DefaultHyperShotDevice = "Keyboard"; +const int DefaultHyperShot[HYPERSHOT_NUM_BUTTONS] = +{ SDLK_q, SDLK_w, SDLK_e, SDLK_r }; + +// Mahjong defaults +const char *MahjongNames[MAHJONG_NUM_BUTTONS] = +{ "00", "01", "02", "03", "04", "05", "06", "07", + "08", "09", "10", "11", "12", "13", "14", "15", + "16", "17", "18", "19", "20" +}; + +const char *DefaultMahjongDevice = "Keyboard"; +const int DefaultMahjong[MAHJONG_NUM_BUTTONS] = +{ SDLK_q, SDLK_w, SDLK_e, SDLK_r, SDLK_t, SDLK_a, SDLK_s, SDLK_d, + SDLK_f, SDLK_g, SDLK_h, SDLK_j, SDLK_k, SDLK_l, SDLK_z, SDLK_x, + SDLK_c, SDLK_v, SDLK_b, SDLK_n, SDLK_m +}; + +// TopRider defaults +const char *TopRiderNames[TOPRIDER_NUM_BUTTONS] = +{ "0", "1", "2", "3", "4", "5", "6", "7" }; +const char *DefaultTopRiderDevice = "Keyboard"; +const int DefaultTopRider[TOPRIDER_NUM_BUTTONS] = +{ SDLK_q, SDLK_w, SDLK_e, SDLK_r, SDLK_t, SDLK_y, SDLK_u, SDLK_i }; + +// FTrainer defaults +const char *FTrainerNames[FTRAINER_NUM_BUTTONS] = +{ "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B" }; +const char *DefaultFTrainerDevice = "Keyboard"; +const int DefaultFTrainer[FTRAINER_NUM_BUTTONS] = +{ SDLK_o, SDLK_p, SDLK_LEFTBRACKET, SDLK_RIGHTBRACKET, + SDLK_k, SDLK_l, SDLK_SEMICOLON, SDLK_QUOTE, + SDLK_m, SDLK_COMMA, SDLK_PERIOD, SDLK_SLASH +}; + +// FamilyKeyBoard defaults +const char *FamilyKeyBoardNames[FAMILYKEYBOARD_NUM_BUTTONS] = +{ "F1", "F2", "F3", "F4", "F5", "F6", "F7", "F8", + "1", "2", "3", "4", "5", "6", "7", "8", "9", "0", + "MINUS", "EQUAL", "BACKSLASH", "BACKSPACE", + "ESCAPE", "Q", "W", "E", "R", "T", "Y", "U", "I", "O", + "P", "GRAVE", "BRACKET_LEFT", "ENTER", + "LEFTCONTROL", "A", "S", "D", "F", "G", "H", "J", "K", + "L", "SEMICOLON", "APOSTROPHE", "BRACKET_RIGHT", "INSERT", + "LEFTSHIFT", "Z", "X", "C", "V", "B", "N", "M", "COMMA", + "PERIOD", "SLASH", "RIGHTALT", "RIGHTSHIFT", "LEFTALT", "SPACE", + "DELETE", "END", "PAGEDOWN", + "CURSORUP", "CURSORLEFT", "CURSORRIGHT", "CURSORDOWN" +}; + +const char *DefaultFamilyKeyBoardDevice = "Keyboard"; +const int DefaultFamilyKeyBoard[FAMILYKEYBOARD_NUM_BUTTONS] = +{ SDLK_F1, SDLK_F2, SDLK_F3, SDLK_F4, SDLK_F5, SDLK_F6, SDLK_F7, SDLK_F8, + SDLK_1, SDLK_2, SDLK_3, SDLK_4, SDLK_5, + SDLK_6, SDLK_7, SDLK_8, SDLK_9, SDLK_0, + SDLK_MINUS, SDLK_EQUALS, SDLK_BACKSLASH, SDLK_BACKSPACE, + SDLK_ESCAPE, SDLK_q, SDLK_w, SDLK_e, SDLK_r, SDLK_t, SDLK_y, SDLK_u, + SDLK_i, SDLK_o, SDLK_p, SDLK_BACKQUOTE, SDLK_LEFTBRACKET, SDLK_RETURN, + SDLK_LCTRL, SDLK_a, SDLK_s, SDLK_d, SDLK_f, SDLK_g, SDLK_h, SDLK_j, + SDLK_k, SDLK_l, SDLK_SEMICOLON, SDLK_QUOTE, SDLK_RIGHTBRACKET, + SDLK_INSERT, SDLK_LSHIFT, SDLK_z, SDLK_x, SDLK_c, SDLK_v, SDLK_b, + SDLK_n, SDLK_m, SDLK_COMMA, SDLK_PERIOD, SDLK_SLASH, SDLK_RALT, + SDLK_RSHIFT, SDLK_LALT, SDLK_SPACE, SDLK_DELETE, SDLK_END, SDLK_PAGEDOWN, + SDLK_UP, SDLK_LEFT, SDLK_RIGHT, SDLK_DOWN +}; diff --git a/src/drivers/Qt/input.h b/src/drivers/Qt/input.h new file mode 100644 index 00000000..2a1a2d85 --- /dev/null +++ b/src/drivers/Qt/input.h @@ -0,0 +1,62 @@ +#ifndef _aosdfjk02fmasf +#define _aosdfjk02fmasf + +#include "../common/configSys.h" + +#define MAXBUTTCONFIG 4 +typedef struct { + uint8 ButtType[MAXBUTTCONFIG]; + uint8 DeviceNum[MAXBUTTCONFIG]; + //uint16 ButtonNum[MAXBUTTCONFIG]; + int ButtonNum[MAXBUTTCONFIG]; + uint32 NumC; + //uint64 DeviceID[MAXBUTTCONFIG]; /* TODO */ +} ButtConfig; + + +extern int NoWaiting; +extern CFGSTRUCT InputConfig[]; +extern ARGPSTRUCT InputArgs[]; +extern int Hotkeys[]; +void ParseGIInput(FCEUGI *GI); +void setHotKeys(); +int getKeyState( int k ); +int ButtonConfigBegin(); +void ButtonConfigEnd(); +void ConfigButton(char *text, ButtConfig *bc); +int DWaitButton(const uint8 *text, ButtConfig *bc, int wb, int *buttonConfigStatus = NULL); + +#define BUTTC_KEYBOARD 0x00 +#define BUTTC_JOYSTICK 0x01 +#define BUTTC_MOUSE 0x02 + +#define FCFGD_GAMEPAD 1 +#define FCFGD_POWERPAD 2 +#define FCFGD_HYPERSHOT 3 +#define FCFGD_QUIZKING 4 + +#define SDL_FCEU_HOTKEY_EVENT SDL_USEREVENT + +void InitInputInterface(void); +void InputUserActiveFix(void); + +extern bool replaceP2StartWithMicrophone; +extern ButtConfig GamePadConfig[4][10]; +//extern ButtConfig powerpadsc[2][12]; +//extern ButtConfig QuizKingButtons[6]; +//extern ButtConfig FTrainerButtons[12]; + +void IncreaseEmulationSpeed(void); +void DecreaseEmulationSpeed(void); + +int DTestButtonJoy(ButtConfig *bc); + +void FCEUD_UpdateInput(void); + +void UpdateInput(Config *config); +void InputCfg(const std::string &); + +std::string GetUserText(const char* title); +const char* ButtonName(const ButtConfig* bc, int which); +#endif + diff --git a/src/drivers/Qt/keyscan.h b/src/drivers/Qt/keyscan.h new file mode 100644 index 00000000..b3973c20 --- /dev/null +++ b/src/drivers/Qt/keyscan.h @@ -0,0 +1,44 @@ +#define SDLK_A SDLK_a +#define SDLK_B SDLK_b +#define SDLK_C SDLK_c +#define SDLK_D SDLK_d +#define SDLK_E SDLK_e +#define SDLK_F SDLK_f +#define SDLK_G SDLK_g +#define SDLK_H SDLK_h +#define SDLK_I SDLK_i +#define SDLK_J SDLK_j +#define SDLK_K SDLK_k +#define SDLK_L SDLK_l +#define SDLK_M SDLK_m +#define SDLK_N SDLK_n +#define SDLK_O SDLK_o +#define SDLK_P SDLK_p +#define SDLK_Q SDLK_q +#define SDLK_R SDLK_r +#define SDLK_S SDLK_s +#define SDLK_T SDLK_t +#define SDLK_U SDLK_u +#define SDLK_V SDLK_v +#define SDLK_W SDLK_w +#define SDLK_X SDLK_x +#define SDLK_Y SDLK_y +#define SDLK_Z SDLK_z +#define SDLK_LEFTCONTROL SDLK_LCTRL +#define SDLK_RIGHTCONTROL SDLK_RCTRL +#define SDLK_LEFTALT SDLK_LALT +#define SDLK_RIGHTALT SDLK_RALT +#define SDLK_LEFTSHIFT SDLK_LSHIFT +#define SDLK_RIGHTSHIFT SDLK_RSHIFT +#define SDLK_CURSORDOWN SDLK_DOWN +#define SDLK_CURSORUP SDLK_UP +#define SDLK_CURSORLEFT SDLK_LEFT +#define SDLK_CURSORRIGHT SDLK_RIGHT +#define SDLK_ENTER SDLK_RETURN +#define SDLK_EQUAL SDLK_EQUALS +#define SDLK_APOSTROPHE SDLK_QUOTE +#define SDLK_BRACKET_LEFT SDLK_LEFTBRACKET +#define SDLK_BRACKET_RIGHT SDLK_RIGHTBRACKET +#define SDLK_SCROLLLOCK SDLK_SCROLLOCK /* I guess the SDL people don't like lots of Ls... */ +#define SDLK_GRAVE SDLK_BACKQUOTE +#define MKK(k) SDLK_##k diff --git a/src/drivers/Qt/main.cpp b/src/drivers/Qt/main.cpp new file mode 100644 index 00000000..14864529 --- /dev/null +++ b/src/drivers/Qt/main.cpp @@ -0,0 +1,15 @@ +#include + +#include "GameApp.h" + +int main( int argc, char *argv[] ) +{ + QApplication app(argc, argv); + gameWin_t win; + + win.resize( 200, 200 ); + win.show(); + + return app.exec(); +} + diff --git a/src/drivers/Qt/main.h b/src/drivers/Qt/main.h new file mode 100644 index 00000000..9b6963e1 --- /dev/null +++ b/src/drivers/Qt/main.h @@ -0,0 +1,100 @@ +/* FCE Ultra - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2002 Xodnizel + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ +#ifndef __FCEU_SDL_MAIN_H +#define __FCEU_SDL_MAIN_H + +#include "../../driver.h" +#include "../common/config.h" +#include "../common/args.h" + +extern int eoptions; +#define EO_NO8LIM 1 +#define EO_SUBASE 2 +#define EO_CLIPSIDES 8 +#define EO_SNAPNAME 16 +#define EO_FOURSCORE 32 +#define EO_NOTHROTTLE 64 +#define EO_GAMEGENIE 128 +#define EO_PAL 256 +#define EO_LOWPASS 512 +#define EO_AUTOHIDE 1024 + +extern int _sound; +extern long soundrate; +extern long soundbufsize; + +extern int pal_emulation; + +int CLImain(int argc, char *argv[]); + +// Device management defaults +#define NUM_INPUT_DEVICES 3 + +// GamePad defaults +#define GAMEPAD_NUM_DEVICES 4 +#define GAMEPAD_NUM_BUTTONS 10 +extern const char *GamePadNames[GAMEPAD_NUM_BUTTONS]; +extern const char *DefaultGamePadDevice[GAMEPAD_NUM_DEVICES]; +extern const int DefaultGamePad[GAMEPAD_NUM_DEVICES][GAMEPAD_NUM_BUTTONS]; + +// PowerPad defaults +#define POWERPAD_NUM_DEVICES 2 +#define POWERPAD_NUM_BUTTONS 12 +extern const char *PowerPadNames[POWERPAD_NUM_BUTTONS]; +extern const char *DefaultPowerPadDevice[POWERPAD_NUM_DEVICES]; +extern const int DefaultPowerPad[POWERPAD_NUM_DEVICES][POWERPAD_NUM_BUTTONS]; + +// QuizKing defaults +#define QUIZKING_NUM_BUTTONS 6 +extern const char *QuizKingNames[QUIZKING_NUM_BUTTONS]; +extern const char *DefaultQuizKingDevice; +extern const int DefaultQuizKing[QUIZKING_NUM_BUTTONS]; + +// HyperShot defaults +#define HYPERSHOT_NUM_BUTTONS 4 +extern const char *HyperShotNames[HYPERSHOT_NUM_BUTTONS]; +extern const char *DefaultHyperShotDevice; +extern const int DefaultHyperShot[HYPERSHOT_NUM_BUTTONS]; + +// Mahjong defaults +#define MAHJONG_NUM_BUTTONS 21 +extern const char *MahjongNames[MAHJONG_NUM_BUTTONS]; +extern const char *DefaultMahjongDevice; +extern const int DefaultMahjong[MAHJONG_NUM_BUTTONS]; + +// TopRider defaults +#define TOPRIDER_NUM_BUTTONS 8 +extern const char *TopRiderNames[TOPRIDER_NUM_BUTTONS]; +extern const char *DefaultTopRiderDevice; +extern const int DefaultTopRider[TOPRIDER_NUM_BUTTONS]; + +// FTrainer defaults +#define FTRAINER_NUM_BUTTONS 12 +extern const char *FTrainerNames[FTRAINER_NUM_BUTTONS]; +extern const char *DefaultFTrainerDevice; +extern const int DefaultFTrainer[FTRAINER_NUM_BUTTONS]; + +// FamilyKeyBoard defaults +#define FAMILYKEYBOARD_NUM_BUTTONS 0x48 +extern const char *FamilyKeyBoardNames[FAMILYKEYBOARD_NUM_BUTTONS]; +extern const char *DefaultFamilyKeyBoardDevice; +extern const int DefaultFamilyKeyBoard[FAMILYKEYBOARD_NUM_BUTTONS]; + +#endif diff --git a/src/drivers/Qt/sdl-joystick.cpp b/src/drivers/Qt/sdl-joystick.cpp new file mode 100644 index 00000000..690b012b --- /dev/null +++ b/src/drivers/Qt/sdl-joystick.cpp @@ -0,0 +1,123 @@ +/* FCE Ultra - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2002 Xodnizel + * Copyright (C) 2002 Paul Kuliniewicz + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/// \file +/// \brief Handles joystick input using the SDL. + +#include "sdl.h" + +#include +#include +#include +#include + +#define MAX_JOYSTICKS 32 +static SDL_Joystick *s_Joysticks[MAX_JOYSTICKS] = {NULL}; + +static int s_jinited = 0; + + +/** + * Tests if the given button is active on the joystick. + */ +int +DTestButtonJoy(ButtConfig *bc) +{ + int x; + + for(x = 0; x < bc->NumC; x++) + { + if(bc->ButtonNum[x] & 0x2000) + { + /* Hat "button" */ + if(SDL_JoystickGetHat(s_Joysticks[bc->DeviceNum[x]], + ((bc->ButtonNum[x] >> 8) & 0x1F)) & + (bc->ButtonNum[x]&0xFF)) + return 1; + } + else if(bc->ButtonNum[x] & 0x8000) + { + /* Axis "button" */ + int pos; + pos = SDL_JoystickGetAxis(s_Joysticks[bc->DeviceNum[x]], + bc->ButtonNum[x] & 16383); + if ((bc->ButtonNum[x] & 0x4000) && pos <= -16383) { + return 1; + } else if (!(bc->ButtonNum[x] & 0x4000) && pos >= 16363) { + return 1; + } + } + else if(SDL_JoystickGetButton(s_Joysticks[bc->DeviceNum[x]], + bc->ButtonNum[x])) + return 1; + } + return 0; +} + +/** + * Shutdown the SDL joystick subsystem. + */ +int +KillJoysticks() +{ + int n; /* joystick index */ + + if(!s_jinited) { + return -1; + } + + for(n = 0; n < MAX_JOYSTICKS; n++) { + if (s_Joysticks[n] != 0) { + SDL_JoystickClose(s_Joysticks[n]); + } + s_Joysticks[n]=0; + } + SDL_QuitSubSystem(SDL_INIT_JOYSTICK); + return 0; +} + +/** + * Initialize the SDL joystick subsystem. + */ +int +InitJoysticks() +{ + int n; /* joystick index */ + int total; + + SDL_InitSubSystem(SDL_INIT_JOYSTICK); + + total = SDL_NumJoysticks(); + if(total>MAX_JOYSTICKS) { + total = MAX_JOYSTICKS; + } + + for(n = 0; n < total; n++) { + /* Open the joystick under SDL. */ + s_Joysticks[n] = SDL_JoystickOpen(n); + //printf("Could not open joystick %d: %s.\n", + //joy[n] - 1, SDL_GetError()); + continue; + } + + s_jinited = 1; + return 1; +} diff --git a/src/drivers/Qt/sdl-sound.cpp b/src/drivers/Qt/sdl-sound.cpp new file mode 100644 index 00000000..00b7c9a6 --- /dev/null +++ b/src/drivers/Qt/sdl-sound.cpp @@ -0,0 +1,280 @@ +/* FCE Ultra - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2002 Xodnizel + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/// \file +/// \brief Handles sound emulation using the SDL. + +#include "sdl.h" + +#include "../common/configSys.h" +#include "../../utils/memory.h" + +#include +#include +#include + +extern Config *g_config; + +static volatile int *s_Buffer = 0; +static unsigned int s_BufferSize; +static unsigned int s_BufferRead; +static unsigned int s_BufferWrite; +static volatile unsigned int s_BufferIn; + +static int s_mute = 0; + + +/** + * Callback from the SDL to get and play audio data. + */ +static void +fillaudio(void *udata, + uint8 *stream, + int len) +{ + int16 *tmps = (int16*)stream; + len >>= 1; + while(len) { + int16 sample = 0; + if(s_BufferIn) { + sample = s_Buffer[s_BufferRead]; + s_BufferRead = (s_BufferRead + 1) % s_BufferSize; + s_BufferIn--; + } else { + sample = 0; + } + + *tmps = sample; + tmps++; + len--; + } +} + +/** + * Initialize the audio subsystem. + */ +int +InitSound() +{ + int sound, soundrate, soundbufsize, soundvolume, soundtrianglevolume, soundsquare1volume, soundsquare2volume, soundnoisevolume, soundpcmvolume, soundq; + SDL_AudioSpec spec; + const char *driverName; + + g_config->getOption("SDL.Sound", &sound); + if (!sound) + { + return 0; + } + + memset(&spec, 0, sizeof(spec)); + if (SDL_InitSubSystem(SDL_INIT_AUDIO) < 0) + { + puts(SDL_GetError()); + KillSound(); + return 0; + } + + // load configuration variables + g_config->getOption("SDL.Sound.Rate", &soundrate); + g_config->getOption("SDL.Sound.BufSize", &soundbufsize); + g_config->getOption("SDL.Sound.Volume", &soundvolume); + g_config->getOption("SDL.Sound.Quality", &soundq); + g_config->getOption("SDL.Sound.TriangleVolume", &soundtrianglevolume); + g_config->getOption("SDL.Sound.Square1Volume", &soundsquare1volume); + g_config->getOption("SDL.Sound.Square2Volume", &soundsquare2volume); + g_config->getOption("SDL.Sound.NoiseVolume", &soundnoisevolume); + g_config->getOption("SDL.Sound.PCMVolume", &soundpcmvolume); + + spec.freq = soundrate; + spec.format = AUDIO_S16SYS; + spec.channels = 1; + spec.samples = 512; + spec.callback = fillaudio; + spec.userdata = 0; + + s_BufferSize = soundbufsize * soundrate / 1000; + + // For safety, set a bare minimum: + if (s_BufferSize < spec.samples * 2) + { + s_BufferSize = spec.samples * 2; + } + + s_Buffer = (int *)FCEU_dmalloc(sizeof(int) * s_BufferSize); + + if (!s_Buffer) + { + return 0; + } + s_BufferRead = s_BufferWrite = s_BufferIn = 0; + + if (SDL_OpenAudio(&spec, 0) < 0) + { + puts(SDL_GetError()); + KillSound(); + return 0; + } + SDL_PauseAudio(0); + + driverName = SDL_GetCurrentAudioDriver(); + + if ( driverName ) + { + fprintf(stderr, "Loading SDL sound with %s driver...\n", driverName); + } + + FCEUI_SetSoundVolume(soundvolume); + FCEUI_SetSoundQuality(soundq); + FCEUI_Sound(soundrate); + FCEUI_SetTriangleVolume(soundtrianglevolume); + FCEUI_SetSquare1Volume(soundsquare1volume); + FCEUI_SetSquare2Volume(soundsquare2volume); + FCEUI_SetNoiseVolume(soundnoisevolume); + FCEUI_SetPCMVolume(soundpcmvolume); + return 1; +} + + +/** + * Returns the size of the audio buffer. + */ +uint32 +GetMaxSound(void) +{ + return(s_BufferSize); +} + +/** + * Returns the amount of free space in the audio buffer. + */ +uint32 +GetWriteSound(void) +{ + return(s_BufferSize - s_BufferIn); +} + +/** + * Send a sound clip to the audio subsystem. + */ +void +WriteSound(int32 *buf, + int Count) +{ + extern int EmulationPaused; + if (EmulationPaused == 0) + while(Count) + { + while(s_BufferIn == s_BufferSize) + { + SDL_Delay(1); + } + + s_Buffer[s_BufferWrite] = *buf; + Count--; + s_BufferWrite = (s_BufferWrite + 1) % s_BufferSize; + + SDL_LockAudio(); + s_BufferIn++; + SDL_UnlockAudio(); + + buf++; + } +} + +/** + * Pause (1) or unpause (0) the audio output. + */ +void +SilenceSound(int n) +{ + SDL_PauseAudio(n); +} + +/** + * Shut down the audio subsystem. + */ +int +KillSound(void) +{ + FCEUI_Sound(0); + SDL_CloseAudio(); + SDL_QuitSubSystem(SDL_INIT_AUDIO); + if(s_Buffer) { + free((void *)s_Buffer); + s_Buffer = 0; + } + return 0; +} + + +/** + * Adjust the volume either down (-1), up (1), or to the default (0). + * Unmutes if mute was active before. + */ +void +FCEUD_SoundVolumeAdjust(int n) +{ + int soundvolume; + g_config->getOption("SDL.Sound.Volume", &soundvolume); + + switch(n) { + case -1: + soundvolume -= 10; + if(soundvolume < 0) { + soundvolume = 0; + } + break; + case 0: + soundvolume = 100; + break; + case 1: + soundvolume += 10; + if(soundvolume > 150) { + soundvolume = 150; + } + break; + } + + s_mute = 0; + FCEUI_SetSoundVolume(soundvolume); + g_config->setOption("SDL.Sound.Volume", soundvolume); + + FCEU_DispMessage("Sound volume %d.",0, soundvolume); +} + +/** + * Toggles the sound on or off. + */ +void +FCEUD_SoundToggle(void) +{ + if(s_mute) { + int soundvolume; + g_config->getOption("SDL.SoundVolume", &soundvolume); + + s_mute = 0; + FCEUI_SetSoundVolume(soundvolume); + FCEU_DispMessage("Sound mute off.",0); + } else { + s_mute = 1; + FCEUI_SetSoundVolume(0); + FCEU_DispMessage("Sound mute on.",0); + } +} diff --git a/src/drivers/Qt/sdl-throttle.cpp b/src/drivers/Qt/sdl-throttle.cpp new file mode 100644 index 00000000..498d4fe7 --- /dev/null +++ b/src/drivers/Qt/sdl-throttle.cpp @@ -0,0 +1,154 @@ +/// \file +/// \brief Handles emulation speed throttling using the SDL timing functions. + +#include "sdl.h" +#include "throttle.h" + +static const double Slowest = 0.015625; // 1/64x speed (around 1 fps on NTSC) +static const double Fastest = 32; // 32x speed (around 1920 fps on NTSC) +static const double Normal = 1.0; // 1x speed (around 60 fps on NTSC) + +static uint64 Lasttime, Nexttime; +static long double desired_frametime; +static int InFrame; +double g_fpsScale = Normal; // used by sdl.cpp +bool MaxSpeed = false; + +/* LOGMUL = exp(log(2) / 3) + * + * This gives us a value such that if we do x*=LOGMUL three times, + * then after that, x is twice the value it was before. + * + * This gives us three speed steps per order of magnitude. + * + */ +#define LOGMUL 1.259921049894873 + +/** + * Refreshes the FPS throttling variables. + */ +void +RefreshThrottleFPS() +{ + uint64 fps = FCEUI_GetDesiredFPS(); // Do >> 24 to get in Hz + desired_frametime = 16777216.0l / (fps * g_fpsScale); + + Lasttime=0; + Nexttime=0; + InFrame=0; +} + +/** + * Perform FPS speed throttling by delaying until the next time slot. + */ +int +SpeedThrottle() +{ + if(g_fpsScale >= 32) + { + return 0; /* Done waiting */ + } + uint64 time_left; + uint64 cur_time; + + if(!Lasttime) + Lasttime = SDL_GetTicks(); + + if(!InFrame) + { + InFrame = 1; + Nexttime = Lasttime + desired_frametime * 1000; + } + + cur_time = SDL_GetTicks(); + if(cur_time >= Nexttime) + time_left = 0; + else + time_left = Nexttime - cur_time; + + if(time_left > 50) + { + time_left = 50; + /* In order to keep input responsive, don't wait too long at once */ + /* 50 ms wait gives us a 20 Hz responsetime which is nice. */ + } + else + InFrame = 0; + + //fprintf(stderr, "attempting to sleep %Ld ms, frame complete=%s\n", + // time_left, InFrame?"no":"yes"); + + if ( time_left > 0 ) + { + SDL_Delay(time_left); + } + + if(!InFrame) + { + Lasttime = SDL_GetTicks(); + return 0; /* Done waiting */ + } + return 1; /* Must still wait some more */ +} + +/** + * Set the emulation speed throttling to the next entry in the speed table. + */ +void IncreaseEmulationSpeed(void) +{ + g_fpsScale *= LOGMUL; + + if(g_fpsScale > Fastest) g_fpsScale = Fastest; + + RefreshThrottleFPS(); + + FCEU_DispMessage("Emulation speed %.1f%%",0, g_fpsScale*100.0); +} + +/** + * Set the emulation speed throttling to the previous entry in the speed table. + */ +void DecreaseEmulationSpeed(void) +{ + g_fpsScale /= LOGMUL; + if(g_fpsScale < Slowest) + g_fpsScale = Slowest; + + RefreshThrottleFPS(); + + FCEU_DispMessage("Emulation speed %.1f%%",0, g_fpsScale*100.0); +} + +/** + * Set the emulation speed throttling to a specific value. + */ +void +FCEUD_SetEmulationSpeed(int cmd) +{ + MaxSpeed = false; + + switch(cmd) { + case EMUSPEED_SLOWEST: + g_fpsScale = Slowest; + break; + case EMUSPEED_SLOWER: + DecreaseEmulationSpeed(); + break; + case EMUSPEED_NORMAL: + g_fpsScale = Normal; + break; + case EMUSPEED_FASTER: + IncreaseEmulationSpeed(); + break; + case EMUSPEED_FASTEST: + g_fpsScale = Fastest; + MaxSpeed = true; + break; + default: + return; + } + + RefreshThrottleFPS(); + + FCEU_DispMessage("Emulation speed %.1f%%",0, g_fpsScale*100.0); +} diff --git a/src/drivers/Qt/sdl-video.cpp b/src/drivers/Qt/sdl-video.cpp new file mode 100644 index 00000000..98f59009 --- /dev/null +++ b/src/drivers/Qt/sdl-video.cpp @@ -0,0 +1,464 @@ +/* FCE Ultra - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2002 Xodnizel + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/// \file +/// \brief Handles the graphical game display for the SDL implementation. + +#include "sdl.h" +#include "gl_win.h" +#include "../common/vidblit.h" +#include "../../fceu.h" +#include "../../version.h" +#include "../../video.h" + +#include "../../utils/memory.h" + +//#include "sdl-icon.h" +#include "dface.h" + +#include "../common/configSys.h" +#include "sdl-video.h" +#include "fceuWrapper.h" + +#ifdef CREATE_AVI +#include "../videolog/nesvideos-piece.h" +#endif + +#include +#include +#include + +// GLOBALS +extern Config *g_config; + +// STATIC GLOBALS +static int s_curbpp = 0; +static int s_srendline, s_erendline; +static int s_tlines; +static int s_inited = 0; + +//#ifdef OPENGL +//static int s_useOpenGL = 0; +//#endif +static double s_exs = 1.0, s_eys = 1.0; +static int s_eefx = 0; +static int s_clipSides = 0; +static int s_fullscreen = 0; +static int noframe = 0; +static int initBlitToHighDone = 0; + +#define NWIDTH (256 - (s_clipSides ? 16 : 0)) +#define NOFFSET (s_clipSides ? 8 : 0) + +static int s_paletterefresh = 1; + +extern bool MaxSpeed; + +/** + * Attempts to destroy the graphical video display. Returns 0 on + * success, -1 on failure. + */ + +//draw input aids if we are fullscreen +bool FCEUD_ShouldDrawInputAids() +{ + return s_fullscreen!=0; +} + +int +KillVideo() +{ + //printf("Killing Video\n"); + + if ( gl_shm != NULL ) + { + gl_shm->clear_pixbuf(); + } + + //destroy_gui_video(); + + // return failure if the video system was not initialized + if (s_inited == 0) + return -1; + + // if the rest of the system has been initialized, shut it down +// // shut down the system that converts from 8 to 16/32 bpp +// if (s_curbpp > 8) +// { +// KillBlitToHigh(); +// } + + // SDL Video system is not used. + // shut down the SDL video sub-system + //SDL_QuitSubSystem(SDL_INIT_VIDEO); + + s_inited = 0; + return 0; +} + + +// this variable contains information about the special scaling filters +static int s_sponge = 0; + +/** + * These functions determine an appropriate scale factor for fullscreen/ + */ +inline double GetXScale(int xres) +{ + return ((double)xres) / NWIDTH; +} +inline double GetYScale(int yres) +{ + return ((double)yres) / s_tlines; +} +void FCEUD_VideoChanged() +{ + int buf; + g_config->getOption("SDL.PAL", &buf); + if(buf == 1) + PAL = 1; + else + PAL = 0; // NTSC and Dendy +} + +int InitVideo(FCEUGI *gi) +{ + int doublebuf, xstretch, ystretch, xres, yres, show_fps; + + FCEUI_printf("Initializing video..."); + + // load the relevant configuration variables + g_config->getOption("SDL.Fullscreen", &s_fullscreen); + g_config->getOption("SDL.DoubleBuffering", &doublebuf); +//#ifdef OPENGL +// g_config->getOption("SDL.OpenGL", &s_useOpenGL); +//#endif + //g_config->getOption("SDL.SpecialFilter", &s_sponge); + g_config->getOption("SDL.XStretch", &xstretch); + g_config->getOption("SDL.YStretch", &ystretch); + //g_config->getOption("SDL.LastXRes", &xres); + //g_config->getOption("SDL.LastYRes", &yres); + g_config->getOption("SDL.ClipSides", &s_clipSides); + g_config->getOption("SDL.NoFrame", &noframe); + g_config->getOption("SDL.ShowFPS", &show_fps); + //g_config->getOption("SDL.XScale", &s_exs); + //g_config->getOption("SDL.YScale", &s_eys); + uint32_t rmask, gmask, bmask; + + s_sponge = 0; + s_exs = 1.0; + s_eys = 1.0; + xres = gui_draw_area_width; + yres = gui_draw_area_height; + // check the starting, ending, and total scan lines + + FCEUI_GetCurrentVidSystem(&s_srendline, &s_erendline); + s_tlines = s_erendline - s_srendline + 1; + + //init_gui_video( s_useOpenGL ); + + s_inited = 1; + + // check to see if we are showing FPS + FCEUI_SetShowFPS(show_fps); + +#ifdef LSB_FIRST + rmask = 0x000000FF; + gmask = 0x0000FF00; + bmask = 0x00FF0000; +#else + rmask = 0x00FF0000; + gmask = 0x0000FF00; + bmask = 0x000000FF; +#endif + + s_curbpp = 32; // Bits per pixel is always 32 + + FCEU_printf(" Video Mode: %d x %d x %d bpp %s\n", + xres, yres, s_curbpp, + s_fullscreen ? "full screen" : ""); + + if (s_curbpp != 8 && s_curbpp != 16 && s_curbpp != 24 && s_curbpp != 32) + { + FCEU_printf(" Sorry, %dbpp modes are not supported by FCE Ultra. Supported bit depths are 8bpp, 16bpp, and 32bpp.\n", s_curbpp); + KillVideo(); + return -1; + } + +#ifdef OPENGL + if(s_exs <= 0.01) { + FCEUD_PrintError("xscale out of bounds."); + KillVideo(); + return -1; + } + if(s_eys <= 0.01) { + FCEUD_PrintError("yscale out of bounds."); + KillVideo(); + return -1; + } + //if(s_sponge && s_useOpenGL) { + // FCEUD_PrintError("scalers not compatible with openGL mode."); + // KillVideo(); + // return -1; + //} +#endif + + if ( !initBlitToHighDone ) + { + InitBlitToHigh(s_curbpp >> 3, + rmask, + gmask, + bmask, + s_eefx, s_sponge, 0); + + initBlitToHighDone = 1; + } + + return 0; +} + +/** + * Toggles the full-screen display. + */ +void ToggleFS(void) +{ + // pause while we we are making the switch + bool paused = FCEUI_EmulationPaused(); + if(!paused) + FCEUI_ToggleEmulationPause(); + + int error, fullscreen = s_fullscreen; + + // shut down the current video system + KillVideo(); + + // flip the fullscreen flag + g_config->setOption("SDL.Fullscreen", !fullscreen); +#ifdef _GTK + if(noGui == 0) + { + if(!fullscreen) + showGui(0); + else + showGui(1); + } +#endif + // try to initialize the video + error = InitVideo(GameInfo); + if(error) { + // if we fail, just continue with what worked before + g_config->setOption("SDL.Fullscreen", fullscreen); + InitVideo(GameInfo); + } + // if we paused to make the switch; unpause + if(!paused) + FCEUI_ToggleEmulationPause(); +} + +static SDL_Color s_psdl[256]; + +/** + * Sets the color for a particular index in the palette. + */ +void +FCEUD_SetPalette(uint8 index, + uint8 r, + uint8 g, + uint8 b) +{ + s_psdl[index].r = r; + s_psdl[index].g = g; + s_psdl[index].b = b; + + s_paletterefresh = 1; +} + +/** + * Gets the color for a particular index in the palette. + */ +void +FCEUD_GetPalette(uint8 index, + uint8 *r, + uint8 *g, + uint8 *b) +{ + *r = s_psdl[index].r; + *g = s_psdl[index].g; + *b = s_psdl[index].b; +} + +/** + * Pushes the palette structure into the underlying video subsystem. + */ +static void RedoPalette() +{ + if (s_curbpp > 8) + { + SetPaletteBlitToHigh((uint8*)s_psdl); + } +} +// XXX soules - console lock/unlock unimplemented? + +///Currently unimplemented. +void LockConsole(){} + +///Currently unimplemented. +void UnlockConsole(){} + +/** + * Pushes the given buffer of bits to the screen. + */ +void +BlitScreen(uint8 *XBuf) +{ + uint8 *dest; + int w, h, pitch; + + // refresh the palette if required + if (s_paletterefresh) + { + RedoPalette(); + s_paletterefresh = 0; + } + + // XXX soules - not entirely sure why this is being done yet + XBuf += s_srendline * 256; + + dest = (uint8*)gl_shm->pixbuf; + w = GL_NES_WIDTH; + h = GL_NES_HEIGHT; + pitch = w*4; + + gl_shm->ncol = NWIDTH; + gl_shm->nrow = s_tlines; + gl_shm->pitch = pitch; + + if ( dest == NULL ) return; + + Blit8ToHigh(XBuf + NOFFSET, dest, NWIDTH, s_tlines, pitch, 1, 1); + + //guiPixelBufferReDraw(); + +#ifdef CREATE_AVI + { int fps = FCEUI_GetDesiredFPS(); + static unsigned char* result = NULL; + static unsigned resultsize = 0; + int width = NWIDTH, height = s_tlines; + if(!result || resultsize != width*height*3*2) + { + if(result) free(result); + result = (unsigned char*) FCEU_dmalloc(resultsize = width*height*3*2); + } + switch(s_curbpp) + { + #if 0 + case 24: case 32: case 15: case 16: + /* Convert to I420 if possible, because our I420 conversion is optimized + * and it'll produce less network traffic, hence faster throughput than + * anything else. And H.264 eats only I420, so it'd be converted sooner + * or later anyway if we didn't do it. Win-win situation. + */ + switch(s_curbpp) + { + case 32: Convert32To_I420Frame(s_screen->pixels, &result[0], width*height, width); break; + case 24: Convert24To_I420Frame(s_screen->pixels, &result[0], width*height, width); break; + case 15: Convert15To_I420Frame(s_screen->pixels, &result[0], width*height, width); break; + case 16: Convert16To_I420Frame(s_screen->pixels, &result[0], width*height, width); break; + } + NESVideoLoggingVideo(&result[0], width,height, fps, 12); + break; + #endif + default: + NESVideoLoggingVideo( dest, width,height, fps, s_curbpp); + } + } +#endif // CREATE_AVI + +#if REALTIME_LOGGING + { + static struct timeval last_time; + static int first_time=1; + extern long soundrate; + + struct timeval cur_time; + gettimeofday(&cur_time, NULL); + + double timediff = + (cur_time.tv_sec *1e6 + cur_time.tv_usec + - (last_time.tv_sec *1e6 + last_time.tv_usec)) / 1e6; + + int nframes = timediff * 60 - 1; + if(first_time) + first_time = 0; + else while(nframes > 0) + { + static const unsigned char Buf[800*4] = {0}; + NESVideoLoggingVideo(screen->pixels, 256,tlines, FCEUI_GetDesiredFPS(), s_curbpp); + NESVideoLoggingAudio(Buf, soundrate,16,1, soundrate/60.0); + --nframes; + } + memcpy(&last_time, &cur_time, sizeof(last_time)); + } +#endif // REALTIME_LOGGING + +} + +/** + * Converts an x-y coordinate in the window manager into an x-y + * coordinate on FCEU's screen. + */ +uint32 +PtoV(uint16 x, + uint16 y) +{ + y = (uint16)((double)y / s_eys); + x = (uint16)((double)x / s_exs); + if(s_clipSides) { + x += 8; + } + y += s_srendline; + return (x | (y << 16)); +} + +bool enableHUDrecording = false; +bool FCEUI_AviEnableHUDrecording() +{ + if (enableHUDrecording) + return true; + + return false; +} +void FCEUI_SetAviEnableHUDrecording(bool enable) +{ + enableHUDrecording = enable; +} + +bool disableMovieMessages = false; +bool FCEUI_AviDisableMovieMessages() +{ + if (disableMovieMessages) + return true; + + return false; +} +void FCEUI_SetAviDisableMovieMessages(bool disable) +{ + disableMovieMessages = disable; +} diff --git a/src/drivers/Qt/sdl-video.h b/src/drivers/Qt/sdl-video.h new file mode 100644 index 00000000..82ac15f7 --- /dev/null +++ b/src/drivers/Qt/sdl-video.h @@ -0,0 +1,17 @@ +#ifndef __FCEU_SDL_VIDEO_H +#define __FCEU_SDL_VIDEO_H +#ifdef _SDL2 +#include +#else +#include +#endif + +uint32 PtoV(uint16 x, uint16 y); +bool FCEUD_ShouldDrawInputAids(); +bool FCEUI_AviDisableMovieMessages(); +bool FCEUI_AviEnableHUDrecording(); +void FCEUI_SetAviEnableHUDrecording(bool enable); +bool FCEUI_AviDisableMovieMessages(); +void FCEUI_SetAviDisableMovieMessages(bool disable); +#endif + diff --git a/src/drivers/Qt/sdl.h b/src/drivers/Qt/sdl.h new file mode 100644 index 00000000..91c6414d --- /dev/null +++ b/src/drivers/Qt/sdl.h @@ -0,0 +1,32 @@ +#ifndef __FCEU_SDL_H +#define __FCEU_SDL_H + +#if _SDL2 +#include +#else +#include +#endif + +#include "main.h" +#include "dface.h" +#include "input.h" + +// I'm using this as a #define so the compiler can optimize the +// modulo operation +#define PERIODIC_SAVE_INTERVAL 5000 // milliseconds + +const int INVALID_STATE = 99; + +extern int noGui; +extern int isloaded; + +extern int dendy; +extern int pal_emulation; +extern bool swapDuty; + +int LoadGame(const char *path); +int CloseGame(void); +void FCEUD_Update(uint8 *XBuf, int32 *Buffer, int Count); +uint64 FCEUD_GetTime(); + +#endif diff --git a/src/drivers/Qt/throttle.h b/src/drivers/Qt/throttle.h new file mode 100644 index 00000000..5709c88a --- /dev/null +++ b/src/drivers/Qt/throttle.h @@ -0,0 +1,2 @@ +void RefreshThrottleFPS(); +int SpeedThrottle(void); diff --git a/src/drivers/Qt/unix-netplay.cpp b/src/drivers/Qt/unix-netplay.cpp new file mode 100644 index 00000000..37fcba12 --- /dev/null +++ b/src/drivers/Qt/unix-netplay.cpp @@ -0,0 +1,366 @@ +/* FCE Ultra - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2002 Xodnizel + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +//todo - ensure that #ifdef WIN32 makes sense +//consider changing this to use sdl net stuff? + +//#include "main.h" +//#include "input.h" +//#include "dface.h" +#include "unix-netplay.h" + +#include "../../fceu.h" +#include "../../driver.h" +#include "../../utils/md5.h" +#include "../../utils/memory.h" + +#include +#include "../common/configSys.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef WIN32 +#include +#else +#include +#include +#include +#include +#include +#include +#endif + +extern Config *g_config; + +#ifndef socklen_t +#define socklen_t int +#endif + +#ifndef SOL_TCP +#define SOL_TCP IPPROTO_TCP +#endif + +int FCEUDnetplay=0; + +static int s_Socket = -1; + +static void +en32(uint8 *buf, + uint32 morp) +{ + buf[0] = morp; + buf[1] = morp >> 8; + buf[2] = morp >> 16; + buf[3] = morp >> 24; +} + +/* +static uint32 de32(uint8 *morp) +{ + return(morp[0]|(morp[1]<<8)|(morp[2]<<16)|(morp[3]<<24)); +} +*/ + +int +FCEUD_NetworkConnect(void) +{ + struct sockaddr_in sockin; + struct hostent *phostentb; + unsigned long hadr; + int TSocket, tcpopt, error; + int netdivisor; + + // get any required configuration variables + int port, localPlayers; + std::string server, username, password, key; + g_config->getOption("SDL.NetworkIP", &server); + g_config->getOption("SDL.NetworkUsername", &username); + g_config->getOption("SDL.NetworkPassword", &password); + g_config->getOption("SDL.NetworkGameKey", &key); + g_config->getOption("SDL.NetworkPort", &port); + g_config->getOption("SDL.NetworkPlayers", &localPlayers); + + + g_config->setOption("SDL.NetworkIP", ""); + g_config->setOption("SDL.NetworkPassword", ""); + g_config->setOption("SDL.NetworkGameKey", ""); + + + + // only initialize if remote server is specified + if(!server.size()) { + return 0; + } + + TSocket = socket(AF_INET, SOCK_STREAM, 0); + if(TSocket < 0) { + const char* s = "Error creating stream socket."; + puts(s); + FCEU_DispMessage(s,0); + FCEUD_NetworkClose(); + return 0; + } + + // try to setup TCP_NODELAY to avoid network jitters + tcpopt = 1; +#ifdef BEOS + error = setsockopt(TSocket, SOL_SOCKET, TCP_NODELAY, &tcpopt, sizeof(int)); +#elif WIN32 + error = setsockopt(TSocket, SOL_TCP, TCP_NODELAY, + (char*)&tcpopt, sizeof(int)); +#else + error = setsockopt(TSocket, SOL_TCP, TCP_NODELAY, &tcpopt, sizeof(int)); +#endif + if(error) { + puts("Nodelay fail"); + } + + memset(&sockin, 0, sizeof(sockin)); + sockin.sin_family = AF_INET; + hadr = inet_addr(server.c_str()); + if(hadr != INADDR_NONE) { + sockin.sin_addr.s_addr = hadr; + } else { + puts("*** Looking up host name..."); + phostentb = gethostbyname(server.c_str()); + if(!phostentb) { + puts("Error getting host network information."); + FCEU_DispMessage("Error getting host info",0); + close(TSocket); + FCEUD_NetworkClose(); + return(0); + } + memcpy(&sockin.sin_addr, phostentb->h_addr, phostentb->h_length); + } + + sockin.sin_port = htons(port); + puts("*** Connecting to remote host..."); + error = connect(TSocket, (struct sockaddr *)&sockin, sizeof(sockin)); + if(error < 0) { + puts("Error connecting to remote host."); + FCEU_DispMessage("Error connecting to server",0); + close(TSocket); + FCEUD_NetworkClose(); + return 0; + } + + s_Socket = TSocket; + + puts("*** Sending initialization data to server..."); + uint8 *sendbuf; + uint8 buf[5]; + uint32 sblen; + + sblen = 4 + 16 + 16 + 64 + 1 + username.size(); + sendbuf = (uint8 *)FCEU_dmalloc(sblen); + memset(sendbuf, 0, sblen); + + // XXX soules - should use htons instead of en32() from above! + //uint32 data = htons(sblen - 4); + //memcpy(sendbuf, &data, sizeof(data)); + en32(sendbuf, sblen - 4); + + if(key.size()) + { + struct md5_context md5; + uint8 md5out[16]; + + md5_starts(&md5); + md5_update(&md5, (uint8*)&GameInfo->MD5.data, 16); + md5_update(&md5, (uint8 *)key.c_str(), key.size()); + md5_finish(&md5, md5out); + memcpy(sendbuf + 4, md5out, 16); + } else + { + memcpy(sendbuf + 4, (uint8*)&GameInfo->MD5.data, 16); + } + + if(password.size()) { + struct md5_context md5; + uint8 md5out[16]; + + md5_starts(&md5); + md5_update(&md5, (uint8 *)password.c_str(), password.size()); + md5_finish(&md5, md5out); + memcpy(sendbuf + 4 + 16, md5out, 16); + } + + memset(sendbuf + 4 + 16 + 16, 0, 64); + + sendbuf[4 + 16 + 16 + 64] = (uint8)localPlayers; + + if(username.size()) { + memcpy(sendbuf + 4 + 16 + 16 + 64 + 1, + username.c_str(), username.size()); + } + +#ifdef WIN32 + send(s_Socket, (char*)sendbuf, sblen, 0); +#else + send(s_Socket, sendbuf, sblen, 0); +#endif + FCEU_dfree(sendbuf); + +#ifdef WIN32 + recv(s_Socket, (char*)buf, 1, 0); +#else + recv(s_Socket, buf, 1, MSG_WAITALL); +#endif + netdivisor = buf[0]; + + puts("*** Connection established."); + FCEU_DispMessage("Connection established.",0); + + FCEUDnetplay = 1; + FCEUI_NetplayStart(localPlayers, netdivisor); + + return 1; +} + + +int +FCEUD_SendData(void *data, + uint32 len) +{ + int check = 0, error = 0; +#ifndef WIN32 + error = ioctl(fileno(stdin), FIONREAD, &check); +#endif + if(!error && check) { + char buf[1024]; + char *f; + + buf[0] = 0; + + if ( fgets(buf, 1024, stdin) ) + { + if((f=strrchr(buf,'\n'))) { + *f = 0; + } + } + FCEUI_NetplayText((uint8 *)buf); + } + +#ifdef WIN32 + send(s_Socket, (char*)data, len ,0); +#else + send(s_Socket, data, len ,0); +#endif + return 1; +} + +int +FCEUD_RecvData(void *data, + uint32 len) +{ + int size; + //NoWaiting &= ~2; + + for(;;) + { + fd_set funfun; + struct timeval popeye; + + popeye.tv_sec=0; + popeye.tv_usec=100000; + + FD_ZERO(&funfun); + FD_SET(s_Socket, &funfun); + + switch(select(s_Socket + 1,&funfun,0,0,&popeye)) { + case 0: continue; + case -1:return 0; + } + + if(FD_ISSET(s_Socket,&funfun)) { +#ifdef WIN32 + size = recv(s_Socket, (char*)data, len, 0); +#else + size = recv(s_Socket, data, len, MSG_WAITALL); +#endif + + if(size == len) { + //unsigned long beefie; + + FD_ZERO(&funfun); + FD_SET(s_Socket, &funfun); + + popeye.tv_sec = popeye.tv_usec = 0; + if(select(s_Socket + 1, &funfun, 0, 0, &popeye) == 1) + //if(!ioctl(s_Socket,FIONREAD,&beefie)) + // if(beefie) + { + //NoWaiting|=2; + } + return 1; + } else { + return 0; + } + } + } + + return 0; +} + +void +FCEUD_NetworkClose(void) +{ + if(s_Socket > 0) { +#ifdef BEOS + closesocket(s_Socket); +#else + close(s_Socket); +#endif + } + s_Socket = -1; + + if(FCEUDnetplay) { + FCEUI_NetplayStop(); + } + FCEUDnetplay = 0; +} + + +void +FCEUD_NetplayText(uint8 *text) +{ + char *tot = (char *)FCEU_dmalloc(strlen((const char *)text) + 1); + char *tmp; + if (!tot) + return; + strcpy(tot, (const char *)text); + tmp = tot; + + while(*tmp) { + if(*tmp < 0x20) { + *tmp = ' '; + } + tmp++; + } + puts(tot); + FCEU_dfree(tot); +} diff --git a/src/drivers/Qt/unix-netplay.h b/src/drivers/Qt/unix-netplay.h new file mode 100644 index 00000000..27b1de43 --- /dev/null +++ b/src/drivers/Qt/unix-netplay.h @@ -0,0 +1,6 @@ +extern char *netplaynick; +extern char *netplayhost; +extern char *netpassword; +extern char *netgamekey; +extern int tport; +extern int netlocalplayers; diff --git a/src/fceux.pro b/src/fceux.pro new file mode 100644 index 00000000..24cf00c0 --- /dev/null +++ b/src/fceux.pro @@ -0,0 +1,305 @@ +###################################################################### +# Automatically generated by qmake (3.1) Sat Jun 20 21:20:47 2020 +###################################################################### + +TEMPLATE = app +TARGET = fceux +INCLUDEPATH += . + +# The following define makes your compiler warn you if you use any +# feature of Qt which has been marked as deprecated (the exact warnings +# depend on your compiler). Please consult the documentation of the +# deprecated API in order to know how to port your code away from it. +DEFINES += QT_DEPRECATED_WARNINGS + +# You can also make your code fail to compile if you use deprecated APIs. +# In order to do so, uncomment the following line. +# You can also select to disable deprecated APIs only up to a certain version of Qt. +#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 + +QT += widgets + +CONFIG += object_parallel_to_source + +unix { + QT_CONFIG -= no-pkg-config + CONFIG += link_pkgconfig + + QMAKE_CXXFLAGS += -DPSS_STYLE=1 -DHAVE_ASPRINTF + + packagesExist(minizip){ + PKGCONFIG += minizip + QMAKE_CXXFLAGS += -D_SYSTEM_MINIZIP + } + + packagesExist(zlib){ + PKGCONFIG += zlib + } + + PKGCONFIG += sdl2 + + packagesExist(lua-5.1){ + PKGCONFIG += lua-5.1 + QMAKE_CXXFLAGS += -D_S9XLUA_H + } + + QMAKE_CXXFLAGS += -Wall -Wno-write-strings -Wno-sign-compare -Wno-parentheses -Wno-unused-local-typedefs +} + +# Input +SOURCES += asm.cpp +SOURCES += cart.cpp +SOURCES += cheat.cpp +SOURCES += conddebug.cpp +SOURCES += config.cpp +SOURCES += debug.cpp +SOURCES += drawing.cpp +SOURCES += fceu.cpp +SOURCES += fds.cpp +SOURCES += file.cpp +SOURCES += emufile.cpp +SOURCES += filter.cpp +SOURCES += ines.cpp +SOURCES += input.cpp +SOURCES += movie.cpp +SOURCES += netplay.cpp +SOURCES += nsf.cpp +SOURCES += oldmovie.cpp +SOURCES += palette.cpp +SOURCES += ppu.cpp +SOURCES += sound.cpp +SOURCES += state.cpp +SOURCES += unif.cpp +SOURCES += video.cpp +SOURCES += vsuni.cpp +SOURCES += wave.cpp +SOURCES += x6502.cpp + +unix { + packagesExist(lua-5.1){ + SOURCES += lua-engine.cpp + } +} +SOURCES += boards/01-222.cpp +SOURCES += boards/09-034a.cpp +SOURCES += boards/103.cpp +SOURCES += boards/106.cpp +SOURCES += boards/108.cpp +SOURCES += boards/112.cpp +SOURCES += boards/116.cpp +SOURCES += boards/117.cpp +SOURCES += boards/120.cpp +SOURCES += boards/121.cpp +SOURCES += boards/12in1.cpp +SOURCES += boards/151.cpp +SOURCES += boards/156.cpp +SOURCES += boards/158B.cpp +SOURCES += boards/15.cpp +SOURCES += boards/164.cpp +SOURCES += boards/168.cpp +SOURCES += boards/170.cpp +SOURCES += boards/175.cpp +SOURCES += boards/176.cpp +SOURCES += boards/177.cpp +SOURCES += boards/178.cpp +SOURCES += boards/183.cpp +SOURCES += boards/185.cpp +SOURCES += boards/186.cpp +SOURCES += boards/187.cpp +SOURCES += boards/189.cpp +SOURCES += boards/18.cpp +SOURCES += boards/190.cpp +SOURCES += boards/193.cpp +SOURCES += boards/199.cpp +SOURCES += boards/206.cpp +SOURCES += boards/208.cpp +SOURCES += boards/222.cpp +SOURCES += boards/225.cpp +SOURCES += boards/228.cpp +SOURCES += boards/230.cpp +SOURCES += boards/232.cpp +SOURCES += boards/234.cpp +SOURCES += boards/235.cpp +SOURCES += boards/244.cpp +SOURCES += boards/246.cpp +SOURCES += boards/252.cpp +SOURCES += boards/253.cpp +SOURCES += boards/28.cpp +SOURCES += boards/32.cpp +SOURCES += boards/33.cpp +SOURCES += boards/34.cpp +SOURCES += boards/36.cpp +SOURCES += boards/3d-block.cpp +SOURCES += boards/40.cpp +SOURCES += boards/411120-c.cpp +SOURCES += boards/41.cpp +SOURCES += boards/42.cpp +SOURCES += boards/43.cpp +SOURCES += boards/46.cpp +SOURCES += boards/50.cpp +SOURCES += boards/51.cpp +SOURCES += boards/57.cpp +SOURCES += boards/603-5052.cpp +SOURCES += boards/62.cpp +SOURCES += boards/65.cpp +SOURCES += boards/67.cpp +SOURCES += boards/68.cpp +SOURCES += boards/69.cpp +SOURCES += boards/71.cpp +SOURCES += boards/72.cpp +SOURCES += boards/77.cpp +SOURCES += boards/79.cpp +SOURCES += boards/80013-B.cpp +SOURCES += boards/80.cpp +SOURCES += boards/8157.cpp +SOURCES += boards/8237.cpp +SOURCES += boards/82.cpp +SOURCES += boards/830118C.cpp +SOURCES += boards/88.cpp +SOURCES += boards/8in1.cpp +SOURCES += boards/90.cpp +SOURCES += boards/91.cpp +SOURCES += boards/96.cpp +SOURCES += boards/99.cpp +SOURCES += boards/a9746.cpp +SOURCES += boards/ac-08.cpp +SOURCES += boards/addrlatch.cpp +SOURCES += boards/ax5705.cpp +SOURCES += boards/bandai.cpp +SOURCES += boards/bb.cpp +SOURCES += boards/bmc13in1jy110.cpp +SOURCES += boards/bmc42in1r.cpp +SOURCES += boards/bmc64in1nr.cpp +SOURCES += boards/bmc70in1.cpp +SOURCES += boards/BMW8544.cpp +SOURCES += boards/bonza.cpp +SOURCES += boards/bs-5.cpp +SOURCES += boards/cheapocabra.cpp +SOURCES += boards/cityfighter.cpp +SOURCES += boards/coolboy.cpp +SOURCES += boards/dance2000.cpp +SOURCES += boards/datalatch.cpp +SOURCES += boards/dream.cpp +SOURCES += boards/__dummy_mapper.cpp +SOURCES += boards/edu2000.cpp +SOURCES += boards/eh8813a.cpp +SOURCES += boards/emu2413.c +SOURCES += boards/et-100.cpp +SOURCES += boards/et-4320.cpp +SOURCES += boards/F-15.cpp +SOURCES += boards/famicombox.cpp +SOURCES += boards/ffe.cpp +SOURCES += boards/fk23c.cpp +SOURCES += boards/fns.cpp +SOURCES += boards/ghostbusters63in1.cpp +SOURCES += boards/gs-2004.cpp +SOURCES += boards/gs-2013.cpp +SOURCES += boards/h2288.cpp +SOURCES += boards/hp10xx_hp20xx.cpp +SOURCES += boards/hp898f.cpp +SOURCES += boards/inlnsf.cpp +SOURCES += boards/karaoke.cpp +SOURCES += boards/kof97.cpp +SOURCES += boards/ks7010.cpp +SOURCES += boards/ks7012.cpp +SOURCES += boards/ks7013.cpp +SOURCES += boards/ks7016.cpp +SOURCES += boards/ks7017.cpp +SOURCES += boards/ks7030.cpp +SOURCES += boards/ks7031.cpp +SOURCES += boards/ks7032.cpp +SOURCES += boards/ks7037.cpp +SOURCES += boards/ks7057.cpp +SOURCES += boards/le05.cpp +SOURCES += boards/lh32.cpp +SOURCES += boards/lh53.cpp +SOURCES += boards/malee.cpp +SOURCES += boards/mihunche.cpp +SOURCES += boards/mmc1.cpp +SOURCES += boards/mmc2and4.cpp +SOURCES += boards/mmc3.cpp +SOURCES += boards/mmc5.cpp +SOURCES += boards/n106.cpp +SOURCES += boards/n625092.cpp +SOURCES += boards/novel.cpp +SOURCES += boards/onebus.cpp +SOURCES += boards/pec-586.cpp +SOURCES += boards/rt-01.cpp +SOURCES += boards/sa-9602b.cpp +SOURCES += boards/sachen.cpp +SOURCES += boards/sb-2000.cpp +SOURCES += boards/sc-127.cpp +SOURCES += boards/sheroes.cpp +SOURCES += boards/sl1632.cpp +SOURCES += boards/subor.cpp +SOURCES += boards/super24.cpp +SOURCES += boards/supervision.cpp +SOURCES += boards/t-227-1.cpp +SOURCES += boards/t-262.cpp +SOURCES += boards/tengen.cpp +SOURCES += boards/tf-1201.cpp +SOURCES += boards/transformer.cpp +SOURCES += boards/unrom512.cpp +SOURCES += boards/vrc1.cpp +SOURCES += boards/vrc2and4.cpp +SOURCES += boards/vrc3.cpp +SOURCES += boards/vrc5.cpp +SOURCES += boards/vrc6.cpp +SOURCES += boards/vrc7.cpp +SOURCES += boards/vrc7p.cpp +SOURCES += boards/yoko.cpp +SOURCES += input/arkanoid.cpp +SOURCES += input/bworld.cpp +SOURCES += input/cursor.cpp +SOURCES += input/fkb.cpp +SOURCES += input/fns.cpp +SOURCES += input/ftrainer.cpp +SOURCES += input/hypershot.cpp +SOURCES += input/mahjong.cpp +SOURCES += input/mouse.cpp +SOURCES += input/oekakids.cpp +SOURCES += input/pec586kb.cpp +SOURCES += input/powerpad.cpp +SOURCES += input/quiz.cpp +SOURCES += input/shadow.cpp +SOURCES += input/snesmouse.cpp +SOURCES += input/suborkb.cpp +SOURCES += input/toprider.cpp +SOURCES += input/virtualboy.cpp +SOURCES += input/zapper.cpp +SOURCES += utils/backward.cpp +SOURCES += utils/ConvertUTF.c +SOURCES += utils/xstring.cpp +SOURCES += utils/crc32.cpp +SOURCES += utils/endian.cpp +SOURCES += utils/general.cpp +SOURCES += utils/guid.cpp +SOURCES += utils/md5.cpp +SOURCES += utils/memory.cpp +SOURCES += drivers/common/args.cpp +SOURCES += drivers/common/cheat.cpp +SOURCES += drivers/common/config.cpp +SOURCES += drivers/common/configSys.cpp +SOURCES += drivers/common/hq2x.cpp +SOURCES += drivers/common/hq3x.cpp +SOURCES += drivers/common/scale2x.cpp +SOURCES += drivers/common/scale3x.cpp +SOURCES += drivers/common/scalebit.cpp +SOURCES += drivers/common/vidblit.cpp +SOURCES += drivers/common/nes_ntsc.c + +HEADERS += drivers/Qt/GameApp.h +HEADERS += drivers/Qt/GameViewer.h +SOURCES += drivers/Qt/main.cpp +SOURCES += drivers/Qt/GameApp.cpp +SOURCES += drivers/Qt/GameViewer.cpp +SOURCES += drivers/Qt/fceuWrapper.cpp +SOURCES += drivers/Qt/config.cpp +SOURCES += drivers/Qt/input.cpp +SOURCES += drivers/Qt/gl_win.cpp +SOURCES += drivers/Qt/sdl-sound.cpp +SOURCES += drivers/Qt/sdl-video.cpp +SOURCES += drivers/Qt/sdl-joystick.cpp +SOURCES += drivers/Qt/sdl-throttle.cpp +SOURCES += drivers/Qt/unix-netplay.cpp +