diff --git a/.gitignore b/.gitignore index 070ae89b..04d5c0d0 100644 --- a/.gitignore +++ b/.gitignore @@ -24,6 +24,8 @@ /output/sav/*.sav /output/fcs/*.fc* /vc/userconfig/scmrev.h +/vc/fceux.zip +/vc/fceux64.zip # linux build output bin diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 00000000..fe75fad4 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,7 @@ + +cmake_minimum_required(VERSION 3.1) + +project(fceux) + +add_subdirectory( src ) + diff --git a/README b/README index d906928f..53c559fc 100644 --- a/README +++ b/README @@ -1,12 +1,13 @@ -FCEUX SDL 2.2.1 SDL README +FCEUX SDL 2.2.3 SDL README ========================== -By Lukas Sabota (sf: punkrockguy318) +Originally By Lukas Sabota (sf: punkrockguy318) +Updated By mjbudd77 -[NOTE: This is old and out of date and only applies to SDL (non windows) builds] +[NOTE: This only applies to SDL (non windows) builds] http://www.fceux.com -Last Modified: March 10, 2013 +Last Modified: July 12, 2020 Table of Contents ----------------- @@ -21,58 +22,64 @@ Table of Contents 1 - Requirements ---------------- -* libsdl1.2 - It is strongly recommended that you upgrade to the latest - version of sdl (1.2.15 at the time of writing). -* scons - Required to build fceux. -* libgtk2.0 (optional) - version >= 2.24 recommended -* libgtk3.0 (optional) - this compiles as of fceux 2.2.0 -* liblua5.1 (optional) -* libgd (optional) - required for LOGO and CREATE_AVI options (https://bitbucket.org/libgd/gd-libgd/downloads) -* minizip (optional) - you may chose to use the version of minizip on your system by enabling SYSTEM_MINIZIP in the SConstruct +* sdl2 - Version >= 2.0 +* cmake - Required to build fceux. +* qt5 - version >= 5.11 recommended +* liblua5.1 (optional) - Will statically link internally if the system cannot provide this. +* minizip +* zlib +* openGL * c++ compiler -- you may use g++ from gcc or clang++ from llvm. 2 - Installation ---------------- -Fceux can be compiled and built using the scons build system. To compile, run: +Fceux can be compiled and built using the cmake build system. To compile, run: - scons + mkdir build; cd build; + cmake -DCMAKE_BUILD_TYPE=Release .. # For a release build + +To build a binary with debug information included in it: + cmake -DCMAKE_BUILD_TYPE=Debug .. + +To do the actual compiling: + make + +To compile faster with multiple processes in parallel: + make -j `nproc` After a sucessful compilation, the fceux binary will be generated to -./src/fceux . You can install fceux to your system with the following command: +./build/src/fceux . You can install fceux to your system with the following command: - scons install + make install -You can optionally define a prefix: +You can optionally define a install prefix when running cmake from the previous step: - scons --prefix=/usr/local install + cmake -DCMAKE_INSTALL_PREFIX=/usr/local install You can choose to install the lua scripts (located in output/luaScripts) to a directory of your choosing: cp -R output/luaScripts /usr/local/some/directory/that/i/will/find/later -If you would like to clean the temporary scons files to perform a 'make clean' like function, you can do the following: +If you would like to do a full clean build a 'make clean' like function, you can do either of following: - scons -c && rm -rf .scon* + make clean # from inside build directory + +OR: + Delete build directory and start over at initial cmake step: + rm -rf build; 3 - Compile-time options ------------------------ You can enable and disable certain features of fceux at build time. -To edit these options, edit the "BoolOptions" following the "opts.AddVariables" method -at the head of the "SConstruct" file in this source directory. The -default options will be fine for most users, but power users may want to -tweak some of these options. +Look in the src/CMakeList.txt file to tweak options. 4 - GUI ------- -You can enable the GTK GUI by setting GTK to 1 in the SConstruct build file. -GfceuX is deprecated in favor of the new GTK GUI. You can disable the GTK GUI at -run-time by passing the --nogui option, or disable it at build-time by setting -GTK to 0 in the SConstruct file. If you prefer GTK3 to GTK2, you can set the -GTK3 BoolVariable to 1 in the SConstruct. +The Qt GUI is required and automatically builds as part of the build. 5 - LUA Scripting ----------------- -FCEUX provides a LUA 5.1 engine that allows for in-game scripting capabilities. LUA can be enabled or disabled at build time by adjusting the "LUA" BoolVariable in the SConstruct file. +FCEUX provides a LUA 5.1 engine that allows for in-game scripting capabilities. LUA is enabled either way. It is just a matter of whether LUA is statically linked internally or dynamically linked to a system library. A collection of LUA scripts are provided with the source distribuition in the output directory: @@ -94,7 +101,7 @@ Finally, if any scripts complaints about "attempt to index global 'iup' (a nil v require("iuplua") -The latest version of iup (3.5 at the time of writing) is recomended. +The latest version of iup (3.5 at the time of writing) is recommended. 6 - FAQ ------- @@ -116,4 +123,4 @@ Running fceux through esddsp is known to fix some audio issues with pulseaudio o 7 - Contact ----------- -If you have an issue with fceux, report it in the sourceforge bug tracker (see fceux.com). If you would like to contact the author of this readme personally, e-mail LTsmooth42 gmail com. You can also check us out at #fceu on irc.freenode.net. +If you have an issue with fceux, report it in the github bug tracker (see fceux at github.com). If you would like to contact the author of this readme personally, e-mail LTsmooth42 gmail com. You can also check us out at #fceu on irc.freenode.net. diff --git a/TODO-SDL b/TODO-SDL index 95defb4b..67111867 100644 --- a/TODO-SDL +++ b/TODO-SDL @@ -1,47 +1,25 @@ Priorities ========== - * SDL 2.0 RC is released - SDL2.0 compatibility is a goal - * Backwards-cpp still has an issue with clang++; look into this - * Users are reporting crashing issues with hotkey dialog (probably because its a mess!). A huge chunk of the hotkey code should be rewritten (GUI and hotkey structs - or lack there-of) - * GTK File menu quit element has "CTRL-Q" accelerator. This causes confusion with there being another SDL Hotkey for quit. This should be addressed. - * Quit was mapped to '0' to prevent users from accidently quitting. Perhaps a default quit combo could be used. + * Clean out old unused files - scons build system is dead, cmake is the way to go. + * GTK GUI was not cross-platform. Has been replaced in favor of Qt5. Need to clean out dead code. + * Cheat Editor will be a high priority. + * Code cleanup. Lots of compiler warning with newer GCC. Maybe I'm OCD... but these warnings bother me. Features ======== - * SDL.Vsync - * lets wait on this -- theres no simple way to use the OS default in SDL unless we just dont touch it, which might be the best thing to do here. + * Emulator no runs as a separate thread from the GUI. Much improved performance. + * Cross platform QT GUI is fully functional minus Debug Tools and Cheat Menu. -GTK +QT === - * Better on-the-fly video resizing with window resize / video config - * Smarter video config (disable widgets that are not used when openGL is enabled) - * Options to investigate: - * bpp - * scanlines - * GUI Cheat editor - -SDL 2.0 -======= - * segfaults when opening a second game - * segfaults on fullscreen entry - * has not been tested in a while + * Clean out rest of old GTK comments and #ifdefs + * GUI Cheat editor TODO + * GUI Debug Tools TODO + * GUI should compile in windows as well.... but testing is not a priority since the windows gui has a totally separate backend. BUGS ==== - * F1 from terminal-less gui fceux process hangs fceux (since input is required from console in cheat editor) - -OS X -==== - * Single window mode does not work (the XWINDOWID hack does not work in Apples X11 server, so this may never get fixed). - * It is possible to use GTK to build native OS X menus: http://developer.gnome.org/gtk3/3.4/GtkApplication.html . It would be awesome to do this and hide the main GTK window if the top bar is available - * Zapper input is taken from GTK window instead of X11 window (a workaround could be implemented to resolve with with some #ifdef APPLE etc) - * Not an "official" target, but testing should be done before release on OS X - * DMG Static binary download for Intel OS X - * Include needful libaries - * Adjust scons to produce static binary/libraries with an option - * http://www.scons.org/wiki/StaticallyLink DOCS ==== - * Be sure to include details about new scons features for package maintainers so that the manpage, luascripts, and auxlib will be included in future packages * Docs REALLY need a cleanup/rewrite diff --git a/_config.yml b/_config.yml new file mode 100644 index 00000000..4f848b1c --- /dev/null +++ b/_config.yml @@ -0,0 +1,43 @@ +# jekyll configuration for github pages + +# ignore stuff not part of the website, everything except: +# - documentation/ +# - web/ +# - fceux.png +# - index.html +exclude: +- attic +- fceux-server +- getSDLKey +- gfceu +- m4 +- output +- pipelines +- src +- vc +- .gitignore +- COPYING +- ChangeLog +- INSTALL +- Makefile.am +- NEWS +- NewPPUtests.txt +- README +- SConstruct +- STYLE-GUIDELINES-SDL +- TODO-SDL +- _config.yml +- appveyor.yml +- autogen.sh +- azure-pipelines.yml +- changelog.txt +- configure.ac +- debian-crossbuild.sh +- doxygen +- fceux.desktop +- readme.md +- fceux-server/fceux-net-server.exe +- vc/BizHawk.Build.Tool.exe +- vc/pscp.exe +- vc/upx.exe +- vc/zip.exe diff --git a/appveyor.yml b/appveyor.yml index 9337bac1..696e0c74 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,8 +1,52 @@ version: 1.0.{build} -image: -- Visual Studio 2019 -- Ubuntu2004 - #- Ubuntu1804 -build_script: -- cmd: pipelines/win32_build.bat -- sh: ./pipelines/linux_build.sh + +environment: + matrix: + + - job_name: Windows 32 + appveyor_build_worker_image: Visual Studio 2019 + + - job_name: Windows 64 + appveyor_build_worker_image: Visual Studio 2019 + + - job_name: Ubuntu + appveyor_build_worker_image: Ubuntu2004 + #appveyor_build_worker_image: Ubuntu1804 + + - job_name: MacOS + appveyor_build_worker_image: macOS + +for: + + - + matrix: + only: + - job_name: Windows 32 + + build_script: + - cmd: pipelines/win32_build.bat + + - + matrix: + only: + - job_name: Windows 64 + + build_script: + - cmd: pipelines/win64_build.bat + + - + matrix: + only: + - job_name: Ubuntu + + build_script: + - sh: ./pipelines/linux_build.sh + + - + matrix: + only: + - job_name: MacOS + + build_script: + - sh: ./pipelines/macOS_build.sh + diff --git a/fceux.icns b/fceux.icns new file mode 100644 index 00000000..938275fd Binary files /dev/null and b/fceux.icns differ diff --git a/fceux.pro b/fceux.pro new file mode 100644 index 00000000..fec9f599 --- /dev/null +++ b/fceux.pro @@ -0,0 +1,369 @@ +###################################################################### +# 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 + +INCLUDEPATH += src src/drivers + +ENABLE_LUA = 0 +USE_INTERNAL_LUA = 0 + +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 + USE_INTERNAL_LUA = 0; + QMAKE_CXXFLAGS += -D_S9XLUA_H + } else { + USE_INTERNAL_LUA = 1; + QMAKE_CXXFLAGS += -D_S9XLUA_H + } + ENABLE_LUA = 1 + + QMAKE_CXXFLAGS -= -O2 + QMAKE_CXXFLAGS += -D__QT_DRIVER__ -O0 -g3 -Wall -Wno-write-strings -Wno-sign-compare -Wno-parentheses -Wno-unused-local-typedefs + QMAKE_CXXFLAGS_RELEASE -= -O2 + + LIBS += -lz +} + +# Input +SOURCES += src/asm.cpp +SOURCES += src/cart.cpp +SOURCES += src/cheat.cpp +SOURCES += src/conddebug.cpp +SOURCES += src/config.cpp +SOURCES += src/debug.cpp +SOURCES += src/drawing.cpp +SOURCES += src/fceu.cpp +SOURCES += src/fds.cpp +SOURCES += src/file.cpp +SOURCES += src/emufile.cpp +SOURCES += src/filter.cpp +SOURCES += src/ines.cpp +SOURCES += src/input.cpp +SOURCES += src/movie.cpp +SOURCES += src/netplay.cpp +SOURCES += src/nsf.cpp +SOURCES += src/oldmovie.cpp +SOURCES += src/palette.cpp +SOURCES += src/ppu.cpp +SOURCES += src/sound.cpp +SOURCES += src/state.cpp +SOURCES += src/unif.cpp +SOURCES += src/video.cpp +SOURCES += src/vsuni.cpp +SOURCES += src/wave.cpp +SOURCES += src/x6502.cpp + +isEqual( ENABLE_LUA, 1 ) { + isEqual( USE_INTERNAL_LUA, 1 ) { + message("Enabling Internal LUA") + INCLUDEPATH += src/lua/src + SOURCES += src/lua/src/lapi.c + SOURCES += src/lua/src/lauxlib.c + SOURCES += src/lua/src/lbaselib.c + SOURCES += src/lua/src/lcode.c + SOURCES += src/lua/src/ldblib.c + SOURCES += src/lua/src/ldebug.c + SOURCES += src/lua/src/ldo.c + SOURCES += src/lua/src/ldump.c + SOURCES += src/lua/src/lfunc.c + SOURCES += src/lua/src/lgc.c + SOURCES += src/lua/src/linit.c + SOURCES += src/lua/src/liolib.c + SOURCES += src/lua/src/llex.c + SOURCES += src/lua/src/lmathlib.c + SOURCES += src/lua/src/lmem.c + SOURCES += src/lua/src/loadlib.c + SOURCES += src/lua/src/lobject.c + SOURCES += src/lua/src/lopcodes.c + SOURCES += src/lua/src/loslib.c + SOURCES += src/lua/src/lparser.c + SOURCES += src/lua/src/lstate.c + SOURCES += src/lua/src/lstring.c + SOURCES += src/lua/src/lstrlib.c + SOURCES += src/lua/src/ltable.c + SOURCES += src/lua/src/ltablib.c + SOURCES += src/lua/src/ltm.c + SOURCES += src/lua/src/lundump.c + SOURCES += src/lua/src/lvm.c + SOURCES += src/lua/src/lzio.c + SOURCES += src/lua/src/print.c + SOURCES += src/lua-engine.cpp + } else { + message("Enabling System LUA") + SOURCES += src/lua-engine.cpp + } + message("Enabling LUA") +} else { + message("Disabling LUA") +} + +SOURCES += src/boards/01-222.cpp +SOURCES += src/boards/09-034a.cpp +SOURCES += src/boards/103.cpp +SOURCES += src/boards/106.cpp +SOURCES += src/boards/108.cpp +SOURCES += src/boards/112.cpp +SOURCES += src/boards/116.cpp +SOURCES += src/boards/117.cpp +SOURCES += src/boards/120.cpp +SOURCES += src/boards/121.cpp +SOURCES += src/boards/12in1.cpp +SOURCES += src/boards/151.cpp +SOURCES += src/boards/156.cpp +SOURCES += src/boards/158B.cpp +SOURCES += src/boards/15.cpp +SOURCES += src/boards/164.cpp +SOURCES += src/boards/168.cpp +SOURCES += src/boards/170.cpp +SOURCES += src/boards/175.cpp +SOURCES += src/boards/176.cpp +SOURCES += src/boards/177.cpp +SOURCES += src/boards/178.cpp +SOURCES += src/boards/183.cpp +SOURCES += src/boards/185.cpp +SOURCES += src/boards/186.cpp +SOURCES += src/boards/187.cpp +SOURCES += src/boards/189.cpp +SOURCES += src/boards/18.cpp +SOURCES += src/boards/190.cpp +SOURCES += src/boards/193.cpp +SOURCES += src/boards/199.cpp +SOURCES += src/boards/206.cpp +SOURCES += src/boards/208.cpp +SOURCES += src/boards/222.cpp +SOURCES += src/boards/225.cpp +SOURCES += src/boards/228.cpp +SOURCES += src/boards/230.cpp +SOURCES += src/boards/232.cpp +SOURCES += src/boards/234.cpp +SOURCES += src/boards/235.cpp +SOURCES += src/boards/244.cpp +SOURCES += src/boards/246.cpp +SOURCES += src/boards/252.cpp +SOURCES += src/boards/253.cpp +SOURCES += src/boards/28.cpp +SOURCES += src/boards/32.cpp +SOURCES += src/boards/33.cpp +SOURCES += src/boards/34.cpp +SOURCES += src/boards/36.cpp +SOURCES += src/boards/3d-block.cpp +SOURCES += src/boards/40.cpp +SOURCES += src/boards/411120-c.cpp +SOURCES += src/boards/41.cpp +SOURCES += src/boards/42.cpp +SOURCES += src/boards/43.cpp +SOURCES += src/boards/46.cpp +SOURCES += src/boards/50.cpp +SOURCES += src/boards/51.cpp +SOURCES += src/boards/57.cpp +SOURCES += src/boards/603-5052.cpp +SOURCES += src/boards/62.cpp +SOURCES += src/boards/65.cpp +SOURCES += src/boards/67.cpp +SOURCES += src/boards/68.cpp +SOURCES += src/boards/69.cpp +SOURCES += src/boards/71.cpp +SOURCES += src/boards/72.cpp +SOURCES += src/boards/77.cpp +SOURCES += src/boards/79.cpp +SOURCES += src/boards/80013-B.cpp +SOURCES += src/boards/80.cpp +SOURCES += src/boards/8157.cpp +SOURCES += src/boards/8237.cpp +SOURCES += src/boards/82.cpp +SOURCES += src/boards/830118C.cpp +SOURCES += src/boards/88.cpp +SOURCES += src/boards/8in1.cpp +SOURCES += src/boards/90.cpp +SOURCES += src/boards/91.cpp +SOURCES += src/boards/96.cpp +SOURCES += src/boards/99.cpp +SOURCES += src/boards/a9746.cpp +SOURCES += src/boards/ac-08.cpp +SOURCES += src/boards/addrlatch.cpp +SOURCES += src/boards/ax5705.cpp +SOURCES += src/boards/bandai.cpp +SOURCES += src/boards/bb.cpp +SOURCES += src/boards/bmc13in1jy110.cpp +SOURCES += src/boards/bmc42in1r.cpp +SOURCES += src/boards/bmc64in1nr.cpp +SOURCES += src/boards/bmc70in1.cpp +SOURCES += src/boards/BMW8544.cpp +SOURCES += src/boards/bonza.cpp +SOURCES += src/boards/bs-5.cpp +SOURCES += src/boards/cheapocabra.cpp +SOURCES += src/boards/cityfighter.cpp +SOURCES += src/boards/coolboy.cpp +SOURCES += src/boards/dance2000.cpp +SOURCES += src/boards/datalatch.cpp +SOURCES += src/boards/dream.cpp +SOURCES += src/boards/__dummy_mapper.cpp +SOURCES += src/boards/edu2000.cpp +SOURCES += src/boards/eh8813a.cpp +SOURCES += src/boards/emu2413.c +SOURCES += src/boards/et-100.cpp +SOURCES += src/boards/et-4320.cpp +SOURCES += src/boards/F-15.cpp +SOURCES += src/boards/famicombox.cpp +SOURCES += src/boards/ffe.cpp +SOURCES += src/boards/fk23c.cpp +SOURCES += src/boards/fns.cpp +SOURCES += src/boards/ghostbusters63in1.cpp +SOURCES += src/boards/gs-2004.cpp +SOURCES += src/boards/gs-2013.cpp +SOURCES += src/boards/h2288.cpp +SOURCES += src/boards/hp10xx_hp20xx.cpp +SOURCES += src/boards/hp898f.cpp +SOURCES += src/boards/inlnsf.cpp +SOURCES += src/boards/karaoke.cpp +SOURCES += src/boards/kof97.cpp +SOURCES += src/boards/ks7010.cpp +SOURCES += src/boards/ks7012.cpp +SOURCES += src/boards/ks7013.cpp +SOURCES += src/boards/ks7016.cpp +SOURCES += src/boards/ks7017.cpp +SOURCES += src/boards/ks7030.cpp +SOURCES += src/boards/ks7031.cpp +SOURCES += src/boards/ks7032.cpp +SOURCES += src/boards/ks7037.cpp +SOURCES += src/boards/ks7057.cpp +SOURCES += src/boards/le05.cpp +SOURCES += src/boards/lh32.cpp +SOURCES += src/boards/lh53.cpp +SOURCES += src/boards/malee.cpp +SOURCES += src/boards/mihunche.cpp +SOURCES += src/boards/mmc1.cpp +SOURCES += src/boards/mmc2and4.cpp +SOURCES += src/boards/mmc3.cpp +SOURCES += src/boards/mmc5.cpp +SOURCES += src/boards/n106.cpp +SOURCES += src/boards/n625092.cpp +SOURCES += src/boards/novel.cpp +SOURCES += src/boards/onebus.cpp +SOURCES += src/boards/pec-586.cpp +SOURCES += src/boards/rt-01.cpp +SOURCES += src/boards/sa-9602b.cpp +SOURCES += src/boards/sachen.cpp +SOURCES += src/boards/sb-2000.cpp +SOURCES += src/boards/sc-127.cpp +SOURCES += src/boards/sheroes.cpp +SOURCES += src/boards/sl1632.cpp +SOURCES += src/boards/subor.cpp +SOURCES += src/boards/super24.cpp +SOURCES += src/boards/supervision.cpp +SOURCES += src/boards/t-227-1.cpp +SOURCES += src/boards/t-262.cpp +SOURCES += src/boards/tengen.cpp +SOURCES += src/boards/tf-1201.cpp +SOURCES += src/boards/transformer.cpp +SOURCES += src/boards/unrom512.cpp +SOURCES += src/boards/vrc1.cpp +SOURCES += src/boards/vrc2and4.cpp +SOURCES += src/boards/vrc3.cpp +SOURCES += src/boards/vrc5.cpp +SOURCES += src/boards/vrc6.cpp +SOURCES += src/boards/vrc7.cpp +SOURCES += src/boards/vrc7p.cpp +SOURCES += src/boards/yoko.cpp +SOURCES += src/input/arkanoid.cpp +SOURCES += src/input/bworld.cpp +SOURCES += src/input/cursor.cpp +SOURCES += src/input/fkb.cpp +SOURCES += src/input/fns.cpp +SOURCES += src/input/ftrainer.cpp +SOURCES += src/input/hypershot.cpp +SOURCES += src/input/mahjong.cpp +SOURCES += src/input/mouse.cpp +SOURCES += src/input/oekakids.cpp +SOURCES += src/input/pec586kb.cpp +SOURCES += src/input/powerpad.cpp +SOURCES += src/input/quiz.cpp +SOURCES += src/input/shadow.cpp +SOURCES += src/input/snesmouse.cpp +SOURCES += src/input/suborkb.cpp +SOURCES += src/input/toprider.cpp +SOURCES += src/input/virtualboy.cpp +SOURCES += src/input/zapper.cpp +SOURCES += src/utils/backward.cpp +SOURCES += src/utils/ConvertUTF.c +SOURCES += src/utils/xstring.cpp +SOURCES += src/utils/crc32.cpp +SOURCES += src/utils/endian.cpp +SOURCES += src/utils/general.cpp +SOURCES += src/utils/guid.cpp +SOURCES += src/utils/md5.cpp +SOURCES += src/utils/memory.cpp +SOURCES += src/drivers/common/args.cpp +SOURCES += src/drivers/common/cheat.cpp +SOURCES += src/drivers/common/config.cpp +SOURCES += src/drivers/common/configSys.cpp +SOURCES += src/drivers/common/hq2x.cpp +SOURCES += src/drivers/common/hq3x.cpp +SOURCES += src/drivers/common/scale2x.cpp +SOURCES += src/drivers/common/scale3x.cpp +SOURCES += src/drivers/common/scalebit.cpp +SOURCES += src/drivers/common/vidblit.cpp +SOURCES += src/drivers/common/nes_ntsc.c + +HEADERS += src/drivers/Qt/ConsoleWindow.h +HEADERS += src/drivers/Qt/ConsoleViewerGL.h +HEADERS += src/drivers/Qt/ConsoleViewerSDL.h +HEADERS += src/drivers/Qt/GamePadConf.h +HEADERS += src/drivers/Qt/HotKeyConf.h +HEADERS += src/drivers/Qt/ConsoleVideoConf.h +HEADERS += src/drivers/Qt/ConsoleSoundConf.h +SOURCES += src/drivers/Qt/main.cpp +SOURCES += src/drivers/Qt/ConsoleWindow.cpp +SOURCES += src/drivers/Qt/ConsoleViewerGL.cpp +SOURCES += src/drivers/Qt/ConsoleViewerSDL.cpp +SOURCES += src/drivers/Qt/GamePadConf.cpp +SOURCES += src/drivers/Qt/HotKeyConf.cpp +SOURCES += src/drivers/Qt/ConsoleVideoConf.cpp +SOURCES += src/drivers/Qt/ConsoleSoundConf.cpp +SOURCES += src/drivers/Qt/fceuWrapper.cpp +SOURCES += src/drivers/Qt/config.cpp +SOURCES += src/drivers/Qt/input.cpp +SOURCES += src/drivers/Qt/nes_shm.cpp +SOURCES += src/drivers/Qt/keyscan.cpp +SOURCES += src/drivers/Qt/sdl-sound.cpp +SOURCES += src/drivers/Qt/sdl-video.cpp +SOURCES += src/drivers/Qt/sdl-joystick.cpp +SOURCES += src/drivers/Qt/sdl-throttle.cpp +SOURCES += src/drivers/Qt/unix-netplay.cpp + diff --git a/fceux1.png b/fceux1.png new file mode 100644 index 00000000..f4966c09 Binary files /dev/null and b/fceux1.png differ diff --git a/index.html b/index.html new file mode 100644 index 00000000..5fa646b8 --- /dev/null +++ b/index.html @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/pipelines/linux_build.sh b/pipelines/linux_build.sh index bf6c1c9b..8da0b4e4 100755 --- a/pipelines/linux_build.sh +++ b/pipelines/linux_build.sh @@ -2,6 +2,7 @@ id pwd +uname -a cat /etc/os-release SCRIPT_DIR=$( cd $(dirname $BASH_SOURCE[0]); pwd ); @@ -54,22 +55,29 @@ pkg-config --cflags --libs minizip # GTK+-2 is no longer needed #sudo apt-get install libgtk2.0-dev -# Install GTK+-3 -echo '****************************************' -echo 'Install Dependency libgtk-3-dev' -echo '****************************************' -sudo apt-get --assume-yes install libgtk-3-dev -pkg-config --cflags --libs gtk+-3.0 +# GTK3 was retired in favor of cross platform QT +## Install GTK+-3 +#echo '****************************************' +#echo 'Install Dependency libgtk-3-dev' +#echo '****************************************' +#sudo apt-get --assume-yes install libgtk-3-dev +#pkg-config --cflags --libs gtk+-3.0 +# +## Install GTK+-3 Sourceview +#sudo apt-get --assume-yes install libgtksourceview-3.0-dev +#pkg-config --cflags --libs gtksourceview-3.0 -# Install GTK+-3 Sourceview -sudo apt-get --assume-yes install libgtksourceview-3.0-dev -pkg-config --cflags --libs gtksourceview-3.0 +# Install QT5 +echo '****************************************' +echo 'Install Dependency Qt5' +echo '****************************************' +sudo apt-get --assume-yes install qt5-default # Install scons -echo '****************************************' -echo 'Install Build Dependency scons' -echo '****************************************' -sudo apt-get --assume-yes install scons +#echo '****************************************' +#echo 'Install Build Dependency scons' +#echo '****************************************' +#sudo apt-get --assume-yes install scons # Install cppcheck echo '****************************************' @@ -81,8 +89,35 @@ echo '**************************' echo '*** Building Project ***' echo '**************************' mkdir -p $INSTALL_PREFIX/usr; -scons --clean -scons GTK3=1 SYSTEM_LUA=1 SYSTEM_MINIZIP=1 CREATE_AVI=1 install --prefix=$INSTALL_PREFIX/usr +#scons --clean +#scons GTK3=1 SYSTEM_LUA=1 SYSTEM_MINIZIP=1 CREATE_AVI=1 install --prefix=$INSTALL_PREFIX/usr +echo "Num CPU: `nproc`"; +mkdir build; cd build; +#qmake PREFIX=$INSTALL_PREFIX/usr .. +cmake \ + -DCMAKE_BUILD_TYPE=Release \ + -DCMAKE_INSTALL_PREFIX=$INSTALL_PREFIX/usr \ + -DCMAKE_VERBOSE_MAKEFILE:BOOL=ON \ + .. +make -j `nproc` +make install + +# Install Files +#cd .. # cd out of build +#mkdir -p $INSTALL_PREFIX/usr/bin/. +#mkdir -p $INSTALL_PREFIX/usr/share/fceux +#mkdir -p $INSTALL_PREFIX/usr/share/pixmaps +#mkdir -p $INSTALL_PREFIX/usr/share/applications +#mkdir -p $INSTALL_PREFIX/usr/man/man6 +# +#cp -f ./build/fceux $INSTALL_PREFIX/usr/bin/. +#cp -a ./output/* $INSTALL_PREFIX/usr/share/fceux/. +#cp -a ./src/auxlib.lua $INSTALL_PREFIX/usr/share/fceux/. +#cp -a ./fceux.png $INSTALL_PREFIX/usr/share/pixmaps/. +#cp -a ./fceux.desktop $INSTALL_PREFIX/usr/share/applications/. +#cp -a ./documentation/fceux.6 $INSTALL_PREFIX/usr/man/man6/. +#cp -a ./documentation/fceux-net-server.6 $INSTALL_PREFIX/usr/man/man6/. + # Debug via ssh if necessary if [ ! -z $APPVEYOR_SSH_BLOCK ]; then diff --git a/pipelines/macOS_build.sh b/pipelines/macOS_build.sh new file mode 100755 index 00000000..b096dce2 --- /dev/null +++ b/pipelines/macOS_build.sh @@ -0,0 +1,80 @@ +#!/bin/bash + +echo ' MacOS Build !!! ' +id +pwd +uname -a +sw_vers + +FCEUX_VERSION_MAJOR=2 +FCEUX_VERSION_MINOR=2 +FCEUX_VERSION_PATCH=3 + +SCRIPT_DIR=$( cd $(dirname $BASH_SOURCE[0]); pwd ); + +NPROC=`getconf _NPROCESSORS_ONLN`; +echo "Number of Processors: $NPROC"; + +INSTALL_PREFIX=/tmp/fceux + +gcc --version + +echo '****************************************' +echo "APPVEYOR_SSH_KEY=$APPVEYOR_SSH_KEY"; +echo "APPVEYOR_SSH_BLOCK=$APPVEYOR_SSH_BLOCK"; +echo '****************************************' + +echo '****************************************' +echo 'Install Dependency sdl2' +echo '****************************************' +brew install sdl2 + +echo '****************************************' +echo 'Install Dependency Qt5' +echo '****************************************' +brew install qt5 + +echo '****************************************' +echo 'Install Dependency minizip' +echo '****************************************' +brew install minizip + +#brew install zlib # Already installed in appveyor macOS + +export PKG_CONFIG_PATH=$PKG_CONFIG_PATH:/usr/local/lib/pkgconfig: + +#QMAKE=`find /usr/local -name qmake`; +QT_CMAKE=`find /usr/local -name Qt5Config.cmake` +echo $QT_CMAKE; +export Qt5_DIR=`dirname $QT_CMAKE`; +echo "Qt5_DIR=$Qt5_DIR"; + +echo '**************************' +echo '*** Building Project ***' +echo '**************************' +mkdir build; +cd build; +#$QMAKE .. +cmake \ + -DCMAKE_BUILD_TYPE=Release \ + -DCMAKE_INSTALL_PREFIX=$INSTALL_PREFIX \ + -DCMAKE_VERBOSE_MAKEFILE:BOOL=ON \ + -DCMAKE_PROJECT_VERSION_MAJOR=$FCEUX_VERSION_MAJOR \ + -DCMAKE_PROJECT_VERSION_MINOR=$FCEUX_VERSION_MINOR \ + -DCMAKE_PROJECT_VERSION_PATCH=$FCEUX_VERSION_PATCH \ + -DCPACK_PACKAGE_VERSION_MAJOR=$FCEUX_VERSION_MAJOR \ + -DCPACK_PACKAGE_VERSION_MINOR=$FCEUX_VERSION_MINOR \ + -DCPACK_PACKAGE_VERSION_PATCH=$FCEUX_VERSION_PATCH \ + .. || exit 1 +make -j $NPROC || exit 1 +sudo make install || exit 1 +sudo cpack -G DragNDrop || exit 1 + +echo 'Pushing DMG Package to Build Artifacts' +appveyor PushArtifact fceux-*.dmg + +# Debug via ssh if necessary +if [ ! -z $APPVEYOR_SSH_BLOCK ]; then + curl -sflL 'https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-ssh.sh' | bash -e - +fi + diff --git a/pipelines/win32_build.bat b/pipelines/win32_build.bat index 7821acc9..61ea22a9 100644 --- a/pipelines/win32_build.bat +++ b/pipelines/win32_build.bat @@ -1,22 +1,18 @@ set PROJECT_ROOT=%~dp0.. -REM echo %PROJECT_ROOT% - -msbuild %PROJECT_ROOT%\vc\vc14_fceux.vcxproj +msbuild %PROJECT_ROOT%\vc\vc14_fceux.vcxproj /p:Configuration=Release /p:Platform="Win32" +@if ERRORLEVEL 1 goto end cd %PROJECT_ROOT%\vc -REM Copy Executable and dlls to output directory -copy vc14_bin_Debug\fceux.exe ..\output\. -copy vc14_bin_Debug\7z.dll ..\output\. - REM Create Zip Archive -REM archive.bat cd %PROJECT_ROOT%\output -..\vc\zip -X -9 -r ..\vc\fceux.zip fceux.exe fceux.chm taseditor.chm 7z.dll *.dll palettes luaScripts tools +..\vc\zip -X -9 -r ..\vc\fceux.zip fceux.exe fceux.chm taseditor.chm lua5.1.dll lua51.dll 7z.dll auxlib.lua palettes luaScripts tools +@if ERRORLEVEL 1 goto end cd %PROJECT_ROOT% appveyor PushArtifact %PROJECT_ROOT%\vc\fceux.zip +:end \ No newline at end of file diff --git a/pipelines/win64_build.bat b/pipelines/win64_build.bat new file mode 100644 index 00000000..41bdbb06 --- /dev/null +++ b/pipelines/win64_build.bat @@ -0,0 +1,21 @@ + +set PROJECT_ROOT=%~dp0.. + +msbuild %PROJECT_ROOT%\vc\vc14_fceux.vcxproj /p:Configuration=Release /p:Platform="x64" +@if ERRORLEVEL 1 goto end + +cd %PROJECT_ROOT%\vc + +REM Create Zip Archive + +cd %PROJECT_ROOT%\output +..\vc\zip -X -9 -j ..\vc\fceux64.zip ..\vc\x64\Release\fceux64.exe ..\src\drivers\win\lua\x64\lua5.1.dll ..\src\drivers\win\lua\x64\lua51.dll ..\src\auxlib.lua ..\src\drivers\win\7z.dll +@if ERRORLEVEL 1 goto end +..\vc\zip -X -9 -u -r ..\vc\fceux64.zip fceux.chm taseditor.chm palettes luaScripts tools +@if ERRORLEVEL 1 goto end + +cd %PROJECT_ROOT% + +appveyor PushArtifact %PROJECT_ROOT%\vc\fceux64.zip + +:end diff --git a/readme.md b/readme.md index e23636d1..da142c09 100644 --- a/readme.md +++ b/readme.md @@ -4,7 +4,11 @@ An open source NES Emulator for Windows and Unix that features solid emulation a ## Builds and Releases -win32 autobuilds @ https://ci.appveyor.com/project/zeromus/fceux/build/artifacts +Interim builds: +* Win32: [fceux.zip](https://ci.appveyor.com/api/projects/zeromus/fceux/artifacts/fceux.zip?branch=master&job=Windows%2032) +* Win64: [fceux64.zip](https://ci.appveyor.com/api/projects/zeromus/fceux/artifacts/fceux64.zip?branch=master&job=Windows%2064) +* Ubuntu: [fceux-2.2.3-amd64.deb](https://ci.appveyor.com/api/projects/zeromus/fceux/artifacts/fceux-2.2.3-amd64.deb?branch=master&job=Ubuntu) +* Status: [Appveyor](https://ci.appveyor.com/project/zeromus/fceux/) But you might like mesen more: https://github.com/SourMesen/Mesen diff --git a/resources.qrc b/resources.qrc new file mode 100644 index 00000000..63be737c --- /dev/null +++ b/resources.qrc @@ -0,0 +1,6 @@ + + + fceux.png + fceux1.png + + diff --git a/scripts/genGitHdr.sh b/scripts/genGitHdr.sh new file mode 100755 index 00000000..64f4d59b --- /dev/null +++ b/scripts/genGitHdr.sh @@ -0,0 +1,33 @@ +#!/bin/bash + +OUTPUT_DIR=$1; + +FILE="fceux_git_info.cpp" +TMP_FILE="/tmp/$FILE"; + +echo "Output File: $OUTPUT_DIR/$FILE"; + +GIT_URL=`git config --get remote.origin.url`; +GIT_REV=`git rev-parse HEAD`; + +echo "// fceux_gitrev.cpp -- DO NOT EDIT: This file is auto-generated at build" >| $TMP_FILE; +echo "#include \"Qt/fceux_git_info.h\" " >> $TMP_FILE; +echo "#define FCEUX_GIT_URL \"$GIT_URL\" " >> $TMP_FILE; +echo "#define FCEUX_GIT_REV \"$GIT_REV\" " >> $TMP_FILE; +echo "const char *fceu_get_git_url(void){ return FCEUX_GIT_URL; }" >> $TMP_FILE +echo "const char *fceu_get_git_rev(void){ return FCEUX_GIT_REV; }" >> $TMP_FILE + +echo "Git URL: $GIT_URL "; +echo "Git Rev: $GIT_REV "; +if [ -e $OUTPUT_DIR/$FILE ]; then + + diff -q $TMP_FILE $OUTPUT_DIR/$FILE + + if [ $? != 0 ]; then + mv -f $TMP_FILE $OUTPUT_DIR/$FILE; + echo "Updated $OUTPUT_DIR/$FILE"; + fi +else + mv -f $TMP_FILE $OUTPUT_DIR/$FILE + echo "Generated $OUTPUT_DIR/$FILE"; +fi diff --git a/scripts/macosx_makeIcons.sh b/scripts/macosx_makeIcons.sh new file mode 100755 index 00000000..386b5d34 --- /dev/null +++ b/scripts/macosx_makeIcons.sh @@ -0,0 +1,34 @@ +#!/bin/bash + +SRC_PNG=../fceux1.png +OUTDIR=/tmp/fceux.iconset; +mkdir -p $OUTDIR; + +function convert() { + #echo "Convert $1 $2" + WIDTH=$1; + SCALE=$2; + WIDTH2=`expr $WIDTH / 2`; + + if [ $SCALE == "2" ]; then + OUT=icon_$WIDTH\x$WIDTH.png + else + OUT=icon_$WIDTH2\x$WIDTH2\@2x.png + fi + CMD="sips -z $WIDTH $WIDTH $SRC_PNG --out $OUTDIR/$OUT"; + echo $CMD; + $CMD; +} + +convert 32 1 ; +convert 32 2 ; +convert 64 1 ; +convert 64 2 ; +convert 256 1 ; +convert 256 2 ; +convert 512 1 ; +convert 512 2 ; +convert 1024 1 ; +convert 1024 2 ; + +iconutil -c icns $OUTDIR/ diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt new file mode 100644 index 00000000..c1063f0c --- /dev/null +++ b/src/CMakeLists.txt @@ -0,0 +1,473 @@ + +set(CMAKE_AUTOMOC ON) +set(CMAKE_AUTORCC ON) +set(CMAKE_AUTOUIC ON) + +set( APP_NAME fceux) + +if(WIN32) + set(SOURCES ${SRC_CORE} ${SRC_DRIVERS_COMMON} ${SRC_DRIVERS_WIN}) + include_directories( ${CMAKE_SOURCE_DIR}/src/drivers/win/directx ${CMAKE_SOURCE_DIR}/src/drivers/win/zlib ) + add_definitions( + -DWIN32 + -DFCEUDEF_DEBUGGER + -D_USE_SHARED_MEMORY_ + -DPSS_STYLE=2 + -DNOMINMAX + -D_S9XLUA_H + ) + link_directories( ${CMAKE_SOURCE_DIR}/src/drivers/win/directx ) +else(WIN32) + # Non Windows System + # UNIX (Linux or Mac OSX) + + #set (OpenGL_GL_PREFERENCE GLVND) + set (OpenGL_GL_PREFERENCE LEGACY) + + # Use the built-in cmake find_package functions to find dependencies + # Use package PkgConfig to detect headers/library what find_package cannot find. + find_package(PkgConfig REQUIRED) + find_package(Qt5 COMPONENTS Widgets OpenGL REQUIRED) + find_package(OpenGL REQUIRED) + find_package(ZLIB REQUIRED) + + add_definitions( ${Qt5Widgets_DEFINITIONS} ) + include_directories( ${Qt5Widgets_INCLUDE_DIRS} ) + + add_definitions( -D__QT_DRIVER__ -Wall -Wno-write-strings -Wno-sign-compare -Wno-parentheses -Wno-unused-local-typedefs -fPIC -DQT_DEPRECATED_WARNINGS ) + + # Check for libminizip + pkg_check_modules( MINIZIP REQUIRED minizip) + + if ( ${MINIZIP_FOUND} ) + add_definitions( -D_SYSTEM_MINIZIP ${MINIZIP_CFLAGS} ) + endif() + + #pkg_check_modules( GL gl) # Use built in find package instead for OpenGL + + # Check for OpenGL + if ( ${OPENGL_FOUND} ) + include_directories( ${OPENGL_INCLUDE_DIR} ) + endif() + + #pkg_check_modules( ZLIB REQUIRED zlib) # Use built in find package instead for zlib + + # Check for zlib + if ( ${ZLIB_FOUND} ) + #add_definitions( ${ZLIB_CFLAGS} ) + include_directories( ${ZLIB_INCLUDE_DIRS} ) + endif() + + # Check for SDL2 + pkg_check_modules( SDL2 REQUIRED sdl2) + + if ( ${SDL2_FOUND} ) + add_definitions( ${SDL2_CFLAGS} ) + endif() + + # Check for LUA + pkg_check_modules( LUA lua-5.1) + + if ( ${LUA_FOUND} ) + # Use System LUA + add_definitions( -D_S9XLUA_H ${LUA_CFLAGS} ) + + set( LUA_ENGINE_SOURCE ${CMAKE_CURRENT_SOURCE_DIR}/lua-engine.cpp ) + + else () + + # Use Internal LUA + add_definitions( -D_S9XLUA_H -I${CMAKE_CURRENT_SOURCE_DIR}/lua/src ) + + set( LUA_ENGINE_SOURCE + ${CMAKE_CURRENT_SOURCE_DIR}/lua/src/lapi.c + ${CMAKE_CURRENT_SOURCE_DIR}/lua/src/lauxlib.c + ${CMAKE_CURRENT_SOURCE_DIR}/lua/src/lbaselib.c + ${CMAKE_CURRENT_SOURCE_DIR}/lua/src/lcode.c + ${CMAKE_CURRENT_SOURCE_DIR}/lua/src/ldblib.c + ${CMAKE_CURRENT_SOURCE_DIR}/lua/src/ldebug.c + ${CMAKE_CURRENT_SOURCE_DIR}/lua/src/ldo.c + ${CMAKE_CURRENT_SOURCE_DIR}/lua/src/ldump.c + ${CMAKE_CURRENT_SOURCE_DIR}/lua/src/lfunc.c + ${CMAKE_CURRENT_SOURCE_DIR}/lua/src/lgc.c + ${CMAKE_CURRENT_SOURCE_DIR}/lua/src/linit.c + ${CMAKE_CURRENT_SOURCE_DIR}/lua/src/liolib.c + ${CMAKE_CURRENT_SOURCE_DIR}/lua/src/llex.c + ${CMAKE_CURRENT_SOURCE_DIR}/lua/src/lmathlib.c + ${CMAKE_CURRENT_SOURCE_DIR}/lua/src/lmem.c + ${CMAKE_CURRENT_SOURCE_DIR}/lua/src/loadlib.c + ${CMAKE_CURRENT_SOURCE_DIR}/lua/src/lobject.c + ${CMAKE_CURRENT_SOURCE_DIR}/lua/src/lopcodes.c + ${CMAKE_CURRENT_SOURCE_DIR}/lua/src/loslib.c + ${CMAKE_CURRENT_SOURCE_DIR}/lua/src/lparser.c + ${CMAKE_CURRENT_SOURCE_DIR}/lua/src/lstate.c + ${CMAKE_CURRENT_SOURCE_DIR}/lua/src/lstring.c + ${CMAKE_CURRENT_SOURCE_DIR}/lua/src/lstrlib.c + ${CMAKE_CURRENT_SOURCE_DIR}/lua/src/ltable.c + ${CMAKE_CURRENT_SOURCE_DIR}/lua/src/ltablib.c + ${CMAKE_CURRENT_SOURCE_DIR}/lua/src/ltm.c + ${CMAKE_CURRENT_SOURCE_DIR}/lua/src/lundump.c + ${CMAKE_CURRENT_SOURCE_DIR}/lua/src/lvm.c + ${CMAKE_CURRENT_SOURCE_DIR}/lua/src/lzio.c + ${CMAKE_CURRENT_SOURCE_DIR}/lua/src/print.c + ${CMAKE_CURRENT_SOURCE_DIR}/lua-engine.cpp + ) + endif() + + add_definitions( -DHAVE_ASPRINTF ) # What system wouldn't have this? + #add_definitions( -DCREATE_AVI ) + + if(APPLE) + set( OPENGL_LDFLAGS "-framework OpenGL" ) + else() + set( OPENGL_LDFLAGS ${OPENGL_LIBRARIES} ) + set( SYS_LIBS -lrt -lpthread ) + endif() + +endif(WIN32) + +include_directories( ${CMAKE_SOURCE_DIR}/src ) +include_directories( ${CMAKE_SOURCE_DIR}/src/drivers ) + +if(APPLE) + add_definitions( -DPSS_STYLE=4 ) +else(APPLE) + if(UNIX) + add_definitions( -DPSS_STYLE=1 ) + endif(UNIX) +endif(APPLE) + +set(SRC_CORE + ${CMAKE_CURRENT_SOURCE_DIR}/asm.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/cart.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/cheat.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/conddebug.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/config.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/debug.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/drawing.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/fceu.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/fds.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/file.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/emufile.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/filter.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/ines.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/input.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/movie.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/netplay.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/nsf.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/oldmovie.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/palette.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/ppu.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/sound.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/state.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/unif.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/video.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/vsuni.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/wave.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/x6502.cpp + ${LUA_ENGINE_SOURCE} + ${CMAKE_CURRENT_SOURCE_DIR}/boards/01-222.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/boards/09-034a.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/boards/103.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/boards/106.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/boards/108.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/boards/112.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/boards/116.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/boards/117.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/boards/120.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/boards/121.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/boards/12in1.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/boards/151.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/boards/156.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/boards/158B.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/boards/15.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/boards/164.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/boards/168.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/boards/170.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/boards/175.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/boards/176.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/boards/177.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/boards/178.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/boards/183.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/boards/185.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/boards/186.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/boards/187.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/boards/189.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/boards/18.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/boards/190.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/boards/193.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/boards/199.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/boards/206.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/boards/208.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/boards/222.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/boards/225.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/boards/228.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/boards/230.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/boards/232.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/boards/234.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/boards/235.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/boards/244.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/boards/246.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/boards/252.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/boards/253.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/boards/28.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/boards/32.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/boards/33.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/boards/34.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/boards/36.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/boards/3d-block.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/boards/40.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/boards/411120-c.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/boards/41.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/boards/42.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/boards/43.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/boards/46.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/boards/50.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/boards/51.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/boards/57.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/boards/603-5052.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/boards/62.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/boards/65.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/boards/67.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/boards/68.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/boards/69.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/boards/71.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/boards/72.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/boards/77.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/boards/79.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/boards/80013-B.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/boards/80.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/boards/8157.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/boards/8237.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/boards/82.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/boards/830118C.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/boards/88.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/boards/8in1.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/boards/90.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/boards/91.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/boards/96.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/boards/99.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/boards/a9746.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/boards/ac-08.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/boards/addrlatch.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/boards/ax5705.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/boards/bandai.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/boards/bb.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/boards/bmc13in1jy110.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/boards/bmc42in1r.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/boards/bmc64in1nr.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/boards/bmc70in1.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/boards/BMW8544.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/boards/bonza.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/boards/bs-5.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/boards/cheapocabra.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/boards/cityfighter.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/boards/coolboy.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/boards/dance2000.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/boards/datalatch.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/boards/dream.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/boards/__dummy_mapper.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/boards/edu2000.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/boards/eh8813a.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/boards/emu2413.c + ${CMAKE_CURRENT_SOURCE_DIR}/boards/et-100.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/boards/et-4320.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/boards/F-15.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/boards/famicombox.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/boards/ffe.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/boards/fk23c.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/boards/fns.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/boards/ghostbusters63in1.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/boards/gs-2004.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/boards/gs-2013.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/boards/h2288.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/boards/hp10xx_hp20xx.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/boards/hp898f.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/boards/inlnsf.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/boards/karaoke.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/boards/kof97.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/boards/ks7010.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/boards/ks7012.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/boards/ks7013.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/boards/ks7016.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/boards/ks7017.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/boards/ks7030.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/boards/ks7031.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/boards/ks7032.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/boards/ks7037.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/boards/ks7057.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/boards/le05.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/boards/lh32.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/boards/lh53.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/boards/malee.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/boards/mihunche.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/boards/mmc1.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/boards/mmc2and4.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/boards/mmc3.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/boards/mmc5.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/boards/n106.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/boards/n625092.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/boards/novel.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/boards/onebus.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/boards/pec-586.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/boards/rt-01.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/boards/sa-9602b.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/boards/sachen.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/boards/sb-2000.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/boards/sc-127.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/boards/sheroes.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/boards/sl1632.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/boards/subor.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/boards/super24.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/boards/supervision.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/boards/t-227-1.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/boards/t-262.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/boards/tengen.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/boards/tf-1201.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/boards/transformer.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/boards/unrom512.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/boards/vrc1.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/boards/vrc2and4.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/boards/vrc3.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/boards/vrc5.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/boards/vrc6.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/boards/vrc7.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/boards/vrc7p.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/boards/yoko.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/input/arkanoid.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/input/bworld.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/input/cursor.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/input/fkb.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/input/fns.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/input/ftrainer.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/input/hypershot.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/input/mahjong.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/input/mouse.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/input/oekakids.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/input/pec586kb.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/input/powerpad.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/input/quiz.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/input/shadow.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/input/snesmouse.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/input/suborkb.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/input/toprider.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/input/virtualboy.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/input/zapper.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/utils/backward.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/utils/ConvertUTF.c + ${CMAKE_CURRENT_SOURCE_DIR}/utils/xstring.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/utils/crc32.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/utils/endian.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/utils/general.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/utils/guid.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/utils/md5.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/utils/memory.cpp +) + + +set(SRC_DRIVERS_COMMON + ${CMAKE_CURRENT_SOURCE_DIR}/drivers/common/args.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/drivers/common/cheat.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/drivers/common/config.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/drivers/common/configSys.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/drivers/common/hq2x.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/drivers/common/hq3x.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/drivers/common/scale2x.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/drivers/common/scale3x.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/drivers/common/scalebit.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/drivers/common/vidblit.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/drivers/common/nes_ntsc.c + ${CMAKE_CURRENT_SOURCE_DIR}/drivers/videolog/nesvideos-piece.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/drivers/videolog/rgbtorgb.cpp +) + +set(SRC_DRIVERS_SDL + ${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/main.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/ConsoleWindow.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/ConsoleViewerGL.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/ConsoleViewerSDL.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/GamePadConf.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/HotKeyConf.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/ConsoleVideoConf.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/ConsoleSoundConf.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/AboutWindow.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/fceuWrapper.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/config.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/input.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/nes_shm.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/keyscan.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/sdl-sound.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/sdl-video.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/sdl-joystick.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/sdl-throttle.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/unix-netplay.cpp +) + +set(SOURCES ${SRC_CORE} ${SRC_DRIVERS_COMMON} ${SRC_DRIVERS_SDL}) + +add_custom_command( + OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/fceux_git_info.cpp + COMMAND ${CMAKE_SOURCE_DIR}/scripts/genGitHdr.sh ${CMAKE_CURRENT_BINARY_DIR} + VERBATIM ) + +set_property(SOURCE ${CMAKE_CURRENT_BINARY_DIR}/fceux_git_info.cpp PROPERTY SKIP_AUTOGEN ON) + +if (APPLE) + +set(MACOSX_BUNDLE_ICON_FILE fceux.icns) +set(APP_ICON ${CMAKE_SOURCE_DIR}/fceux.icns ) +set_source_files_properties( ${APP_ICON} PROPERTIES MACOSX_PACKAGE_LOCATION "Resources" ) + +add_executable( ${APP_NAME} MACOSX_BUNDLE ${APP_ICON} ${SOURCES} ../resources.qrc + ${CMAKE_CURRENT_BINARY_DIR}/fceux_git_info.cpp) + +else() +add_executable( ${APP_NAME} ${SOURCES} ../resources.qrc + ${CMAKE_CURRENT_BINARY_DIR}/fceux_git_info.cpp) +endif() + +target_link_libraries( fceux + ${Qt5Widgets_LIBRARIES} + ${Qt5OpenGL_LIBRARIES} + ${OPENGL_LDFLAGS} + ${SDL2_LDFLAGS} + ${MINIZIP_LDFLAGS} ${ZLIB_LIBRARIES} + ${LUA_LDFLAGS} + ${SYS_LIBS} +) + +if (APPLE) + +install( TARGETS ${APP_NAME} + BUNDLE DESTINATION . COMPONENT Runtime + RUNTIME DESTINATION bin COMPONENT Runtime ) + +set( APPS ${CMAKE_INSTALL_PREFIX}/${APP_NAME}.app) +set( DIRS ${CMAKE_BINARY_DIR} /usr/local/lib) + +message(STATUS APPS: ${APPS}) +message(STATUS DIRS: ${DIRS} ) + +set(CPACK_PACKAGE_ICON ${CMAKE_SOURCE_DIR}/fceux.icns ) +set(CPACK_BUNDLE_ICON ${CMAKE_SOURCE_DIR}/fceux.icns ) +set(CPACK_GENERATOR "DRAGNDROP") +include(CPACK) + +install( CODE "include(BundleUtilities) + fixup_bundle( \"${APPS}\" \"\" \"${DIRS}\") " + COMPONENT Runtime + ) + +else(APPLE) + +install( TARGETS ${APP_NAME} + RUNTIME DESTINATION bin ) + +install( FILES ${CMAKE_CURRENT_SOURCE_DIR}/auxlib.lua DESTINATION share/fceux/luaScripts ) +install( DIRECTORY ${CMAKE_SOURCE_DIR}/output/. DESTINATION share/fceux ) +install( FILES ${CMAKE_SOURCE_DIR}/fceux.png DESTINATION share/pixmaps ) +install( FILES ${CMAKE_SOURCE_DIR}/fceux.desktop DESTINATION share/applications ) +install( FILES ${CMAKE_SOURCE_DIR}/documentation/fceux.6 DESTINATION share/man/man6 ) +install( FILES ${CMAKE_SOURCE_DIR}/documentation/fceux-net-server.6 DESTINATION share/man/man6 ) + +endif(APPLE) diff --git a/src/cheat.h b/src/cheat.h index 4ea6f12c..9f3dbe2b 100644 --- a/src/cheat.h +++ b/src/cheat.h @@ -40,7 +40,7 @@ typedef struct { struct CHEATF { struct CHEATF *next; - char *name = ""; + char *name; uint16 addr; uint8 val; int compare; /* -1 for no compare. */ @@ -65,4 +65,4 @@ struct SEARCHPOSSIBLE { #define FCEU_SEARCH_NEWVAL_GT_KNOWN 7 #define FCEU_SEARCH_NEWVAL_LT_KNOWN 8 -#endif \ No newline at end of file +#endif diff --git a/src/driver.h b/src/driver.h index 496ab636..d3f1f020 100644 --- a/src/driver.h +++ b/src/driver.h @@ -23,7 +23,7 @@ ArchiveScanRecord FCEUD_ScanArchive(std::string fname); const char *FCEUD_GetCompilerString(); //This makes me feel dirty for some reason. -void FCEU_printf(char *format, ...); +void FCEU_printf(const char *format, ...); #define FCEUI_printf FCEU_printf //Video interface @@ -183,7 +183,7 @@ void FCEUD_LuaRunFrom(void); int32 FCEUI_GetDesiredFPS(void); void FCEUI_SaveSnapshot(void); void FCEUI_SaveSnapshotAs(void); -void FCEU_DispMessage(char *format, int disppos, ...); +void FCEU_DispMessage(const char *format, int disppos, ...); #define FCEUI_DispMessage FCEU_DispMessage int FCEUI_DecodePAR(const char *code, int *a, int *v, int *c, int *type); 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/AboutWindow.cpp b/src/drivers/Qt/AboutWindow.cpp new file mode 100644 index 00000000..4d67090d --- /dev/null +++ b/src/drivers/Qt/AboutWindow.cpp @@ -0,0 +1,150 @@ +// AboutWindow.cpp +// +#include +#include +#include +#include + +#include +#include +#include +#include +//#include "Qt/icon.xpm" +#include "Qt/AboutWindow.h" +#include "Qt/fceux_git_info.h" +#include "../../version.h" + +static const char *Authors[] = { + "Linux/SDL Developers:", + "\t Lukas Sabota //punkrockguy318", "\t Soules", "\t Bryan Cain", "\t radsaq", + "\t Shinydoofy", + "FceuX 2.0 Developers:", + "\t SP", "\t zeromus", "\t adelikat", "\t caH4e3", "\t qfox", + "\t Luke Gustafson", "\t _mz", "\t UncombedCoconut", "\t DwEdit", "\t AnS", + "\t rainwarrior", "\t feos", + "Pre 2.0 Guys:", + "\t Bero", "\t Xodnizel", "\t Aaron Oneal", "\t Joe Nahmias", + "\t Paul Kuliniewicz", "\t Quietust", "\t Ben Parnell", + "\t Parasyte & bbitmaster", + "\t blip & nitsuja", + "Included components:", + "\t Mitsutaka Okazaki - YM2413 emulator", + "\t Andrea Mazzoleni - Scale2x/Scale3x scalers", + "\t Gilles Vollant - unzip.c PKZIP fileio", + NULL +}; +//---------------------------------------------------------------------------- +AboutWindow::AboutWindow(QWidget *parent) + : QDialog( parent ) +{ + int i; + QVBoxLayout *mainLayout; + QHBoxLayout *hbox1; + //QPixmap pm( icon_xpm ); + QPixmap pm(":fceux1.png"); + QPixmap pm2; + QLabel *lbl; + QTextEdit *credits; + char stmp[256]; + + pm2 = pm.scaled( 64, 64 ); + + setWindowTitle( tr("About fceuX") ); + + resize( 512, 512 ); + + mainLayout = new QVBoxLayout(); + + hbox1 = new QHBoxLayout(); + lbl = new QLabel(); + lbl->setPixmap(pm2); + + hbox1->addWidget( lbl ); + hbox1->setAlignment( Qt::AlignCenter ); + + mainLayout->addLayout( hbox1 ); + + hbox1 = new QHBoxLayout(); + lbl = new QLabel( tr("fceuX") ); + + hbox1->addWidget( lbl ); + hbox1->setAlignment( Qt::AlignCenter ); + + mainLayout->addLayout( hbox1 ); + + hbox1 = new QHBoxLayout(); + lbl = new QLabel( tr(FCEU_VERSION_STRING) ); + + hbox1->addWidget( lbl ); + hbox1->setAlignment( Qt::AlignCenter ); + + mainLayout->addLayout( hbox1 ); + + sprintf( stmp, "git URL: %s", fceu_get_git_url() ); + + hbox1 = new QHBoxLayout(); + lbl = new QLabel( tr(stmp) ); + + hbox1->addWidget( lbl ); + hbox1->setAlignment( Qt::AlignCenter ); + + mainLayout->addLayout( hbox1 ); + + sprintf( stmp, "git Revision: %s", fceu_get_git_rev() ); + + hbox1 = new QHBoxLayout(); + lbl = new QLabel( tr(stmp) ); + + hbox1->addWidget( lbl ); + hbox1->setAlignment( Qt::AlignCenter ); + + mainLayout->addLayout( hbox1 ); + + hbox1 = new QHBoxLayout(); + lbl = new QLabel(); + lbl->setText("Website"); + lbl->setTextInteractionFlags(Qt::TextBrowserInteraction); + lbl->setOpenExternalLinks(true); + + hbox1->addWidget( lbl ); + hbox1->setAlignment( Qt::AlignCenter ); + + mainLayout->addLayout( hbox1 ); + + hbox1 = new QHBoxLayout(); + lbl = new QLabel( tr("License: GPL") ); + + hbox1->addWidget( lbl ); + hbox1->setAlignment( Qt::AlignCenter ); + + mainLayout->addLayout( hbox1 ); + + hbox1 = new QHBoxLayout(); + lbl = new QLabel( tr("© 2016 FceuX Development Team") ); + + hbox1->addWidget( lbl ); + hbox1->setAlignment( Qt::AlignCenter ); + + mainLayout->addLayout( hbox1 ); + + credits = new QTextEdit(); + + i=0; + while ( Authors[i] != NULL ) + { + credits->insertPlainText( Authors[i] ); i++; + credits->insertPlainText( "\n"); + } + credits->moveCursor(QTextCursor::Start); + credits->setReadOnly(true); + + mainLayout->addWidget( credits ); + + setLayout( mainLayout ); +} +//---------------------------------------------------------------------------- +AboutWindow::~AboutWindow(void) +{ + +} +//---------------------------------------------------------------------------- diff --git a/src/drivers/Qt/AboutWindow.h b/src/drivers/Qt/AboutWindow.h new file mode 100644 index 00000000..e8ebb10c --- /dev/null +++ b/src/drivers/Qt/AboutWindow.h @@ -0,0 +1,35 @@ +// GamePadConf.h +// + +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "Qt/main.h" + +class AboutWindow : public QDialog +{ + Q_OBJECT + + public: + AboutWindow(QWidget *parent = 0); + ~AboutWindow(void); + + protected: + + private: + + private slots: + +}; diff --git a/src/drivers/Qt/ConsoleSoundConf.cpp b/src/drivers/Qt/ConsoleSoundConf.cpp new file mode 100644 index 00000000..4d716f3b --- /dev/null +++ b/src/drivers/Qt/ConsoleSoundConf.cpp @@ -0,0 +1,449 @@ +// ConsoleSoundConf.cpp +// +#include "../../fceu.h" +#include "../../driver.h" +#include "Qt/ConsoleSoundConf.h" +#include "Qt/main.h" +#include "Qt/dface.h" +#include "Qt/config.h" +#include "Qt/fceuWrapper.h" + +//---------------------------------------------------- +ConsoleSndConfDialog_t::ConsoleSndConfDialog_t(QWidget *parent) + : QDialog( parent ) +{ + int buf; + QHBoxLayout *hbox1, *hbox2; + QVBoxLayout *vbox1, *vbox2; + QLabel *lbl; + QGroupBox *frame; + QSlider *vslider; + + setWindowTitle( tr("Sound Config") ); + + hbox1 = new QHBoxLayout(); + vbox1 = new QVBoxLayout(); + + // Enable Sound Select + enaChkbox = new QCheckBox( tr("Enable Sound") ); + // Enable Low Pass Filter Select + enaLowPass = new QCheckBox( tr("Enable Low Pass Filter") ); + + setCheckBoxFromProperty( enaChkbox , "SDL.Sound" ); + setCheckBoxFromProperty( enaLowPass, "SDL.Sound.LowPass" ); + + connect(enaChkbox , SIGNAL(stateChanged(int)), this, SLOT(enaSoundStateChange(int)) ); + connect(enaLowPass, SIGNAL(stateChanged(int)), this, SLOT(enaSoundLowPassChange(int)) ); + + vbox1->addWidget( enaChkbox ); + vbox1->addWidget( enaLowPass ); + + // Audio Quality Select + hbox2 = new QHBoxLayout(); + + lbl = new QLabel( tr("Quality:") ); + + qualitySelect = new QComboBox(); + + qualitySelect->addItem( tr("Low") , 0 ); + qualitySelect->addItem( tr("High") , 1 ); + qualitySelect->addItem( tr("Very High"), 2 ); + + setComboBoxFromProperty( qualitySelect, "SDL.Sound.Quality" ); + + connect(qualitySelect, SIGNAL(currentIndexChanged(int)), this, SLOT(soundQualityChanged(int)) ); + + hbox2->addWidget( lbl ); + hbox2->addWidget( qualitySelect ); + + vbox1->addLayout( hbox2 ); + + // Sample Rate Select + hbox2 = new QHBoxLayout(); + + lbl = new QLabel("Rate:"); + + rateSelect = new QComboBox(); + + rateSelect->addItem( tr("11025"), 11025 ); + rateSelect->addItem( tr("22050"), 22050 ); + rateSelect->addItem( tr("44100"), 44100 ); + rateSelect->addItem( tr("48000"), 48000 ); + rateSelect->addItem( tr("96000"), 96000 ); + + setComboBoxFromProperty( rateSelect, "SDL.Sound.Rate" ); + + connect(rateSelect, SIGNAL(currentIndexChanged(int)), this, SLOT(soundRateChanged(int)) ); + + g_config->getOption ("SDL.Sound.Rate", &buf); + + hbox2->addWidget( lbl ); + hbox2->addWidget( rateSelect ); + + vbox1->addLayout( hbox2 ); + + // Buffer Size Select + // + hbox2 = new QHBoxLayout(); + + lbl = new QLabel( tr("Buffer Size (in ms):") ); + + bufSizeLabel = new QLabel("128"); + bufSizeSlider = new QSlider( Qt::Horizontal ); + + bufSizeSlider->setMinimum( 15); + bufSizeSlider->setMaximum(200); + //bufSizeSlider->setSliderPosition(128); + setSliderFromProperty( bufSizeSlider, bufSizeLabel, "SDL.Sound.BufSize" ); + + hbox2->addWidget( lbl ); + hbox2->addWidget( bufSizeLabel ); + + vbox1->addLayout( hbox2 ); + vbox1->addWidget( bufSizeSlider ); + + connect(bufSizeSlider, SIGNAL(valueChanged(int)), this, SLOT(bufSizeChanged(int)) ); + + // Swap Duty Cycles + swapDutyChkbox = new QCheckBox( tr("Swap Duty Cycles") ); + vbox1->addWidget( swapDutyChkbox ); + + setCheckBoxFromProperty( swapDutyChkbox , "SDL.SwapDuty" ); + + connect(swapDutyChkbox , SIGNAL(stateChanged(int)), this, SLOT(swapDutyCallback(int)) ); + + hbox1->addLayout( vbox1 ); + + frame = new QGroupBox(tr("Mixer:")); + hbox2 = new QHBoxLayout(); + + frame->setLayout( hbox2 ); + + hbox1->addWidget( frame ); + + frame = new QGroupBox(tr("Volume")); + vbox2 = new QVBoxLayout(); + volLbl = new QLabel("150"); + vslider = new QSlider( Qt::Vertical ); + vslider->setMinimum( 0); + vslider->setMaximum(255); + setSliderFromProperty( vslider, volLbl, "SDL.Sound.Volume" ); + + vbox2->addWidget( volLbl ); + vbox2->addWidget( vslider ); + frame->setLayout( vbox2 ); + hbox2->addWidget( frame ); + + connect(vslider, SIGNAL(valueChanged(int)), this, SLOT(volumeChanged(int)) ); + + frame = new QGroupBox(tr("Triangle")); + vbox2 = new QVBoxLayout(); + triLbl = new QLabel("255"); + vslider = new QSlider( Qt::Vertical ); + vslider->setMinimum( 0); + vslider->setMaximum(255); + setSliderFromProperty( vslider, triLbl, "SDL.Sound.TriangleVolume" ); + + vbox2->addWidget( triLbl ); + vbox2->addWidget( vslider ); + frame->setLayout( vbox2 ); + hbox2->addWidget( frame ); + + connect(vslider, SIGNAL(valueChanged(int)), this, SLOT(triangleChanged(int)) ); + + frame = new QGroupBox(tr("Square1")); + vbox2 = new QVBoxLayout(); + sqr1Lbl = new QLabel("255"); + vslider = new QSlider( Qt::Vertical ); + vslider->setMinimum( 0); + vslider->setMaximum(255); + setSliderFromProperty( vslider, sqr1Lbl, "SDL.Sound.Square1Volume" ); + + vbox2->addWidget( sqr1Lbl ); + vbox2->addWidget( vslider ); + frame->setLayout( vbox2 ); + hbox2->addWidget( frame ); + + connect(vslider, SIGNAL(valueChanged(int)), this, SLOT(square1Changed(int)) ); + + frame = new QGroupBox(tr("Square2")); + vbox2 = new QVBoxLayout(); + sqr2Lbl = new QLabel("255"); + vslider = new QSlider( Qt::Vertical ); + vslider->setMinimum( 0); + vslider->setMaximum(255); + setSliderFromProperty( vslider, sqr2Lbl, "SDL.Sound.Square2Volume" ); + + vbox2->addWidget( sqr2Lbl ); + vbox2->addWidget( vslider ); + frame->setLayout( vbox2 ); + hbox2->addWidget( frame ); + + connect(vslider, SIGNAL(valueChanged(int)), this, SLOT(square2Changed(int)) ); + + frame = new QGroupBox(tr("Noise")); + vbox2 = new QVBoxLayout(); + nseLbl = new QLabel("255"); + vslider = new QSlider( Qt::Vertical ); + vslider->setMinimum( 0); + vslider->setMaximum(255); + setSliderFromProperty( vslider, nseLbl, "SDL.Sound.NoiseVolume" ); + + vbox2->addWidget( nseLbl ); + vbox2->addWidget( vslider ); + frame->setLayout( vbox2 ); + hbox2->addWidget( frame ); + + connect(vslider, SIGNAL(valueChanged(int)), this, SLOT(noiseChanged(int)) ); + + frame = new QGroupBox(tr("PCM")); + vbox2 = new QVBoxLayout(); + pcmLbl = new QLabel("255"); + vslider = new QSlider( Qt::Vertical ); + vslider->setMinimum( 0); + vslider->setMaximum(255); + setSliderFromProperty( vslider, pcmLbl, "SDL.Sound.PCMVolume" ); + + vbox2->addWidget( pcmLbl ); + vbox2->addWidget( vslider ); + frame->setLayout( vbox2 ); + hbox2->addWidget( frame ); + + connect(vslider, SIGNAL(valueChanged(int)), this, SLOT(pcmChanged(int)) ); + + // Set Final Layout + setLayout( hbox1 ); +} +//---------------------------------------------------- +ConsoleSndConfDialog_t::~ConsoleSndConfDialog_t(void) +{ + +} +//---------------------------------------------------- +void ConsoleSndConfDialog_t::setCheckBoxFromProperty( QCheckBox *cbx, const char *property ) +{ + int pval; + g_config->getOption (property, &pval); + + cbx->setCheckState( pval ? Qt::Checked : Qt::Unchecked ); +} +//---------------------------------------------------- +void ConsoleSndConfDialog_t::setComboBoxFromProperty( QComboBox *cbx, const char *property ) +{ + int i, pval; + g_config->getOption (property, &pval); + + for (i=0; icount(); i++) + { + if ( pval == cbx->itemData(i).toInt() ) + { + cbx->setCurrentIndex(i); break; + } + } +} +//---------------------------------------------------- +void ConsoleSndConfDialog_t::setSliderFromProperty( QSlider *slider, QLabel *lbl, const char *property ) +{ + int pval; + char stmp[32]; + g_config->getOption (property, &pval); + slider->setValue( pval ); + sprintf( stmp, "%i", pval ); + lbl->setText( stmp ); +} +//---------------------------------------------------- +void ConsoleSndConfDialog_t::bufSizeChanged(int value) +{ + char stmp[32]; + + sprintf( stmp, "%i", value ); + + bufSizeLabel->setText(stmp); + + g_config->setOption ("SDL.Sound.BufSize", value); + // reset sound subsystem for changes to take effect + fceuWrapperLock(); + KillSound (); + InitSound (); + fceuWrapperUnLock(); +} +//---------------------------------------------------- +void ConsoleSndConfDialog_t::volumeChanged(int value) +{ + char stmp[32]; + + sprintf( stmp, "%i", value ); + + volLbl->setText(stmp); + + g_config->setOption ("SDL.Sound.Volume", value); + + fceuWrapperLock(); + FCEUI_SetSoundVolume (value); + fceuWrapperUnLock(); +} +//---------------------------------------------------- +void ConsoleSndConfDialog_t::triangleChanged(int value) +{ + char stmp[32]; + + sprintf( stmp, "%i", value ); + + triLbl->setText(stmp); + + g_config->setOption ("SDL.Sound.TriangleVolume", value); + + fceuWrapperLock(); + FCEUI_SetTriangleVolume (value); + fceuWrapperUnLock(); +} +//---------------------------------------------------- +void ConsoleSndConfDialog_t::square1Changed(int value) +{ + char stmp[32]; + + sprintf( stmp, "%i", value ); + + sqr1Lbl->setText(stmp); + + g_config->setOption ("SDL.Sound.Square1Volume", value); + + fceuWrapperLock(); + FCEUI_SetSquare1Volume (value); + fceuWrapperUnLock(); +} +//---------------------------------------------------- +void ConsoleSndConfDialog_t::square2Changed(int value) +{ + char stmp[32]; + + sprintf( stmp, "%i", value ); + + sqr2Lbl->setText(stmp); + + g_config->setOption ("SDL.Sound.Square2Volume", value); + + fceuWrapperLock(); + FCEUI_SetSquare2Volume (value); + fceuWrapperUnLock(); +} +//---------------------------------------------------- +void ConsoleSndConfDialog_t::noiseChanged(int value) +{ + char stmp[32]; + + sprintf( stmp, "%i", value ); + + nseLbl->setText(stmp); + + g_config->setOption ("SDL.Sound.NoiseVolume", value); + + fceuWrapperLock(); + FCEUI_SetNoiseVolume (value); + fceuWrapperUnLock(); +} +//---------------------------------------------------- +void ConsoleSndConfDialog_t::pcmChanged(int value) +{ + char stmp[32]; + + sprintf( stmp, "%i", value ); + + pcmLbl->setText(stmp); + + g_config->setOption ("SDL.Sound.PCMVolume", value); + + fceuWrapperLock(); + FCEUI_SetPCMVolume (value); + fceuWrapperUnLock(); +} +//---------------------------------------------------- +void ConsoleSndConfDialog_t::enaSoundStateChange(int value) +{ + if ( value ) + { + int last_soundopt; + g_config->getOption ("SDL.Sound", &last_soundopt); + g_config->setOption ("SDL.Sound", 1); + + fceuWrapperLock(); + + if (GameInfo && !last_soundopt) + { + InitSound (); + } + fceuWrapperUnLock(); + } + else + { + g_config->setOption ("SDL.Sound", 0); + + fceuWrapperLock(); + KillSound (); + fceuWrapperUnLock(); + } +} +//---------------------------------------------------- +void ConsoleSndConfDialog_t::enaSoundLowPassChange(int value) +{ + if (value) + { + g_config->setOption ("SDL.Sound.LowPass", 1); + + fceuWrapperLock(); + FCEUI_SetLowPass (1); + fceuWrapperUnLock(); + } + else + { + g_config->setOption ("SDL.Sound.LowPass", 0); + + fceuWrapperLock(); + FCEUI_SetLowPass (0); + fceuWrapperUnLock(); + } + g_config->save (); +} +//---------------------------------------------------- +void ConsoleSndConfDialog_t::swapDutyCallback(int value) +{ + if (value) + { + g_config->setOption ("SDL.SwapDuty", 1); + swapDuty = 1; + } + else + { + g_config->setOption ("SDL.SwapDuty", 0); + swapDuty = 0; + } + g_config->save (); +} +//---------------------------------------------------- +void ConsoleSndConfDialog_t::soundQualityChanged(int index) +{ + //printf("Sound Quality: %i : %i \n", index, qualitySelect->itemData(index).toInt() ); + + g_config->setOption ("SDL.Sound.Quality", qualitySelect->itemData(index).toInt() ); + + // reset sound subsystem for changes to take effect + fceuWrapperLock(); + KillSound (); + InitSound (); + fceuWrapperUnLock(); + g_config->save (); +} +//---------------------------------------------------- +void ConsoleSndConfDialog_t::soundRateChanged(int index) +{ + //printf("Sound Rate: %i : %i \n", index, rateSelect->itemData(index).toInt() ); + + g_config->setOption ("SDL.Sound.Rate", rateSelect->itemData(index).toInt() ); + // reset sound subsystem for changes to take effect + fceuWrapperLock(); + KillSound (); + InitSound (); + fceuWrapperUnLock(); + g_config->save (); +} +//---------------------------------------------------- diff --git a/src/drivers/Qt/ConsoleSoundConf.h b/src/drivers/Qt/ConsoleSoundConf.h new file mode 100644 index 00000000..40e86d2a --- /dev/null +++ b/src/drivers/Qt/ConsoleSoundConf.h @@ -0,0 +1,62 @@ +// GameSoundConf.h +// + +#ifndef __GameSndH__ +#define __GameSndH__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +class ConsoleSndConfDialog_t : public QDialog +{ + Q_OBJECT + + public: + ConsoleSndConfDialog_t(QWidget *parent = 0); + ~ConsoleSndConfDialog_t(void); + + protected: + QCheckBox *enaChkbox; + QCheckBox *enaLowPass; + QCheckBox *swapDutyChkbox; + QComboBox *qualitySelect; + QComboBox *rateSelect; + QSlider *bufSizeSlider; + QLabel *bufSizeLabel; + QLabel *volLbl; + QLabel *triLbl; + QLabel *sqr1Lbl; + QLabel *sqr2Lbl; + QLabel *nseLbl; + QLabel *pcmLbl; + + void setCheckBoxFromProperty( QCheckBox *cbx, const char *property ); + void setComboBoxFromProperty( QComboBox *cbx, const char *property ); + void setSliderFromProperty( QSlider *slider, QLabel *lbl, const char *property ); + + private slots: + void bufSizeChanged(int value); + void volumeChanged(int value); + void triangleChanged(int value); + void square1Changed(int value); + void square2Changed(int value); + void noiseChanged(int value); + void pcmChanged(int value); + void enaSoundStateChange(int value); + void enaSoundLowPassChange(int value); + void swapDutyCallback(int value); + void soundQualityChanged(int index); + void soundRateChanged(int index); + +}; + +#endif diff --git a/src/drivers/Qt/ConsoleVideoConf.cpp b/src/drivers/Qt/ConsoleVideoConf.cpp new file mode 100644 index 00000000..05104e20 --- /dev/null +++ b/src/drivers/Qt/ConsoleVideoConf.cpp @@ -0,0 +1,228 @@ +// ConsoleVideoConf.cpp +// +#include "../../fceu.h" +#include "Qt/main.h" +#include "Qt/dface.h" +#include "Qt/config.h" +#include "Qt/fceuWrapper.h" +#include "Qt/ConsoleVideoConf.h" + +//---------------------------------------------------- +ConsoleVideoConfDialog_t::ConsoleVideoConfDialog_t(QWidget *parent) + : QDialog( parent ) +{ + QVBoxLayout *main_vbox; + QHBoxLayout *hbox1; + QLabel *lbl; + QPushButton *button; + + setWindowTitle( tr("Video Config") ); + + main_vbox = new QVBoxLayout(); + + // Video Driver Select + lbl = new QLabel( tr("Driver:") ); + + driverSelect = new QComboBox(); + + driverSelect->addItem( tr("OpenGL"), 0 ); + //driverSelect->addItem( tr("SDL"), 1 ); + + hbox1 = new QHBoxLayout(); + + hbox1->addWidget( lbl ); + hbox1->addWidget( driverSelect ); + + main_vbox->addLayout( hbox1 ); + + // Enable OpenGL Linear Filter Checkbox + gl_LF_chkBox = new QCheckBox( tr("Enable OpenGL Linear Filter") ); + + setCheckBoxFromProperty( gl_LF_chkBox , "SDL.OpenGLip"); + + main_vbox->addWidget( gl_LF_chkBox ); + + // Region Select + lbl = new QLabel( tr("Region:") ); + + regionSelect = new QComboBox(); + + regionSelect->addItem( tr("NTSC") , 0 ); + regionSelect->addItem( tr("PAL") , 1 ); + regionSelect->addItem( tr("Dendy"), 2 ); + + setComboBoxFromProperty( regionSelect, "SDL.PAL"); + + connect(regionSelect, SIGNAL(currentIndexChanged(int)), this, SLOT(regionChanged(int)) ); + + hbox1 = new QHBoxLayout(); + + hbox1->addWidget( lbl ); + hbox1->addWidget( regionSelect ); + + main_vbox->addLayout( hbox1 ); + + // Enable New PPU Checkbox + new_PPU_ena = new QCheckBox( tr("Enable New PPU") ); + + // Enable New PPU Checkbox + frmskipcbx = new QCheckBox( tr("Enable Frameskip") ); + + // Disable Sprite Limit Checkbox + sprtLimCbx = new QCheckBox( tr("Disable Sprite Limit") ); + + // Clip Sides Checkbox + clipSidesCbx = new QCheckBox( tr("Clip Sides") ); + + // Show FPS Checkbox + showFPS_cbx = new QCheckBox( tr("Show FPS") ); + + setCheckBoxFromProperty( new_PPU_ena , "SDL.NewPPU"); + setCheckBoxFromProperty( frmskipcbx , "SDL.Frameskip"); + setCheckBoxFromProperty( sprtLimCbx , "SDL.DisableSpriteLimit"); + setCheckBoxFromProperty( clipSidesCbx , "SDL.ClipSides"); + setCheckBoxFromProperty( showFPS_cbx , "SDL.ShowFPS"); + + connect(new_PPU_ena , SIGNAL(stateChanged(int)), this, SLOT(use_new_PPU_changed(int)) ); + connect(frmskipcbx , SIGNAL(stateChanged(int)), this, SLOT(frameskip_changed(int)) ); + connect(sprtLimCbx , SIGNAL(stateChanged(int)), this, SLOT(useSpriteLimitChanged(int)) ); + connect(clipSidesCbx, SIGNAL(stateChanged(int)), this, SLOT(clipSidesChanged(int)) ); + connect(showFPS_cbx , SIGNAL(stateChanged(int)), this, SLOT(showFPSChanged(int)) ); + + main_vbox->addWidget( new_PPU_ena ); + main_vbox->addWidget( frmskipcbx ); + main_vbox->addWidget( sprtLimCbx ); + main_vbox->addWidget( clipSidesCbx); + main_vbox->addWidget( showFPS_cbx ); + + hbox1 = new QHBoxLayout(); + + button = new QPushButton( tr("Apply") ); + hbox1->addWidget( button ); + connect(button, SIGNAL(clicked()), this, SLOT(applyChanges(void)) ); + + button = new QPushButton( tr("Close") ); + hbox1->addWidget( button ); + connect(button, SIGNAL(clicked()), this, SLOT(closewindow(void)) ); + + main_vbox->addLayout( hbox1 ); + + setLayout( main_vbox ); + +} +//---------------------------------------------------- +ConsoleVideoConfDialog_t::~ConsoleVideoConfDialog_t(void) +{ + +} +//---------------------------------------------------- +void ConsoleVideoConfDialog_t::resetVideo(void) +{ + KillVideo (); + InitVideo (GameInfo); +} +//---------------------------------------------------- +void ConsoleVideoConfDialog_t::setCheckBoxFromProperty( QCheckBox *cbx, const char *property ) +{ + int pval; + g_config->getOption (property, &pval); + + cbx->setCheckState( pval ? Qt::Checked : Qt::Unchecked ); +} +//---------------------------------------------------- +void ConsoleVideoConfDialog_t::setComboBoxFromProperty( QComboBox *cbx, const char *property ) +{ + int i, pval; + g_config->getOption (property, &pval); + + for (i=0; icount(); i++) + { + if ( pval == cbx->itemData(i).toInt() ) + { + cbx->setCurrentIndex(i); break; + } + } +} +//---------------------------------------------------- +void ConsoleVideoConfDialog_t::use_new_PPU_changed( int value ) +{ + //printf("Value:%i \n", value ); + g_config->setOption("SDL.NewPPU", (value == Qt::Checked) ); + g_config->save (); + + fceuWrapperLock(); + UpdateEMUCore (g_config); + fceuWrapperUnLock(); +} +//---------------------------------------------------- +void ConsoleVideoConfDialog_t::frameskip_changed( int value ) +{ + //printf("Value:%i \n", value ); + g_config->setOption("SDL.Frameskip", (value == Qt::Checked) ); + g_config->save (); + + fceuWrapperLock(); + UpdateEMUCore (g_config); + fceuWrapperUnLock(); +} +//---------------------------------------------------- +void ConsoleVideoConfDialog_t::useSpriteLimitChanged( int value ) +{ + //printf("Value:%i \n", value ); + g_config->setOption("SDL.DisableSpriteLimit", (value == Qt::Checked) ); + g_config->save (); + + fceuWrapperLock(); + UpdateEMUCore (g_config); + fceuWrapperUnLock(); +} +//---------------------------------------------------- +void ConsoleVideoConfDialog_t::clipSidesChanged( int value ) +{ + //printf("Value:%i \n", value ); + g_config->setOption("SDL.ClipSides", (value == Qt::Checked) ); + g_config->save (); + + fceuWrapperLock(); + UpdateEMUCore (g_config); + fceuWrapperUnLock(); +} +//---------------------------------------------------- +void ConsoleVideoConfDialog_t::showFPSChanged( int value ) +{ + //printf("Value:%i \n", value ); + g_config->setOption("SDL.ShowFPS", (value == Qt::Checked) ); + g_config->save (); + + fceuWrapperLock(); + UpdateEMUCore (g_config); + fceuWrapperUnLock(); +} +//---------------------------------------------------- +void ConsoleVideoConfDialog_t::regionChanged(int index) +{ + int region; + //printf("Region: %i : %i \n", index, regionSelect->itemData(index).toInt() ); + + region = regionSelect->itemData(index).toInt(); + + g_config->setOption ("SDL.PAL", region); + + g_config->save (); + + // reset sound subsystem for changes to take effect + fceuWrapperLock(); + FCEUI_SetRegion (region, true); + fceuWrapperUnLock(); +} +//---------------------------------------------------- +void ConsoleVideoConfDialog_t::applyChanges( void ) +{ + resetVideo(); +} +//---------------------------------------------------- +void ConsoleVideoConfDialog_t::closewindow( void ) +{ + done(0); +} +//---------------------------------------------------- diff --git a/src/drivers/Qt/ConsoleVideoConf.h b/src/drivers/Qt/ConsoleVideoConf.h new file mode 100644 index 00000000..e27d59c0 --- /dev/null +++ b/src/drivers/Qt/ConsoleVideoConf.h @@ -0,0 +1,55 @@ +// ConsoleVideoConf.h +// + +#ifndef __ConsoleVideoH__ +#define __ConsoleVideoH__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +class ConsoleVideoConfDialog_t : public QDialog +{ + Q_OBJECT + + public: + ConsoleVideoConfDialog_t(QWidget *parent = 0); + ~ConsoleVideoConfDialog_t(void); + + protected: + QComboBox *driverSelect; + QComboBox *regionSelect; + QCheckBox *gl_LF_chkBox; + QCheckBox *new_PPU_ena; + QCheckBox *frmskipcbx; + QCheckBox *sprtLimCbx; + QCheckBox *clipSidesCbx; + QCheckBox *showFPS_cbx; + + void setCheckBoxFromProperty( QCheckBox *cbx, const char *property ); + void setComboBoxFromProperty( QComboBox *cbx, const char *property ); + //void setSliderFromProperty( QSlider *slider, QLabel *lbl, const char *property ); + + void resetVideo(void); + + private slots: + void use_new_PPU_changed( int value ); + void frameskip_changed( int value ); + void useSpriteLimitChanged( int value ); + void clipSidesChanged( int value ); + void showFPSChanged( int value ); + void regionChanged(int index); + void applyChanges( void ); + void closewindow( void ); + +}; + +#endif diff --git a/src/drivers/Qt/ConsoleViewerGL.cpp b/src/drivers/Qt/ConsoleViewerGL.cpp new file mode 100644 index 00000000..b4b19b4a --- /dev/null +++ b/src/drivers/Qt/ConsoleViewerGL.cpp @@ -0,0 +1,190 @@ +// GameViewer.cpp +// +#include +#include +#include +#include + +#include +#include + +#include "Qt/nes_shm.h" +#include "Qt/ConsoleViewerGL.h" + +extern unsigned int gui_draw_area_width; +extern unsigned int gui_draw_area_height; + +ConsoleViewGL_t::ConsoleViewGL_t(QWidget *parent) + : QOpenGLWidget( parent ) +{ + view_width = 0; + view_height = 0; + gltexture = 0; + devPixRatio = 1.0f; + linearFilter = false; + + QScreen *screen = QGuiApplication::primaryScreen(); + + if ( screen != NULL ) + { + devPixRatio = screen->devicePixelRatio(); + //printf("Ratio: %f \n", screen->devicePixelRatio() ); + } + localBufSize = GL_NES_WIDTH * GL_NES_HEIGHT * sizeof(uint32_t); + + localBuf = (uint32_t*)malloc( localBufSize ); + + if ( localBuf ) + { + memset( localBuf, 0, localBufSize ); + } +} + +ConsoleViewGL_t::~ConsoleViewGL_t(void) +{ + // Make sure the context is current and then explicitly + // destroy all underlying OpenGL resources. + makeCurrent(); + + // Free GL texture + if (gltexture) + { + //printf("Destroying GL Texture\n"); + glDeleteTextures(1, &gltexture); + gltexture=0; + } + + doneCurrent(); + + if ( localBuf ) + { + free( localBuf ); localBuf = NULL; + } +} + +int ConsoleViewGL_t::init( void ) +{ + return 0; +} + +void ConsoleViewGL_t::buildTextures(void) +{ + glEnable(GL_TEXTURE_RECTANGLE); + + if ( gltexture ) + { + glDeleteTextures(1, &gltexture); + gltexture=0; + } + + glGenTextures(1, &gltexture); + //printf("Linear Interpolation on GL Texture: %s \n", linearFilter ? "Enabled" : "Disabled"); + + glBindTexture( GL_TEXTURE_RECTANGLE, gltexture); + + glTexParameteri( GL_TEXTURE_RECTANGLE, GL_TEXTURE_MAG_FILTER, linearFilter ? GL_LINEAR : GL_NEAREST ); + glTexParameteri( GL_TEXTURE_RECTANGLE, GL_TEXTURE_MIN_FILTER, linearFilter ? GL_LINEAR : GL_NEAREST ); + glTexParameteri( GL_TEXTURE_RECTANGLE, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE ); + glTexParameteri( GL_TEXTURE_RECTANGLE, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE ); + + glTexImage2D( GL_TEXTURE_RECTANGLE, 0, + GL_RGBA8, GL_NES_WIDTH, GL_NES_HEIGHT, 0, + GL_BGRA, GL_UNSIGNED_BYTE, 0 ); + +} + +void ConsoleViewGL_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"); + + buildTextures(); +} + +void ConsoleViewGL_t::resizeGL(int w, int h) +{ + w = (int)( devPixRatio * w ); + h = (int)( devPixRatio * h ); + //printf("GL Resize: %i x %i \n", w, h ); + glViewport(0, 0, w, h); + + view_width = w; + view_height = h; + + gui_draw_area_width = w; + gui_draw_area_height = h; + + buildTextures(); +} + +void ConsoleViewGL_t::transfer2LocalBuffer(void) +{ + memcpy( localBuf, nes_shm->pixbuf, localBufSize ); +} + +void ConsoleViewGL_t::paintGL(void) +{ + int texture_width = nes_shm->ncol; + int texture_height = nes_shm->nrow; + int l=0, r=texture_width; + int t=0, b=texture_height; + + float xscale = (float)view_width / (float)texture_width; + float yscale = (float)view_height / (float)texture_height; + + if (xscale < yscale ) + { + yscale = xscale; + } + else + { + xscale = yscale; + } + int rw=(int)((r-l)*xscale); + int rh=(int)((b-t)*yscale); + int sx=(view_width-rw)/2; + int sy=(view_height-rh)/2; + + glViewport(sx, sy, rw, rh); + + glLoadIdentity(); + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glMatrixMode(GL_MODELVIEW); + glOrtho( 0.0, rw, 0.0, rh, -1.0, 1.0); + + glDisable(GL_DEPTH_TEST); + glClearColor( 0.0, 0.0f, 0.0f, 0.0f); // Background color to black. + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + glDisable(GL_TEXTURE_2D); + glEnable(GL_TEXTURE_RECTANGLE); + glBindTexture(GL_TEXTURE_RECTANGLE, gltexture); + + glTexSubImage2D(GL_TEXTURE_RECTANGLE, 0, + 0, 0, GL_NES_WIDTH, GL_NES_HEIGHT, + GL_BGRA, GL_UNSIGNED_BYTE, localBuf ); + + glBegin(GL_QUADS); + glTexCoord2f( l, b); // Bottom left of picture. + glVertex2f( 0.0, 0.0f); // Bottom left of target. + + glTexCoord2f(r, b);// Bottom right of picture. + glVertex2f( rw, 0.0f); // Bottom right of target. + + glTexCoord2f(r, t); // Top right of our picture. + glVertex2f( rw, rh); // Top right of target. + + glTexCoord2f(l, t); // Top left of our picture. + glVertex2f( 0.0f, rh); // Top left of target. + glEnd(); + + glDisable(GL_TEXTURE_2D); + glDisable(GL_TEXTURE_RECTANGLE); + + //printf("Paint GL!\n"); +} diff --git a/src/drivers/Qt/ConsoleViewerGL.h b/src/drivers/Qt/ConsoleViewerGL.h new file mode 100644 index 00000000..b45ddcb4 --- /dev/null +++ b/src/drivers/Qt/ConsoleViewerGL.h @@ -0,0 +1,43 @@ +// GameViewerGL.h +// + +#pragma once + +#include + +#include +#include + +class ConsoleViewGL_t : public QOpenGLWidget, protected QOpenGLFunctions +{ + Q_OBJECT + + public: + ConsoleViewGL_t(QWidget *parent = 0); + ~ConsoleViewGL_t(void); + + int init( void ); + + void transfer2LocalBuffer(void); + + protected: + void initializeGL(void); + void resizeGL(int w, int h); + void paintGL(void); + + void buildTextures(void); + void calcPixRemap(void); + void doRemap(void); + + double devPixRatio; + int view_width; + int view_height; + GLuint gltexture; + bool linearFilter; + + uint32_t *localBuf; + uint32_t localBufSize; + + private slots: +}; + diff --git a/src/drivers/Qt/ConsoleViewerSDL.cpp b/src/drivers/Qt/ConsoleViewerSDL.cpp new file mode 100644 index 00000000..18867777 --- /dev/null +++ b/src/drivers/Qt/ConsoleViewerSDL.cpp @@ -0,0 +1,198 @@ +// GameViewer.cpp +// +#include +#include +#include +#include +#include + +#include "Qt/nes_shm.h" +#include "Qt/ConsoleViewerSDL.h" + +extern unsigned int gui_draw_area_width; +extern unsigned int gui_draw_area_height; + +ConsoleViewSDL_t::ConsoleViewSDL_t(QWidget *parent) + : QWidget( parent ) +{ + view_width = GL_NES_WIDTH; + view_height = GL_NES_HEIGHT; + + sx = sy = 0; + rw = view_width; + rh = view_height; + sdlRendW = 0; + sdlRendH = 0; + + devPixRatio = 1.0f; + sdlWindow = NULL; + sdlRenderer = NULL; + sdlTexture = NULL; + + vsyncEnabled = false; +} + +ConsoleViewSDL_t::~ConsoleViewSDL_t(void) +{ + +} + +int ConsoleViewSDL_t::init(void) +{ + WId windowHandle; + + if (SDL_InitSubSystem(SDL_INIT_VIDEO) != 0) + { + printf("[SDL] Failed to initialize video subsystem.\n"); + return -1; + } + //else + //{ + // printf("Initialized SDL Video Subsystem\n"); + //} + + windowHandle = this->winId(); + + //printf("Window Handle: %llu \n", windowHandle ); + + //sleep(1); + + sdlWindow = SDL_CreateWindowFrom( (void*)windowHandle); + if (sdlWindow == NULL) + { + printf("[SDL] Failed to create window from handle.\n"); + return -1; + } + + uint32_t baseFlags = vsyncEnabled ? SDL_RENDERER_PRESENTVSYNC : 0; + + sdlRenderer = SDL_CreateRenderer(sdlWindow, -1, baseFlags | SDL_RENDERER_ACCELERATED); + + if (sdlRenderer == NULL) + { + printf("[SDL] Failed to create accelerated renderer.\n"); + + printf("[SDL] Attempting to create software renderer...\n"); + + sdlRenderer = SDL_CreateRenderer(sdlWindow, -1, baseFlags | SDL_RENDERER_SOFTWARE); + + if (sdlRenderer == NULL) + { + printf("[SDL] Failed to create software renderer.\n"); + return -1; + } + } + + SDL_GetRendererOutputSize( sdlRenderer, &sdlRendW, &sdlRendH ); + + printf("[SDL] Renderer Output Size: %i x %i \n", sdlRendW, sdlRendH ); + + sdlTexture = SDL_CreateTexture(sdlRenderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, GL_NES_WIDTH, GL_NES_HEIGHT); + + if (sdlTexture == NULL) + { + printf("[SDL] Failed to create texture: %i x %i", GL_NES_WIDTH, GL_NES_HEIGHT ); + return -1; + } + + return 0; +} + +void ConsoleViewSDL_t::cleanup(void) +{ + if (sdlTexture) + { + SDL_DestroyTexture(sdlTexture); + sdlTexture = NULL; + } + if (sdlRenderer) + { + SDL_DestroyRenderer(sdlRenderer); + sdlRenderer = NULL; + } +} + +void ConsoleViewSDL_t::reset(void) +{ + cleanup(); + if ( init() == 0 ) + { + //console->GetVideoRenderer()->RegisterRenderingDevice(this); + } + else + { + cleanup(); + } +} + +void ConsoleViewSDL_t::resizeEvent(QResizeEvent *event) +{ + QSize s; + + s = event->size(); + view_width = s.width(); + view_height = s.height(); + //printf("SDL Resize: %i x %i \n", view_width, view_height); + + reset(); + + sdlViewport.x = sdlRendW - view_width; + sdlViewport.y = sdlRendH - view_height; + sdlViewport.w = view_width; + sdlViewport.h = view_height; +} + +void ConsoleViewSDL_t::paintEvent( QPaintEvent *event ) +{ + int nesWidth = GL_NES_WIDTH; + int nesHeight = GL_NES_HEIGHT; + + if ( nes_shm != NULL ) + { + nesWidth = nes_shm->ncol; + nesHeight = nes_shm->nrow; + } + //printf(" %i x %i \n", nesWidth, nesHeight ); + float xscale = (float)view_width / (float)nesWidth; + float yscale = (float)view_height / (float)nesHeight; + + if (xscale < yscale ) + { + yscale = xscale; + } + else + { + xscale = yscale; + } + + rw=(int)(nesWidth*xscale); + rh=(int)(nesHeight*yscale); + sx=sdlViewport.x + (view_width-rw)/2; + sy=sdlViewport.y + (view_height-rh)/2; + + if ( (sdlRenderer == NULL) || (sdlTexture == NULL) ) + { + return; + } + + SDL_SetRenderDrawColor( sdlRenderer, 0, 0, 0, 0 ); + + SDL_RenderClear(sdlRenderer); + + uint8_t *textureBuffer; + int rowPitch; + SDL_LockTexture( sdlTexture, nullptr, (void**)&textureBuffer, &rowPitch); + { + memcpy( textureBuffer, nes_shm->pixbuf, GL_NES_HEIGHT*GL_NES_WIDTH*sizeof(uint32_t) ); + } + SDL_UnlockTexture(sdlTexture); + + SDL_RenderSetViewport( sdlRenderer, &sdlViewport ); + + SDL_Rect source = {0, 0, GL_NES_WIDTH, GL_NES_HEIGHT }; + SDL_Rect dest = { sx, sy, rw, rh }; + SDL_RenderCopy(sdlRenderer, sdlTexture, &source, &dest); + + SDL_RenderPresent(sdlRenderer); + +} diff --git a/src/drivers/Qt/ConsoleViewerSDL.h b/src/drivers/Qt/ConsoleViewerSDL.h new file mode 100644 index 00000000..386d148a --- /dev/null +++ b/src/drivers/Qt/ConsoleViewerSDL.h @@ -0,0 +1,47 @@ +// GameViewerSDL.h +// + +#pragma once + +#include +#include +#include +#include + +class ConsoleViewSDL_t : public QWidget +{ + Q_OBJECT + + public: + ConsoleViewSDL_t(QWidget *parent = 0); + ~ConsoleViewSDL_t(void); + + int init(void); + void reset(void); + void cleanup(void); + + protected: + + void paintEvent(QPaintEvent *event); + void resizeEvent(QResizeEvent *event); + int view_width; + int view_height; + + double devPixRatio; + int rw; + int rh; + int sx; + int sy; + int sdlRendW; + int sdlRendH; + + bool vsyncEnabled; + + SDL_Window *sdlWindow; + SDL_Renderer *sdlRenderer; + SDL_Texture *sdlTexture; + SDL_Rect sdlViewport; + + private slots: +}; + diff --git a/src/drivers/Qt/ConsoleWindow.cpp b/src/drivers/Qt/ConsoleWindow.cpp new file mode 100644 index 00000000..c9bc21db --- /dev/null +++ b/src/drivers/Qt/ConsoleWindow.cpp @@ -0,0 +1,1352 @@ +// GameApp.cpp +// +#include +#include +#include +#include + +#include "../../fceu.h" +#include "../../fds.h" +#include "../../movie.h" + +#ifdef _S9XLUA_H +#include "../../fceulua.h" +#endif + +#include "Qt/main.h" +#include "Qt/dface.h" +#include "Qt/input.h" +#include "Qt/ConsoleWindow.h" +#include "Qt/GamePadConf.h" +#include "Qt/HotKeyConf.h" +#include "Qt/ConsoleSoundConf.h" +#include "Qt/ConsoleVideoConf.h" +#include "Qt/AboutWindow.h" +#include "Qt/fceuWrapper.h" +#include "Qt/keyscan.h" +#include "Qt/nes_shm.h" + +consoleWin_t::consoleWin_t(QWidget *parent) + : QMainWindow( parent ) +{ + + createMainMenu(); + + viewport = new ConsoleViewGL_t(this); + //viewport = new ConsoleViewSDL_t(this); + + setCentralWidget(viewport); + setWindowIcon(QIcon(":fceux1.png")); + + gameTimer = new QTimer( this ); + mutex = new QMutex( QMutex::NonRecursive ); + emulatorThread = new emulatorThread_t(); + + connect(emulatorThread, &QThread::finished, emulatorThread, &QObject::deleteLater); + + connect( gameTimer, &QTimer::timeout, this, &consoleWin_t::updatePeriodic ); + + gameTimer->setTimerType( Qt::PreciseTimer ); + //gameTimer->start( 16 ); // 60hz + gameTimer->start( 8 ); // 120hz + + emulatorThread->start(); + + gamePadConfWin = NULL; +} + +consoleWin_t::~consoleWin_t(void) +{ + nes_shm->runEmulator = 0; + + if ( gamePadConfWin != NULL ) + { + gamePadConfWin->closeWindow(); + } + fceuWrapperLock(); + fceuWrapperClose(); + fceuWrapperUnLock(); + + //printf("Thread Finished: %i \n", gameThread->isFinished() ); + emulatorThread->quit(); + emulatorThread->wait(); + + delete viewport; + delete mutex; + + // LoadGame() checks for an IP and if it finds one begins a network session + // clear the NetworkIP field so this doesn't happen unintentionally + g_config->setOption ("SDL.NetworkIP", ""); + g_config->save (); +} + +void consoleWin_t::setCyclePeriodms( int ms ) +{ + // If timer is already running, it will be restarted. + gameTimer->start( ms ); + + //printf("Period Set to: %i ms \n", ms ); +} + +void consoleWin_t::closeEvent(QCloseEvent *event) +{ + //printf("Main Window Close Event\n"); + if ( gamePadConfWin != NULL ) + { + //printf("Command Game Pad Close\n"); + gamePadConfWin->closeWindow(); + } + event->accept(); + + closeApp(); +} + +void consoleWin_t::keyPressEvent(QKeyEvent *event) +{ + //printf("Key Press: 0x%x \n", event->key() ); + pushKeyEvent( event, 1 ); +} + +void consoleWin_t::keyReleaseEvent(QKeyEvent *event) +{ + //printf("Key Release: 0x%x \n", event->key() ); + pushKeyEvent( event, 0 ); +} + +//--------------------------------------------------------------------------- +void consoleWin_t::createMainMenu(void) +{ + QMenu *subMenu; + QActionGroup *group; + + // This is needed for menu bar to show up on MacOS + menuBar()->setNativeMenuBar(false); + + //----------------------------------------------------------------------- + // File + fileMenu = menuBar()->addMenu(tr("File")); + + // File -> Open ROM + openROM = new QAction(tr("Open ROM"), this); + openROM->setShortcuts(QKeySequence::Open); + openROM->setStatusTip(tr("Open ROM File")); + connect(openROM, SIGNAL(triggered()), this, SLOT(openROMFile(void)) ); + + fileMenu->addAction(openROM); + + // File -> Close ROM + closeROM = new QAction(tr("Close ROM"), this); + closeROM->setShortcut( QKeySequence(tr("Ctrl+C"))); + closeROM->setStatusTip(tr("Close Loaded ROM")); + connect(closeROM, SIGNAL(triggered()), this, SLOT(closeROMCB(void)) ); + + fileMenu->addAction(closeROM); + + fileMenu->addSeparator(); + + // File -> Play NSF + playNSF = new QAction(tr("Play NSF"), this); + playNSF->setShortcut( QKeySequence(tr("Ctrl+N"))); + playNSF->setStatusTip(tr("Play NSF")); + connect(playNSF, SIGNAL(triggered()), this, SLOT(loadNSF(void)) ); + + fileMenu->addAction(playNSF); + + fileMenu->addSeparator(); + + // File -> Load State From + loadStateAct = new QAction(tr("Load State From"), this); + //loadStateAct->setShortcut( QKeySequence(tr("Ctrl+N"))); + loadStateAct->setStatusTip(tr("Load State From")); + connect(loadStateAct, SIGNAL(triggered()), this, SLOT(loadStateFrom(void)) ); + + fileMenu->addAction(loadStateAct); + + // File -> Save State As + saveStateAct = new QAction(tr("Save State As"), this); + //loadStateAct->setShortcut( QKeySequence(tr("Ctrl+N"))); + saveStateAct->setStatusTip(tr("Save State As")); + connect(saveStateAct, SIGNAL(triggered()), this, SLOT(saveStateAs(void)) ); + + fileMenu->addAction(saveStateAct); + + // File -> Quick Load + quickLoadAct = new QAction(tr("Quick Load"), this); + quickLoadAct->setShortcut( QKeySequence(tr("F7"))); + quickLoadAct->setStatusTip(tr("Quick Load")); + connect(quickLoadAct, SIGNAL(triggered()), this, SLOT(quickLoad(void)) ); + + fileMenu->addAction(quickLoadAct); + + // File -> Quick Save + quickSaveAct = new QAction(tr("Quick Save"), this); + quickSaveAct->setShortcut( QKeySequence(tr("F5"))); + quickSaveAct->setStatusTip(tr("Quick Save")); + connect(quickSaveAct, SIGNAL(triggered()), this, SLOT(quickSave(void)) ); + + fileMenu->addAction(quickSaveAct); + + // File -> Change State + subMenu = fileMenu->addMenu(tr("Change State")); + group = new QActionGroup(this); + + group->setExclusive(true); + + for (int i=0; i<10; i++) + { + char stmp[8]; + + sprintf( stmp, "%i", i ); + + state[i] = new QAction(tr(stmp), this); + state[i]->setCheckable(true); + + group->addAction(state[i]); + subMenu->addAction(state[i]); + } + state[0]->setChecked(true); + + connect(state[0], SIGNAL(triggered()), this, SLOT(changeState0(void)) ); + connect(state[1], SIGNAL(triggered()), this, SLOT(changeState1(void)) ); + connect(state[2], SIGNAL(triggered()), this, SLOT(changeState2(void)) ); + connect(state[3], SIGNAL(triggered()), this, SLOT(changeState3(void)) ); + connect(state[4], SIGNAL(triggered()), this, SLOT(changeState4(void)) ); + connect(state[5], SIGNAL(triggered()), this, SLOT(changeState5(void)) ); + connect(state[6], SIGNAL(triggered()), this, SLOT(changeState6(void)) ); + connect(state[7], SIGNAL(triggered()), this, SLOT(changeState7(void)) ); + connect(state[8], SIGNAL(triggered()), this, SLOT(changeState8(void)) ); + connect(state[9], SIGNAL(triggered()), this, SLOT(changeState9(void)) ); + + fileMenu->addSeparator(); + +#ifdef _S9XLUA_H + // File -> Quick Save + loadLuaAct = new QAction(tr("Load Lua Script"), this); + //loadLuaAct->setShortcut( QKeySequence(tr("F5"))); + loadLuaAct->setStatusTip(tr("Load Lua Script")); + connect(loadLuaAct, SIGNAL(triggered()), this, SLOT(loadLua(void)) ); + + fileMenu->addAction(loadLuaAct); + + fileMenu->addSeparator(); +#else + loadLuaAct = NULL; +#endif + + // File -> Screenshort + scrShotAct = new QAction(tr("Screenshot"), this); + scrShotAct->setShortcut( QKeySequence(tr("F12"))); + scrShotAct->setStatusTip(tr("Screenshot")); + connect(scrShotAct, SIGNAL(triggered()), this, SLOT(takeScreenShot())); + + fileMenu->addAction(scrShotAct); + + // File -> Quit + quitAct = new QAction(tr("Quit"), this); + quitAct->setShortcut( QKeySequence(tr("Ctrl+Q"))); + quitAct->setStatusTip(tr("Quit the Application")); + connect(quitAct, SIGNAL(triggered()), this, SLOT(closeApp())); + + fileMenu->addAction(quitAct); + + //----------------------------------------------------------------------- + // Options + optMenu = menuBar()->addMenu(tr("Options")); + + // Options -> GamePad Config + gamePadConfig = new QAction(tr("GamePad Config"), this); + //gamePadConfig->setShortcut( QKeySequence(tr("Ctrl+C"))); + gamePadConfig->setStatusTip(tr("GamePad Configure")); + connect(gamePadConfig, SIGNAL(triggered()), this, SLOT(openGamePadConfWin(void)) ); + + optMenu->addAction(gamePadConfig); + + // Options -> Sound Config + gameSoundConfig = new QAction(tr("Sound Config"), this); + //gameSoundConfig->setShortcut( QKeySequence(tr("Ctrl+C"))); + gameSoundConfig->setStatusTip(tr("Sound Configure")); + connect(gameSoundConfig, SIGNAL(triggered()), this, SLOT(openGameSndConfWin(void)) ); + + optMenu->addAction(gameSoundConfig); + + // Options -> Video Config + gameVideoConfig = new QAction(tr("Video Config"), this); + //gameVideoConfig->setShortcut( QKeySequence(tr("Ctrl+C"))); + gameVideoConfig->setStatusTip(tr("Video Preferences")); + connect(gameVideoConfig, SIGNAL(triggered()), this, SLOT(openGameVideoConfWin(void)) ); + + optMenu->addAction(gameVideoConfig); + + // Options -> HotKey Config + hotkeyConfig = new QAction(tr("Hotkey Config"), this); + //hotkeyConfig->setShortcut( QKeySequence(tr("Ctrl+C"))); + hotkeyConfig->setStatusTip(tr("Hotkey Configure")); + connect(hotkeyConfig, SIGNAL(triggered()), this, SLOT(openHotkeyConfWin(void)) ); + + optMenu->addAction(hotkeyConfig); + + // Options -> Auto-Resume + autoResume = new QAction(tr("Auto-Resume Play"), this); + //autoResume->setShortcut( QKeySequence(tr("Ctrl+C"))); + autoResume->setCheckable(true); + autoResume->setStatusTip(tr("Auto-Resume Play")); + connect(autoResume, SIGNAL(triggered()), this, SLOT(toggleAutoResume(void)) ); + + optMenu->addAction(autoResume); + + optMenu->addSeparator(); + + // Options -> Full Screen + fullscreen = new QAction(tr("Fullscreen"), this); + fullscreen->setShortcut( QKeySequence(tr("Alt+Return"))); + //fullscreen->setCheckable(true); + fullscreen->setStatusTip(tr("Fullscreen")); + connect(fullscreen, SIGNAL(triggered()), this, SLOT(toggleFullscreen(void)) ); + + optMenu->addAction(fullscreen); + + //----------------------------------------------------------------------- + // Emulation + emuMenu = menuBar()->addMenu(tr("Emulation")); + + // Emulation -> Power + powerAct = new QAction(tr("Power"), this); + //powerAct->setShortcut( QKeySequence(tr("Ctrl+P"))); + powerAct->setStatusTip(tr("Power On Console")); + connect(powerAct, SIGNAL(triggered()), this, SLOT(powerConsoleCB(void)) ); + + emuMenu->addAction(powerAct); + + // Emulation -> Reset + resetAct = new QAction(tr("Reset"), this); + //resetAct->setShortcut( QKeySequence(tr("Ctrl+R"))); + resetAct->setStatusTip(tr("Reset Console")); + connect(resetAct, SIGNAL(triggered()), this, SLOT(consoleHardReset(void)) ); + + emuMenu->addAction(resetAct); + + // Emulation -> Soft Reset + sresetAct = new QAction(tr("Soft Reset"), this); + //sresetAct->setShortcut( QKeySequence(tr("Ctrl+R"))); + sresetAct->setStatusTip(tr("Soft Reset of Console")); + connect(sresetAct, SIGNAL(triggered()), this, SLOT(consoleSoftReset(void)) ); + + emuMenu->addAction(sresetAct); + + // Emulation -> Pause + pauseAct = new QAction(tr("Pause"), this); + pauseAct->setShortcut( QKeySequence(tr("Pause"))); + pauseAct->setStatusTip(tr("Pause Console")); + connect(pauseAct, SIGNAL(triggered()), this, SLOT(consolePause(void)) ); + + emuMenu->addAction(pauseAct); + + emuMenu->addSeparator(); + + // Emulation -> Enable Game Genie + gameGenieAct = new QAction(tr("Enable Game Genie"), this); + //gameGenieAct->setShortcut( QKeySequence(tr("Ctrl+G"))); + gameGenieAct->setCheckable(true); + gameGenieAct->setStatusTip(tr("Enable Game Genie")); + connect(gameGenieAct, SIGNAL(triggered(bool)), this, SLOT(toggleGameGenie(bool)) ); + + syncActionConfig( gameGenieAct, "SDL.GameGenie" ); + + emuMenu->addAction(gameGenieAct); + + // Emulation -> Load Game Genie ROM + loadGgROMAct = new QAction(tr("Load Game Genie ROM"), this); + //loadGgROMAct->setShortcut( QKeySequence(tr("Ctrl+G"))); + loadGgROMAct->setStatusTip(tr("Load Game Genie ROM")); + connect(loadGgROMAct, SIGNAL(triggered()), this, SLOT(loadGameGenieROM(void)) ); + + emuMenu->addAction(loadGgROMAct); + + emuMenu->addSeparator(); + + // Emulation -> Insert Coin + insCoinAct = new QAction(tr("Insert Coin"), this); + //insCoinAct->setShortcut( QKeySequence(tr("Ctrl+G"))); + insCoinAct->setStatusTip(tr("Insert Coin")); + connect(insCoinAct, SIGNAL(triggered()), this, SLOT(insertCoin(void)) ); + + emuMenu->addAction(insCoinAct); + + emuMenu->addSeparator(); + + // Emulation -> FDS + subMenu = emuMenu->addMenu(tr("FDS")); + + // Emulation -> FDS -> Switch Disk + fdsSwitchAct = new QAction(tr("Switch Disk"), this); + //fdsSwitchAct->setShortcut( QKeySequence(tr("Ctrl+G"))); + fdsSwitchAct->setStatusTip(tr("Switch Disk")); + connect(fdsSwitchAct, SIGNAL(triggered()), this, SLOT(fdsSwitchDisk(void)) ); + + subMenu->addAction(fdsSwitchAct); + + // Emulation -> FDS -> Eject Disk + fdsEjectAct = new QAction(tr("Eject Disk"), this); + //fdsEjectAct->setShortcut( QKeySequence(tr("Ctrl+G"))); + fdsEjectAct->setStatusTip(tr("Eject Disk")); + connect(fdsEjectAct, SIGNAL(triggered()), this, SLOT(fdsEjectDisk(void)) ); + + subMenu->addAction(fdsEjectAct); + + // Emulation -> FDS -> Load BIOS + fdsLoadBiosAct = new QAction(tr("Load BIOS"), this); + //fdsLoadBiosAct->setShortcut( QKeySequence(tr("Ctrl+G"))); + fdsLoadBiosAct->setStatusTip(tr("Load BIOS")); + connect(fdsLoadBiosAct, SIGNAL(triggered()), this, SLOT(fdsLoadBiosFile(void)) ); + + subMenu->addAction(fdsLoadBiosAct); + + //----------------------------------------------------------------------- + // Movie + movieMenu = menuBar()->addMenu(tr("Movie")); + + // Movie -> Open + openMovAct = new QAction(tr("Open"), this); + openMovAct->setShortcut( QKeySequence(tr("Shift+F7"))); + openMovAct->setStatusTip(tr("Open Movie File")); + connect(openMovAct, SIGNAL(triggered()), this, SLOT(openMovie(void)) ); + + movieMenu->addAction(openMovAct); + + // Movie -> Stop + stopMovAct = new QAction(tr("Stop"), this); + //stopMovAct->setShortcut( QKeySequence(tr("Shift+F7"))); + stopMovAct->setStatusTip(tr("Stop Movie Recording")); + connect(stopMovAct, SIGNAL(triggered()), this, SLOT(stopMovie(void)) ); + + movieMenu->addAction(stopMovAct); + + movieMenu->addSeparator(); + + // Movie -> Record + recMovAct = new QAction(tr("Record"), this); + recMovAct->setShortcut( QKeySequence(tr("Shift+F5"))); + recMovAct->setStatusTip(tr("Record Movie")); + connect(recMovAct, SIGNAL(triggered()), this, SLOT(recordMovie(void)) ); + + movieMenu->addAction(recMovAct); + + // Movie -> Record As + recAsMovAct = new QAction(tr("Record As"), this); + //recAsMovAct->setShortcut( QKeySequence(tr("Shift+F5"))); + recAsMovAct->setStatusTip(tr("Record Movie")); + connect(recAsMovAct, SIGNAL(triggered()), this, SLOT(recordMovieAs(void)) ); + + movieMenu->addAction(recAsMovAct); + + //----------------------------------------------------------------------- + // Help + helpMenu = menuBar()->addMenu(tr("Help")); + + aboutAct = new QAction(tr("About"), this); + aboutAct->setStatusTip(tr("About FCEUX")); + connect(aboutAct, SIGNAL(triggered()), this, SLOT(aboutFCEUX(void)) ); + + helpMenu->addAction(aboutAct); +}; +//--------------------------------------------------------------------------- +void consoleWin_t::closeApp(void) +{ + nes_shm->runEmulator = 0; + + fceuWrapperLock(); + fceuWrapperClose(); + fceuWrapperUnLock(); + + // LoadGame() checks for an IP and if it finds one begins a network session + // clear the NetworkIP field so this doesn't happen unintentionally + g_config->setOption ("SDL.NetworkIP", ""); + g_config->save (); + //SDL_Quit (); // Already called by fceuWrapperClose + + //qApp::quit(); + qApp->quit(); +} +//--------------------------------------------------------------------------- +int consoleWin_t::getDirFromFile( const char *path, char *dir ) +{ + int i, lastSlash = -1, lastPeriod = -1; + + i=0; + while ( path[i] != 0 ) + { + if ( path[i] == '/' ) + { + lastSlash = i; + } + else if ( path[i] == '.' ) + { + lastPeriod = i; + } + dir[i] = path[i]; i++; + } + dir[i] = 0; + + if ( lastPeriod >= 0 ) + { + if ( lastPeriod > lastSlash ) + { + dir[lastSlash] = 0; + } + } + + return 0; +} +//--------------------------------------------------------------------------- + +void consoleWin_t::openROMFile(void) +{ + int ret; + QString filename; + std::string last; + char dir[512]; + QFileDialog dialog(this, tr("Open ROM File") ); + + dialog.setFileMode(QFileDialog::ExistingFile); + + dialog.setNameFilter(tr("NES files (*.nes)(*.NES) ;; All files (*)")); + + dialog.setViewMode(QFileDialog::List); + + g_config->getOption ("SDL.LastOpenFile", &last ); + + getDirFromFile( last.c_str(), dir ); + + dialog.setDirectory( tr(dir) ); + + // the gnome default file dialog is not playing nice with QT. + // TODO make this a config option to use native file dialog. + dialog.setOption(QFileDialog::DontUseNativeDialog, true); + + dialog.show(); + ret = dialog.exec(); + + if ( ret ) + { + QStringList fileList; + fileList = dialog.selectedFiles(); + + if ( fileList.size() > 0 ) + { + filename = fileList[0]; + } + } + + if ( filename.isNull() ) + { + return; + } + qDebug() << "selected file path : " << filename.toUtf8(); + + g_config->setOption ("SDL.LastOpenFile", filename.toStdString().c_str() ); + + fceuWrapperLock(); + CloseGame (); + LoadGame ( filename.toStdString().c_str() ); + fceuWrapperUnLock(); + + return; +} + +void consoleWin_t::closeROMCB(void) +{ + fceuWrapperLock(); + CloseGame(); + fceuWrapperUnLock(); +} + +void consoleWin_t::loadNSF(void) +{ + int ret; + QString filename; + std::string last; + char dir[512]; + QFileDialog dialog(this, tr("Load NSF File") ); + + dialog.setFileMode(QFileDialog::ExistingFile); + + dialog.setNameFilter(tr("NSF Sound Files (*.nsf)(*.NSF) ;; Zip Files (*.zip)(*.ZIP) ;; All files (*)")); + + dialog.setViewMode(QFileDialog::List); + + g_config->getOption ("SDL.LastOpenNSF", &last ); + + getDirFromFile( last.c_str(), dir ); + + dialog.setDirectory( tr(dir) ); + + // the gnome default file dialog is not playing nice with QT. + // TODO make this a config option to use native file dialog. + dialog.setOption(QFileDialog::DontUseNativeDialog, true); + + dialog.show(); + ret = dialog.exec(); + + if ( ret ) + { + QStringList fileList; + fileList = dialog.selectedFiles(); + + if ( fileList.size() > 0 ) + { + filename = fileList[0]; + } + } + + if ( filename.isNull() ) + { + return; + } + qDebug() << "selected file path : " << filename.toUtf8(); + + g_config->setOption ("SDL.LastOpenNSF", filename.toStdString().c_str() ); + + fceuWrapperLock(); + LoadGame( filename.toStdString().c_str() ); + fceuWrapperUnLock(); +} + +void consoleWin_t::loadStateFrom(void) +{ + int ret; + QString filename; + std::string last; + char dir[512]; + QFileDialog dialog(this, tr("Load State From File") ); + + dialog.setFileMode(QFileDialog::ExistingFile); + + dialog.setNameFilter(tr("FCS Files (*.fc?)(*.FC?) ;; SAV Files (*.sav)(*.SAV) ;; All files (*)")); + + dialog.setViewMode(QFileDialog::List); + + g_config->getOption ("SDL.LastLoadStateFrom", &last ); + + getDirFromFile( last.c_str(), dir ); + + dialog.setDirectory( tr(dir) ); + + // the gnome default file dialog is not playing nice with QT. + // TODO make this a config option to use native file dialog. + dialog.setOption(QFileDialog::DontUseNativeDialog, true); + + dialog.show(); + ret = dialog.exec(); + + if ( ret ) + { + QStringList fileList; + fileList = dialog.selectedFiles(); + + if ( fileList.size() > 0 ) + { + filename = fileList[0]; + } + } + + if ( filename.isNull() ) + { + return; + } + qDebug() << "selected file path : " << filename.toUtf8(); + + g_config->setOption ("SDL.LastLoadStateFrom", filename.toStdString().c_str() ); + + fceuWrapperLock(); + FCEUI_LoadState( filename.toStdString().c_str() ); + fceuWrapperUnLock(); +} + +void consoleWin_t::saveStateAs(void) +{ + int ret; + QString filename; + std::string last; + char dir[512]; + QFileDialog dialog(this, tr("Save State To File") ); + + dialog.setFileMode(QFileDialog::AnyFile); + + dialog.setNameFilter(tr("FCS Files (*.fc?)(*.FC?) ;; SAV Files (*.sav)(*.SAV) ;; All files (*)")); + + dialog.setViewMode(QFileDialog::List); + + g_config->getOption ("SDL.LastSaveStateAs", &last ); + + getDirFromFile( last.c_str(), dir ); + + dialog.setDirectory( tr(dir) ); + + // the gnome default file dialog is not playing nice with QT. + // TODO make this a config option to use native file dialog. + dialog.setOption(QFileDialog::DontUseNativeDialog, true); + + dialog.show(); + ret = dialog.exec(); + + if ( ret ) + { + QStringList fileList; + fileList = dialog.selectedFiles(); + + if ( fileList.size() > 0 ) + { + filename = fileList[0]; + } + } + + if ( filename.isNull() ) + { + return; + } + qDebug() << "selected file path : " << filename.toUtf8(); + + g_config->setOption ("SDL.LastSaveStateAs", filename.toStdString().c_str() ); + + fceuWrapperLock(); + FCEUI_SaveState( filename.toStdString().c_str() ); + fceuWrapperUnLock(); +} + +void consoleWin_t::quickLoad(void) +{ + fceuWrapperLock(); + FCEUI_LoadState( NULL ); + fceuWrapperUnLock(); +} + +void consoleWin_t::quickSave(void) +{ + fceuWrapperLock(); + FCEUI_SaveState( NULL ); + fceuWrapperUnLock(); +} + +void consoleWin_t::changeState0(void) +{ + fceuWrapperLock(); + FCEUI_SelectState( 0, 1 ); + fceuWrapperUnLock(); +} + +void consoleWin_t::changeState1(void) +{ + fceuWrapperLock(); + FCEUI_SelectState( 1, 1 ); + fceuWrapperUnLock(); +} + +void consoleWin_t::changeState2(void) +{ + fceuWrapperLock(); + FCEUI_SelectState( 2, 1 ); + fceuWrapperUnLock(); +} + +void consoleWin_t::changeState3(void) +{ + fceuWrapperLock(); + FCEUI_SelectState( 3, 1 ); + fceuWrapperUnLock(); +} + +void consoleWin_t::changeState4(void) +{ + fceuWrapperLock(); + FCEUI_SelectState( 4, 1 ); + fceuWrapperUnLock(); +} + +void consoleWin_t::changeState5(void) +{ + fceuWrapperLock(); + FCEUI_SelectState( 5, 1 ); + fceuWrapperUnLock(); +} + +void consoleWin_t::changeState6(void) +{ + fceuWrapperLock(); + FCEUI_SelectState( 6, 1 ); + fceuWrapperUnLock(); +} + +void consoleWin_t::changeState7(void) +{ + fceuWrapperLock(); + FCEUI_SelectState( 7, 1 ); + fceuWrapperUnLock(); +} + +void consoleWin_t::changeState8(void) +{ + fceuWrapperLock(); + FCEUI_SelectState( 8, 1 ); + fceuWrapperUnLock(); +} + +void consoleWin_t::changeState9(void) +{ + fceuWrapperLock(); + FCEUI_SelectState( 9, 1 ); + fceuWrapperUnLock(); +} + +void consoleWin_t::takeScreenShot(void) +{ + fceuWrapperLock(); + FCEUI_SaveSnapshot(); + fceuWrapperUnLock(); +} + +void consoleWin_t::loadLua(void) +{ +#ifdef _S9XLUA_H + int ret; + QString filename; + std::string last; + char dir[512]; + QFileDialog dialog(this, tr("Open LUA Script") ); + + dialog.setFileMode(QFileDialog::ExistingFile); + + dialog.setNameFilter(tr("LUA Scripts (*.lua)(*.LUA) ;; All files (*)")); + + dialog.setViewMode(QFileDialog::List); + + g_config->getOption ("SDL.LastLoadLua", &last ); + + if ( last.size() == 0 ) + { + last.assign( "/usr/share/fceux/luaScripts" ); + } + + getDirFromFile( last.c_str(), dir ); + + dialog.setDirectory( tr(dir) ); + + // the gnome default file dialog is not playing nice with QT. + // TODO make this a config option to use native file dialog. + dialog.setOption(QFileDialog::DontUseNativeDialog, true); + + dialog.show(); + ret = dialog.exec(); + + if ( ret ) + { + QStringList fileList; + fileList = dialog.selectedFiles(); + + if ( fileList.size() > 0 ) + { + filename = fileList[0]; + } + } + + if ( filename.isNull() ) + { + return; + } + qDebug() << "selected file path : " << filename.toUtf8(); + + g_config->setOption ("SDL.LastLoadLua", filename.toStdString().c_str() ); + + fceuWrapperLock(); + if ( 0 == FCEU_LoadLuaCode( filename.toStdString().c_str() ) ) + { + printf("Error: Could not open the selected lua script: '%s'\n", filename.toStdString().c_str() ); + } + fceuWrapperUnLock(); +#endif +} + +void consoleWin_t::openGamePadConfWin(void) +{ + if ( gamePadConfWin != NULL ) + { + printf("GamePad Config Window Already Open\n"); + return; + } + //printf("Open GamePad Config Window\n"); + gamePadConfWin = new GamePadConfDialog_t(this); + + gamePadConfWin->show(); + gamePadConfWin->exec(); + + delete gamePadConfWin; + gamePadConfWin = NULL; + //printf("GamePad Config Window Destroyed\n"); +} + +void consoleWin_t::openGameSndConfWin(void) +{ + ConsoleSndConfDialog_t *sndConfWin; + + //printf("Open Sound Config Window\n"); + + sndConfWin = new ConsoleSndConfDialog_t(this); + + sndConfWin->show(); + sndConfWin->exec(); + + delete sndConfWin; + + //printf("Sound Config Window Destroyed\n"); +} + +void consoleWin_t::openGameVideoConfWin(void) +{ + ConsoleVideoConfDialog_t *vidConfWin; + + //printf("Open Video Config Window\n"); + + vidConfWin = new ConsoleVideoConfDialog_t(this); + + vidConfWin->show(); + vidConfWin->exec(); + + delete vidConfWin; + + //printf("Video Config Window Destroyed\n"); +} + +void consoleWin_t::openHotkeyConfWin(void) +{ + HotKeyConfDialog_t *hkConfWin; + + //printf("Open Hot Key Config Window\n"); + + hkConfWin = new HotKeyConfDialog_t(this); + + hkConfWin->show(); + hkConfWin->exec(); + + delete hkConfWin; + + //printf("Hotkey Config Window Destroyed\n"); +} + +void consoleWin_t::toggleAutoResume(void) +{ + //printf("Auto Resume: %i\n", autoResume->isChecked() ); + + g_config->setOption ("SDL.AutoResume", (int) autoResume->isChecked() ); + + AutoResumePlay = autoResume->isChecked(); +} + +void consoleWin_t::toggleFullscreen(void) +{ + if ( isFullScreen() ) + { + showNormal(); + } + else + { + showFullScreen(); + } +} + +void consoleWin_t::powerConsoleCB(void) +{ + fceuWrapperLock(); + FCEUI_PowerNES(); + fceuWrapperUnLock(); + return; +} + +void consoleWin_t::consoleHardReset(void) +{ + fceuWrapperLock(); + fceuWrapperHardReset(); + fceuWrapperUnLock(); + return; +} + +void consoleWin_t::consoleSoftReset(void) +{ + fceuWrapperLock(); + fceuWrapperSoftReset(); + fceuWrapperUnLock(); + return; +} + +void consoleWin_t::consolePause(void) +{ + fceuWrapperLock(); + fceuWrapperTogglePause(); + fceuWrapperUnLock(); + return; +} + +void consoleWin_t::toggleGameGenie(bool checked) +{ + int gg_enabled; + + fceuWrapperLock(); + g_config->getOption ("SDL.GameGenie", &gg_enabled); + g_config->setOption ("SDL.GameGenie", !gg_enabled); + g_config->save (); + FCEUI_SetGameGenie (gg_enabled); + fceuWrapperUnLock(); + return; +} + +void consoleWin_t::loadGameGenieROM(void) +{ + int ret; + QString filename; + std::string last; + char dir[512]; + QFileDialog dialog(this, tr("Open Game Genie ROM") ); + + dialog.setFileMode(QFileDialog::ExistingFile); + + dialog.setNameFilter(tr("GG ROM File (gg.rom)(*Genie*.nes) ;; All files (*)")); + + dialog.setViewMode(QFileDialog::List); + + g_config->getOption ("SDL.LastOpenFile", &last ); + + getDirFromFile( last.c_str(), dir ); + + dialog.setDirectory( tr(dir) ); + + // the gnome default file dialog is not playing nice with QT. + // TODO make this a config option to use native file dialog. + dialog.setOption(QFileDialog::DontUseNativeDialog, true); + + dialog.show(); + ret = dialog.exec(); + + if ( ret ) + { + QStringList fileList; + fileList = dialog.selectedFiles(); + + if ( fileList.size() > 0 ) + { + filename = fileList[0]; + } + } + + if ( filename.isNull() ) + { + return; + } + qDebug() << "selected file path : " << filename.toUtf8(); + + g_config->setOption ("SDL.LastOpenFile", filename.toStdString().c_str() ); + + // copy file to proper place (~/.fceux/gg.rom) + std::ifstream f1 ( filename.toStdString().c_str(), std::fstream::binary); + std::string fn_out = FCEU_MakeFName (FCEUMKF_GGROM, 0, ""); + std::ofstream f2 (fn_out.c_str (), + std::fstream::trunc | std::fstream::binary); + f2 << f1.rdbuf (); + + return; +} + +void consoleWin_t::insertCoin(void) +{ + fceuWrapperLock(); + FCEUI_VSUniCoin(); + fceuWrapperUnLock(); + return; +} + +void consoleWin_t::fdsSwitchDisk(void) +{ + fceuWrapperLock(); + FCEU_FDSSelect(); + fceuWrapperUnLock(); + return; +} + +void consoleWin_t::fdsEjectDisk(void) +{ + fceuWrapperLock(); + FCEU_FDSInsert(); + fceuWrapperUnLock(); + return; +} + +void consoleWin_t::fdsLoadBiosFile(void) +{ + int ret; + QString filename; + std::string last; + char dir[512]; + QFileDialog dialog(this, tr("Load FDS BIOS (disksys.rom)") ); + + dialog.setFileMode(QFileDialog::ExistingFile); + + dialog.setNameFilter(tr("ROM files (*.rom)(*.ROM) ;; All files (*)")); + + dialog.setViewMode(QFileDialog::List); + + g_config->getOption ("SDL.LastOpenFile", &last ); + + getDirFromFile( last.c_str(), dir ); + + dialog.setDirectory( tr(dir) ); + + // the gnome default file dialog is not playing nice with QT. + // TODO make this a config option to use native file dialog. + dialog.setOption(QFileDialog::DontUseNativeDialog, true); + + dialog.show(); + ret = dialog.exec(); + + if ( ret ) + { + QStringList fileList; + fileList = dialog.selectedFiles(); + + if ( fileList.size() > 0 ) + { + filename = fileList[0]; + } + } + + if ( filename.isNull() ) + { + return; + } + qDebug() << "selected file path : " << filename.toUtf8(); + + // copy BIOS file to proper place (~/.fceux/disksys.rom) + std::ifstream fdsBios (filename.toStdString().c_str(), std::fstream::binary); + std::string output_filename = + FCEU_MakeFName (FCEUMKF_FDSROM, 0, ""); + std::ofstream outFile (output_filename.c_str (), + std::fstream::trunc | std::fstream:: + binary); + outFile << fdsBios.rdbuf (); + if (outFile.fail ()) + { + FCEUD_PrintError ("Error copying the FDS BIOS file."); + } + else + { + printf("Famicom Disk System BIOS loaded. If you are you having issues, make sure your BIOS file is 8KB in size.\n"); + } + + return; +} + +void consoleWin_t::openMovie(void) +{ + int ret; + QString filename; + std::string last; + char dir[512]; + QFileDialog dialog(this, tr("Open FM2 Movie") ); + + dialog.setFileMode(QFileDialog::ExistingFile); + + dialog.setNameFilter(tr("FM2 Movies (*.fm2) ;; All files (*)")); + + dialog.setViewMode(QFileDialog::List); + + g_config->getOption ("SDL.LastOpenFile", &last ); + + getDirFromFile( last.c_str(), dir ); + + dialog.setDirectory( tr(dir) ); + + // the gnome default file dialog is not playing nice with QT. + // TODO make this a config option to use native file dialog. + dialog.setOption(QFileDialog::DontUseNativeDialog, true); + + dialog.show(); + ret = dialog.exec(); + + if ( ret ) + { + QStringList fileList; + fileList = dialog.selectedFiles(); + + if ( fileList.size() > 0 ) + { + filename = fileList[0]; + } + } + + if ( filename.isNull() ) + { + return; + } + qDebug() << "selected file path : " << filename.toUtf8(); + + int pauseframe; + g_config->getOption ("SDL.PauseFrame", &pauseframe); + g_config->setOption ("SDL.PauseFrame", 0); + + FCEUI_printf ("Playing back movie located at %s\n", filename.toStdString().c_str() ); + + fceuWrapperLock(); + if (FCEUI_LoadMovie( filename.toStdString().c_str(), + false, pauseframe ? pauseframe : false) == false) + { + printf("Error: Could not open movie file: %s \n", filename.toStdString().c_str() ); + } + fceuWrapperUnLock(); + + return; +} + +void consoleWin_t::stopMovie(void) +{ + fceuWrapperLock(); + FCEUI_StopMovie(); + fceuWrapperUnLock(); + return; +} + +void consoleWin_t::recordMovie(void) +{ + fceuWrapperLock(); + if (fceuWrapperGameLoaded()) + { + std::string name = FCEU_MakeFName (FCEUMKF_MOVIE, 0, 0); + FCEUI_printf ("Recording movie to %s\n", name.c_str ()); + FCEUI_SaveMovie (name.c_str (), MOVIE_FLAG_NONE, L""); + } + fceuWrapperUnLock(); + return; +} + +void consoleWin_t::recordMovieAs(void) +{ + int ret; + QString filename; + std::string last; + char dir[512]; + QFileDialog dialog(this, tr("Save FM2 Movie for Recording") ); + + dialog.setFileMode(QFileDialog::AnyFile); + + dialog.setNameFilter(tr("FM2 Movies (*.fm2) ;; All files (*)")); + + dialog.setViewMode(QFileDialog::List); + + g_config->getOption ("SDL.LastOpenFile", &last ); + + getDirFromFile( last.c_str(), dir ); + + dialog.setDirectory( tr(dir) ); + + // the gnome default file dialog is not playing nice with QT. + // TODO make this a config option to use native file dialog. + dialog.setOption(QFileDialog::DontUseNativeDialog, true); + + dialog.show(); + ret = dialog.exec(); + + if ( ret ) + { + QStringList fileList; + fileList = dialog.selectedFiles(); + + if ( fileList.size() > 0 ) + { + filename = fileList[0]; + } + } + + if ( filename.isNull() ) + { + return; + } + qDebug() << "selected file path : " << filename.toUtf8(); + + int pauseframe; + g_config->getOption ("SDL.PauseFrame", &pauseframe); + g_config->setOption ("SDL.PauseFrame", 0); + + FCEUI_printf ("Recording movie to %s\n", filename.toStdString().c_str() ); + + fceuWrapperLock(); + std::string s = GetUserText ("Author name"); + std::wstring author (s.begin (), s.end ()); + + FCEUI_SaveMovie ( filename.toStdString().c_str(), MOVIE_FLAG_NONE, author); + fceuWrapperUnLock(); + + return; +} + +void consoleWin_t::aboutFCEUX(void) +{ + AboutWindow *aboutWin; + + //printf("About FCEUX Window\n"); + + aboutWin = new AboutWindow(this); + + aboutWin->show(); + aboutWin->exec(); + + delete aboutWin; + + //printf("About Window Destroyed\n"); + return; +} + +void consoleWin_t::syncActionConfig( QAction *act, const char *property ) +{ + if ( act->isCheckable() ) + { + int enable; + g_config->getOption ( property, &enable); + + act->setChecked( enable ? true : false ); + } +} + +void consoleWin_t::updatePeriodic(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); + + // Update Input Devices + FCEUD_UpdateInput(); + + // RePaint Game Viewport + if ( nes_shm->blitUpdated ) + { + nes_shm->blitUpdated = 0; + + viewport->transfer2LocalBuffer(); + + //viewport->repaint(); + viewport->update(); + } + + return; +} + +void emulatorThread_t::run(void) +{ + printf("Emulator Start\n"); + nes_shm->runEmulator = 1; + + while ( nes_shm->runEmulator ) + { + fceuWrapperUpdate(); + } + printf("Emulator Exit\n"); + emit finished(); +} diff --git a/src/drivers/Qt/ConsoleWindow.h b/src/drivers/Qt/ConsoleWindow.h new file mode 100644 index 00000000..59bb43f5 --- /dev/null +++ b/src/drivers/Qt/ConsoleWindow.h @@ -0,0 +1,153 @@ + +// + +#ifndef __GameAppH__ +#define __GameAppH__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "Qt/ConsoleViewerGL.h" +#include "Qt/ConsoleViewerSDL.h" +#include "Qt/GamePadConf.h" + +class emulatorThread_t : public QThread +{ + Q_OBJECT + + //public slots: + void run( void ) override; + signals: + void finished(); +}; + +class consoleWin_t : public QMainWindow +{ + Q_OBJECT + + public: + consoleWin_t(QWidget *parent = 0); + ~consoleWin_t(void); + + ConsoleViewGL_t *viewport; + //ConsoleViewSDL_t *viewport; + + void setCyclePeriodms( int ms ); + + QMutex *mutex; + + protected: + QMenu *fileMenu; + QMenu *optMenu; + QMenu *emuMenu; + QMenu *movieMenu; + QMenu *helpMenu; + + QAction *openROM; + QAction *closeROM; + QAction *playNSF; + QAction *loadStateAct; + QAction *saveStateAct; + QAction *quickLoadAct; + QAction *quickSaveAct; + QAction *loadLuaAct; + QAction *scrShotAct; + QAction *quitAct; + QAction *gamePadConfig; + QAction *gameSoundConfig; + QAction *gameVideoConfig; + QAction *hotkeyConfig; + QAction *autoResume; + QAction *fullscreen; + QAction *aboutAct; + QAction *state[10]; + QAction *powerAct; + QAction *resetAct; + QAction *sresetAct; + QAction *pauseAct; + QAction *gameGenieAct; + QAction *loadGgROMAct; + QAction *insCoinAct; + QAction *fdsSwitchAct; + QAction *fdsEjectAct; + QAction *fdsLoadBiosAct; + QAction *openMovAct; + QAction *stopMovAct; + QAction *recMovAct; + QAction *recAsMovAct; + + QTimer *gameTimer; + emulatorThread_t *emulatorThread; + + GamePadConfDialog_t *gamePadConfWin; + + protected: + void closeEvent(QCloseEvent *event); + void keyPressEvent(QKeyEvent *event); + void keyReleaseEvent(QKeyEvent *event); + void syncActionConfig( QAction *act, const char *property ); + + int getDirFromFile( const char *path, char *dir ); + + private: + void createMainMenu(void); + + private slots: + void closeApp(void); + void openROMFile(void); + void loadNSF(void); + void loadStateFrom(void); + void saveStateAs(void); + void quickLoad(void); + void quickSave(void); + void closeROMCB(void); + void aboutFCEUX(void); + void openGamePadConfWin(void); + void openGameSndConfWin(void); + void openGameVideoConfWin(void); + void openHotkeyConfWin(void); + void toggleAutoResume(void); + void toggleFullscreen(void); + void updatePeriodic(void); + void changeState0(void); + void changeState1(void); + void changeState2(void); + void changeState3(void); + void changeState4(void); + void changeState5(void); + void changeState6(void); + void changeState7(void); + void changeState8(void); + void changeState9(void); + void loadLua(void); + void takeScreenShot(void); + void powerConsoleCB(void); + void consoleHardReset(void); + void consoleSoftReset(void); + void consolePause(void); + void toggleGameGenie(bool checked); + void loadGameGenieROM(void); + void insertCoin(void); + void fdsSwitchDisk(void); + void fdsEjectDisk(void); + void fdsLoadBiosFile(void); + void openMovie(void); + void stopMovie(void); + void recordMovie(void); + void recordMovieAs(void); + +}; + +extern consoleWin_t *consoleWindow; + +#endif diff --git a/src/drivers/Qt/GamePadConf.cpp b/src/drivers/Qt/GamePadConf.cpp new file mode 100644 index 00000000..24cfb88c --- /dev/null +++ b/src/drivers/Qt/GamePadConf.cpp @@ -0,0 +1,439 @@ +// GamePadConf.cpp +// +#include "Qt/GamePadConf.h" +#include "Qt/main.h" +#include "Qt/input.h" +#include "Qt/config.h" +#include "Qt/keyscan.h" +#include "Qt/fceuWrapper.h" + +//---------------------------------------------------- +GamePadConfDialog_t::GamePadConfDialog_t(QWidget *parent) + : QDialog( parent ) +{ + QHBoxLayout *hbox1, *hbox2; + QGridLayout *grid; + QCheckBox *efs_chkbox, *udlr_chkbox; + QGroupBox *frame; + QPushButton *loadDefaultButton; + QPushButton *clearAllButton; + QPushButton *closebutton; + QPushButton *clearButton[GAMEPAD_NUM_BUTTONS]; + + portNum = 0; + configNo = 0; + buttonConfigStatus = 1; + + setWindowTitle( tr("GamePad Config") ); + + hbox1 = new QHBoxLayout(); + hbox2 = new QHBoxLayout(); + + QLabel *label = new QLabel(tr("Port:")); + portSel = new QComboBox(); + hbox1->addWidget( label ); + hbox1->addWidget( portSel ); + + portSel->addItem( tr("1"), 0 ); + portSel->addItem( tr("2"), 1 ); + portSel->addItem( tr("3"), 2 ); + portSel->addItem( tr("4"), 3 ); + + efs_chkbox = new QCheckBox( tr("Enable Four Score") ); + udlr_chkbox = new QCheckBox( tr("Allow Up+Down/Left+Right") ); + + int fourScore; + g_config->getOption("SDL.FourScore", &fourScore); + efs_chkbox->setChecked( fourScore ); + + int opposite_dirs; + g_config->getOption("SDL.Input.EnableOppositeDirectionals", &opposite_dirs); + udlr_chkbox->setChecked( opposite_dirs ); + + frame = new QGroupBox(tr("Buttons:")); + grid = new QGridLayout(); + + grid-> setHorizontalSpacing(50); + + //frame->setFrameStyle( QFrame::Box ); + frame->setLayout( grid ); + + for (int i=0; isetAlignment(Qt::AlignCenter); + + buttonName = new QLabel(tr(text)); + keyName[i] = new QLabel(); + button[i] = new GamePadConfigButton_t(i); + clearButton[i] = new QPushButton( tr("Clear") ); + + grid->addWidget( buttonName , i, 0, Qt::AlignCenter ); + grid->addWidget( keyName[i] , i, 1, Qt::AlignCenter ); + grid->addWidget( button[i] , i, 2, Qt::AlignCenter ); + grid->addWidget( clearButton[i], i, 3, Qt::AlignCenter ); + } + updateCntrlrDpy(); + + loadDefaultButton = new QPushButton(tr("Load Defaults")); + clearAllButton = new QPushButton(tr("Clear All")); + closebutton = new QPushButton(tr("Close")); + + hbox2->addWidget( loadDefaultButton ); + hbox2->addWidget( clearAllButton ); + hbox2->addWidget( closebutton ); + + connect(button[0], SIGNAL(clicked()), this, SLOT(changeButton0(void)) ); + connect(button[1], SIGNAL(clicked()), this, SLOT(changeButton1(void)) ); + connect(button[2], SIGNAL(clicked()), this, SLOT(changeButton2(void)) ); + connect(button[3], SIGNAL(clicked()), this, SLOT(changeButton3(void)) ); + connect(button[4], SIGNAL(clicked()), this, SLOT(changeButton4(void)) ); + connect(button[5], SIGNAL(clicked()), this, SLOT(changeButton5(void)) ); + connect(button[6], SIGNAL(clicked()), this, SLOT(changeButton6(void)) ); + connect(button[7], SIGNAL(clicked()), this, SLOT(changeButton7(void)) ); + connect(button[8], SIGNAL(clicked()), this, SLOT(changeButton8(void)) ); + connect(button[9], SIGNAL(clicked()), this, SLOT(changeButton9(void)) ); + + connect(clearButton[0], SIGNAL(clicked()), this, SLOT(clearButton0(void)) ); + connect(clearButton[1], SIGNAL(clicked()), this, SLOT(clearButton1(void)) ); + connect(clearButton[2], SIGNAL(clicked()), this, SLOT(clearButton2(void)) ); + connect(clearButton[3], SIGNAL(clicked()), this, SLOT(clearButton3(void)) ); + connect(clearButton[4], SIGNAL(clicked()), this, SLOT(clearButton4(void)) ); + connect(clearButton[5], SIGNAL(clicked()), this, SLOT(clearButton5(void)) ); + connect(clearButton[6], SIGNAL(clicked()), this, SLOT(clearButton6(void)) ); + connect(clearButton[7], SIGNAL(clicked()), this, SLOT(clearButton7(void)) ); + connect(clearButton[8], SIGNAL(clicked()), this, SLOT(clearButton8(void)) ); + connect(clearButton[9], SIGNAL(clicked()), this, SLOT(clearButton9(void)) ); + + connect(loadDefaultButton, SIGNAL(clicked()), this, SLOT(loadDefaults(void)) ); + connect(clearAllButton , SIGNAL(clicked()), this, SLOT(clearAllCallback(void)) ); + connect(closebutton , SIGNAL(clicked()), this, SLOT(closeWindow(void)) ); + + connect(portSel , SIGNAL(activated(int)), this, SLOT(controllerSelect(int)) ); + connect(efs_chkbox , SIGNAL(stateChanged(int)), this, SLOT(ena4score(int)) ); + connect(udlr_chkbox, SIGNAL(stateChanged(int)), this, SLOT(oppDirEna(int)) ); + + QVBoxLayout *mainLayout = new QVBoxLayout(); + + mainLayout->addLayout( hbox1 ); + mainLayout->addWidget( efs_chkbox ); + mainLayout->addWidget( udlr_chkbox ); + mainLayout->addWidget( frame ); + mainLayout->addLayout( hbox2 ); + + setLayout( mainLayout ); + +} + +//---------------------------------------------------- +GamePadConfDialog_t::~GamePadConfDialog_t(void) +{ + buttonConfigStatus = 0; +} +void GamePadConfDialog_t::keyPressEvent(QKeyEvent *event) +{ + //printf("GamePad Window Key Press: 0x%x \n", event->key() ); + pushKeyEvent( event, 1 ); +} + +void GamePadConfDialog_t::keyReleaseEvent(QKeyEvent *event) +{ + //printf("GamePad Window Key Release: 0x%x \n", event->key() ); + pushKeyEvent( event, 0 ); +} +//---------------------------------------------------- +void GamePadConfDialog_t::updateCntrlrDpy(void) +{ + char keyNameStr[128]; + + for (int i=0; isetText( tr(keyNameStr) ); + } +} +//---------------------------------------------------- +void GamePadConfDialog_t::controllerSelect(int index) +{ + //printf("Port Number:%i \n", index); + portNum = index; + updateCntrlrDpy(); +} +//---------------------------------------------------- +void GamePadConfDialog_t::ena4score(int state) +{ + int value = (state == Qt::Unchecked) ? 0 : 1; + //printf("Set 'SDL.FourScore' = %i\n", value); + g_config->setOption("SDL.FourScore", value); +} +//---------------------------------------------------- +void GamePadConfDialog_t::oppDirEna(int state) +{ + int value = (state == Qt::Unchecked) ? 0 : 1; + //printf("Set 'SDL.Input.EnableOppositeDirectionals' = %i\n", value); + g_config->setOption("SDL.Input.EnableOppositeDirectionals", value); +} +//---------------------------------------------------- +void GamePadConfDialog_t::changeButton(int padNo, int x) +{ + char buf[256]; + std::string prefix; + const char *keyNameStr; + + if ( buttonConfigStatus == 2 ) + { + buttonConfigStatus = 0; + return; + } + buttonConfigStatus = 2; + + ButtonConfigBegin (); + + button[x]->setText("Waiting" ); + + snprintf (buf, sizeof(buf)-1, "SDL.Input.GamePad.%d.", padNo); + prefix = buf; + DWaitButton (NULL, &GamePadConfig[padNo][x], configNo, &buttonConfigStatus ); + + g_config->setOption (prefix + GamePadNames[x], + GamePadConfig[padNo][x].ButtonNum[configNo]); + + if (GamePadConfig[padNo][x].ButtType[configNo] == BUTTC_KEYBOARD) + { + g_config->setOption (prefix + "DeviceType", "Keyboard"); + } + else if (GamePadConfig[padNo][x].ButtType[configNo] == BUTTC_JOYSTICK) + { + g_config->setOption (prefix + "DeviceType", "Joystick"); + } + else + { + g_config->setOption (prefix + "DeviceType", "Unknown"); + } + g_config->setOption (prefix + "DeviceNum", + GamePadConfig[padNo][x].DeviceNum[configNo]); + + keyNameStr = ButtonName( &GamePadConfig[padNo][x], configNo ); + + keyName[x]->setText( keyNameStr ); + button[x]->setText("Change"); + + ButtonConfigEnd (); + + buttonConfigStatus = 1; +} +//---------------------------------------------------- +void GamePadConfDialog_t::clearButton( int padNo, int x ) +{ + char buf[256]; + std::string prefix; + + GamePadConfig[padNo][x].ButtonNum[configNo] = -1; + + keyName[x]->setText(""); + + snprintf (buf, sizeof(buf)-1, "SDL.Input.GamePad.%d.", padNo); + prefix = buf; + + g_config->setOption (prefix + GamePadNames[x], + GamePadConfig[padNo][x].ButtonNum[configNo]); + +} +//---------------------------------------------------- +void GamePadConfDialog_t::closeEvent(QCloseEvent *event) +{ + //printf("GamePad Close Window Event\n"); + buttonConfigStatus = 0; + done(0); + event->accept(); +} +//---------------------------------------------------- +void GamePadConfDialog_t::closeWindow(void) +{ + //printf("Close Window\n"); + buttonConfigStatus = 0; + done(0); +} +//---------------------------------------------------- +void GamePadConfDialog_t::changeButton0(void) +{ + changeButton( portNum, 0 ); +} +//---------------------------------------------------- +void GamePadConfDialog_t::changeButton1(void) +{ + changeButton( portNum, 1 ); +} +//---------------------------------------------------- +void GamePadConfDialog_t::changeButton2(void) +{ + changeButton( portNum, 2 ); +} +//---------------------------------------------------- +void GamePadConfDialog_t::changeButton3(void) +{ + changeButton( portNum, 3 ); +} +//---------------------------------------------------- +void GamePadConfDialog_t::changeButton4(void) +{ + changeButton( portNum, 4 ); +} +//---------------------------------------------------- +void GamePadConfDialog_t::changeButton5(void) +{ + changeButton( portNum, 5 ); +} +//---------------------------------------------------- +void GamePadConfDialog_t::changeButton6(void) +{ + changeButton( portNum, 6 ); +} +//---------------------------------------------------- +void GamePadConfDialog_t::changeButton7(void) +{ + changeButton( portNum, 7 ); +} +//---------------------------------------------------- +void GamePadConfDialog_t::changeButton8(void) +{ + changeButton( portNum, 8 ); +} +//---------------------------------------------------- +void GamePadConfDialog_t::changeButton9(void) +{ + changeButton( portNum, 9 ); +} +//---------------------------------------------------- +void GamePadConfDialog_t::clearButton0(void) +{ + clearButton( portNum, 0 ); +} +//---------------------------------------------------- +void GamePadConfDialog_t::clearButton1(void) +{ + clearButton( portNum, 1 ); +} +//---------------------------------------------------- +void GamePadConfDialog_t::clearButton2(void) +{ + clearButton( portNum, 2 ); +} +//---------------------------------------------------- +void GamePadConfDialog_t::clearButton3(void) +{ + clearButton( portNum, 3 ); +} +//---------------------------------------------------- +void GamePadConfDialog_t::clearButton4(void) +{ + clearButton( portNum, 4 ); +} +//---------------------------------------------------- +void GamePadConfDialog_t::clearButton5(void) +{ + clearButton( portNum, 5 ); +} +//---------------------------------------------------- +void GamePadConfDialog_t::clearButton6(void) +{ + clearButton( portNum, 6 ); +} +//---------------------------------------------------- +void GamePadConfDialog_t::clearButton7(void) +{ + clearButton( portNum, 7 ); +} +//---------------------------------------------------- +void GamePadConfDialog_t::clearButton8(void) +{ + clearButton( portNum, 8 ); +} +//---------------------------------------------------- +void GamePadConfDialog_t::clearButton9(void) +{ + clearButton( portNum, 9 ); +} +//---------------------------------------------------- +void GamePadConfDialog_t::clearAllCallback(void) +{ + for (int i=0; i 0 ) + { + clearAllCallback(); + return; + } + + snprintf (buf, sizeof(buf)-1, "SDL.Input.GamePad.%d.", portNum); + prefix = buf; + + for (int x=0; xsetOption (prefix + GamePadNames[x], + GamePadConfig[portNum][x].ButtonNum[configNo]); + + if (GamePadConfig[portNum][x].ButtType[configNo] == BUTTC_KEYBOARD) + { + g_config->setOption (prefix + "DeviceType", "Keyboard"); + } + else if (GamePadConfig[portNum][x].ButtType[configNo] == BUTTC_JOYSTICK) + { + g_config->setOption (prefix + "DeviceType", "Joystick"); + } + else + { + g_config->setOption (prefix + "DeviceType", "Unknown"); + } + g_config->setOption (prefix + "DeviceNum", + GamePadConfig[portNum][x].DeviceNum[configNo]); + } + updateCntrlrDpy(); +} +//---------------------------------------------------- +GamePadConfigButton_t::GamePadConfigButton_t(int i) +{ + idx = i; + setText("Change"); +} +//---------------------------------------------------- +void GamePadConfigButton_t::keyPressEvent(QKeyEvent *event) +{ + //printf("GamePad Button Key Press: 0x%x \n", event->key() ); + pushKeyEvent( event, 1 ); +} + +void GamePadConfigButton_t::keyReleaseEvent(QKeyEvent *event) +{ + //printf("GamePad Button Key Release: 0x%x \n", event->key() ); + pushKeyEvent( event, 0 ); +} +//---------------------------------------------------- diff --git a/src/drivers/Qt/GamePadConf.h b/src/drivers/Qt/GamePadConf.h new file mode 100644 index 00000000..0f83000c --- /dev/null +++ b/src/drivers/Qt/GamePadConf.h @@ -0,0 +1,85 @@ +// GamePadConf.h +// + +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "Qt/main.h" + +class GamePadConfigButton_t : public QPushButton +{ + public: + GamePadConfigButton_t(int i); + + protected: + void keyPressEvent(QKeyEvent *event); + void keyReleaseEvent(QKeyEvent *event); + + int idx; +}; + +class GamePadConfDialog_t : public QDialog +{ + Q_OBJECT + + public: + GamePadConfDialog_t(QWidget *parent = 0); + ~GamePadConfDialog_t(void); + + protected: + QComboBox *portSel; + QLabel *keyName[GAMEPAD_NUM_BUTTONS]; + GamePadConfigButton_t *button[GAMEPAD_NUM_BUTTONS]; + + int portNum; + int configNo; + int buttonConfigStatus; + + void changeButton( int port, int button ); + void clearButton( int port, int button ); + void keyPressEvent(QKeyEvent *event); + void keyReleaseEvent(QKeyEvent *event); + void closeEvent(QCloseEvent *bar); + private: + void updateCntrlrDpy(void); + + public slots: + void closeWindow(void); + private slots: + void changeButton0(void); + void changeButton1(void); + void changeButton2(void); + void changeButton3(void); + void changeButton4(void); + void changeButton5(void); + void changeButton6(void); + void changeButton7(void); + void changeButton8(void); + void changeButton9(void); + void clearButton0(void); + void clearButton1(void); + void clearButton2(void); + void clearButton3(void); + void clearButton4(void); + void clearButton5(void); + void clearButton6(void); + void clearButton7(void); + void clearButton8(void); + void clearButton9(void); + void clearAllCallback(void); + void loadDefaults(void); + void ena4score(int state); + void oppDirEna(int state); + void controllerSelect(int index); + +}; diff --git a/src/drivers/Qt/HotKeyConf.cpp b/src/drivers/Qt/HotKeyConf.cpp new file mode 100644 index 00000000..13c33f1c --- /dev/null +++ b/src/drivers/Qt/HotKeyConf.cpp @@ -0,0 +1,125 @@ +// HotKeyConf.cpp +// +#include +#include +#include +#include + +#include +#include + +#include "Qt/main.h" +#include "Qt/dface.h" +#include "Qt/input.h" +#include "Qt/config.h" +#include "Qt/keyscan.h" +#include "Qt/fceuWrapper.h" +#include "Qt/HotKeyConf.h" + +//---------------------------------------------------------------------------- +HotKeyConfDialog_t::HotKeyConfDialog_t(QWidget *parent) + : QDialog( parent ) +{ + QVBoxLayout *mainLayout; + QTreeWidgetItem *item; + std::string prefix = "SDL.Hotkeys."; + int keycode; + + setWindowTitle("Hotkey Configuration"); + + resize( 512, 512 ); + + mainLayout = new QVBoxLayout(); + + tree = new QTreeWidget(); + + tree->setColumnCount(2); + + item = new QTreeWidgetItem(); + item->setText( 0, QString::fromStdString( "Command" ) ); + item->setText( 1, QString::fromStdString( "Key" ) ); + item->setTextAlignment( 0, Qt::AlignLeft); + item->setTextAlignment( 1, Qt::AlignCenter); + + tree->setHeaderItem( item ); + + tree->header()->setSectionResizeMode( QHeaderView::ResizeToContents ); + + for (int i=0; igetOption (optionName.c_str (), &keycode); + + item = new QTreeWidgetItem(); + + item->setText( 0, QString::fromStdString( optionName ) ); + item->setText( 1, QString::fromStdString( SDL_GetKeyName (keycode) ) ); + + item->setTextAlignment( 0, Qt::AlignLeft); + item->setTextAlignment( 1, Qt::AlignCenter); + + tree->addTopLevelItem( item ); + } + mainLayout->addWidget( tree ); + + setLayout( mainLayout ); +} +//---------------------------------------------------------------------------- +HotKeyConfDialog_t::~HotKeyConfDialog_t(void) +{ + +} +//---------------------------------------------------------------------------- +void HotKeyConfDialog_t::closeWindow(void) +{ + //printf("Close Window\n"); + done(0); +} +//---------------------------------------------------------------------------- +void HotKeyConfDialog_t::assignHotkey(QKeyEvent *event) +{ + SDL_Keycode k = convQtKey2SDLKeyCode( (Qt::Key)event->key() ); + + if ( k != SDLK_UNKNOWN ) + { + QList l; + + l = tree->selectedItems(); + + for (size_t i=0; i < l.size(); i++) + { + //int idx; + QString qs; + QTreeWidgetItem *item; + + item = l.at(i); + + //idx = tree->indexOfTopLevelItem( item ); + + qs = item->text(0); + + g_config->setOption ( qs.toStdString(), k ); + + setHotKeys(); + + item->setText( 1, QString::fromStdString( SDL_GetKeyName (k) ) ); + + //printf("Hotkey Window Key Press: 0x%x item:%p\n '%s' : %i\n", + // k, item, qs.toStdString().c_str(), idx ); + } + } +} +//---------------------------------------------------------------------------- +void HotKeyConfDialog_t::keyPressEvent(QKeyEvent *event) +{ + //printf("Hotkey Window Key Press: 0x%x \n", event->key() ); + assignHotkey( event ); +} +//---------------------------------------------------------------------------- +void HotKeyConfDialog_t::keyReleaseEvent(QKeyEvent *event) +{ + //printf("Hotkey Window Key Release: 0x%x \n", event->key() ); + assignHotkey( event ); +} +//---------------------------------------------------------------------------- diff --git a/src/drivers/Qt/HotKeyConf.h b/src/drivers/Qt/HotKeyConf.h new file mode 100644 index 00000000..cba35cee --- /dev/null +++ b/src/drivers/Qt/HotKeyConf.h @@ -0,0 +1,42 @@ +// GamePadConf.h +// + +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "Qt/main.h" + +class HotKeyConfDialog_t : public QDialog +{ + Q_OBJECT + + public: + HotKeyConfDialog_t(QWidget *parent = 0); + ~HotKeyConfDialog_t(void); + + protected: + void keyPressEvent(QKeyEvent *event); + void keyReleaseEvent(QKeyEvent *event); + void assignHotkey(QKeyEvent *event); + + QTreeWidget *tree; + + private: + + public slots: + void closeWindow(void); + private slots: + +}; diff --git a/src/drivers/Qt/config.cpp b/src/drivers/Qt/config.cpp new file mode 100644 index 00000000..5c16c617 --- /dev/null +++ b/src/drivers/Qt/config.cpp @@ -0,0 +1,482 @@ +#include "Qt/main.h" +#include "Qt/throttle.h" +#include "Qt/config.h" + +#include "../common/cheat.h" + +#include "Qt/input.h" +#include "Qt/dface.h" + +#include "Qt/sdl.h" +#include "Qt/sdl-video.h" +#include "Qt/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); + + 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", ""); + + // 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..c413a259 --- /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..2f3890ec --- /dev/null +++ b/src/drivers/Qt/dface.h @@ -0,0 +1,37 @@ +#include "common/args.h" +#include "common/config.h" + +#include "Qt/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..7e1daca0 --- /dev/null +++ b/src/drivers/Qt/fceuWrapper.cpp @@ -0,0 +1,1001 @@ +// fceuWrapper.cpp +// +#include +#include +#include + +#include "Qt/main.h" +#include "Qt/throttle.h" +#include "Qt/config.h" +#include "Qt/dface.h" +#include "Qt/fceuWrapper.h" +#include "Qt/input.h" +#include "Qt/sdl.h" +#include "Qt/sdl-video.h" +#include "Qt/nes_shm.h" +#include "Qt/unix-netplay.h" +#include "Qt/ConsoleWindow.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; +static int frameskip=0; +static int periodic_saves = 0; +static bool mutexLocked = 0; + +extern double g_fpsScale; + +#ifdef CREATE_AVI +int mutecapture = 0; +#endif +//***************************************************************** +// 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) +{ + int gg_enabled; + + if (isloaded){ + CloseGame(); + } + + // For some reason, the core of the emulator clears the state of + // the game genie option selection. So check the config each time + // and re-enable the core game genie state if needed. + g_config->getOption ("SDL.GameGenie", &gg_enabled); + + FCEUI_SetGameGenie (gg_enabled); + + 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); +} + +int fceuWrapperSoftReset(void) +{ + if ( isloaded ) + { + ResetNES(); + } + return 0; +} + +int fceuWrapperHardReset(void) +{ + if ( isloaded ) + { + std::string lastFile; + CloseGame(); + g_config->getOption ("SDL.LastOpenFile", &lastFile); + LoadGame (lastFile.c_str()); + } + return 0; +} + +int fceuWrapperTogglePause(void) +{ + if ( isloaded ) + { + FCEUI_ToggleEmulationPause(); + } + return 0; +} + +bool fceuWrapperGameLoaded(void) +{ + return (isloaded ? true : false); +} + +static const char *DriverUsage = +"Option Value Description\n" +"--pal {0|1} Use PAL timing.\n" +"--newppu {0|1} Enable the new PPU core. (WARNING: May break savestates)\n" +"--inputcfg d Configures input device d on startup.\n" +"--input(1,2) d Set which input device to emulate for input 1 or 2.\n" +" Devices: gamepad zapper powerpad.0 powerpad.1\n" +" arkanoid\n" +"--input(3,4) d Set the famicom expansion device to emulate for\n" +" input(3, 4)\n" +" Devices: quizking hypershot mahjong toprider ftrainer\n" +" familykeyboard oekakids arkanoid shadow bworld\n" +" 4player\n" +"--gamegenie {0|1} Enable emulated Game Genie.\n" +"--frameskip x Set # of frames to skip per emulated frame.\n" +"--xres x Set horizontal resolution for full screen mode.\n" +"--yres x Set vertical resolution for full screen mode.\n" +"--autoscale {0|1} Enable autoscaling in fullscreen. \n" +"--keepratio {0|1} Keep native NES aspect ratio when autoscaling. \n" +"--(x/y)scale x Multiply width/height by x. \n" +" (Real numbers >0 with OpenGL, otherwise integers >0).\n" +"--(x/y)stretch {0|1} Stretch to fill surface on x/y axis (OpenGL only).\n" +"--bpp {8|16|32} Set bits per pixel.\n" +"--opengl {0|1} Enable OpenGL support.\n" +"--fullscreen {0|1} Enable full screen mode.\n" +"--noframe {0|1} Hide title bar and window decorations.\n" +"--special {1-4} Use special video scaling filters\n" +" (1 = hq2x; 2 = Scale2x; 3 = NTSC 2x; 4 = hq3x;\n" +" 5 = Scale3x; 6 = Prescale2x; 7 = Prescale3x; 8=Precale4x; 9=PAL)\n" +"--palette f Load custom global palette from file f.\n" +"--sound {0|1} Enable sound.\n" +"--soundrate x Set sound playback rate to x Hz.\n" +"--soundq {0|1|2} Set sound quality. (0 = Low 1 = High 2 = Very High)\n" +"--soundbufsize x Set sound buffer size to x ms.\n" +"--volume {0-256} Set volume to x.\n" +"--soundrecord f Record sound to file f.\n" +"--playmov f Play back a recorded FCM/FM2/FM3 movie from filename f.\n" +"--pauseframe x Pause movie playback at frame x.\n" +"--fcmconvert f Convert fcm movie file f to fm2.\n" +"--ripsubs f Convert movie's subtitles to srt\n" +"--subtitles {0|1} Enable subtitle display\n" +"--fourscore {0|1} Enable fourscore emulation\n" +"--no-config {0|1} Use default config file and do not save\n" +"--net s Connect to server 's' for TCP/IP network play.\n" +"--port x Use TCP/IP port x for network play.\n" +"--user x Set the nickname to use in network play.\n" +"--pass x Set password to use for connecting to the server.\n" +"--netkey s Use string 's' to create a unique session for the\n" +" game loaded.\n" +"--players x Set the number of local players in a network play\n" +" session.\n" +"--rp2mic {0|1} Replace Port 2 Start with microphone (Famicom).\n" +"--nogui Don't load the GTK GUI\n" +"--4buttonexit {0|1} exit the emulator when A+B+Select+Start is pressed\n" +"--loadstate {0-9|>9} load from the given state when the game is loaded\n" +"--savestate {0-9|>9} save to the given state when the game is closed\n" +" to not save/load automatically provide a number\n" +" greater than 9\n" +"--periodicsaves {0|1} enable automatic periodic saving. This will save to\n" +" the state passed to --savestate\n"; + +static void ShowUsage(const char *prog) +{ + printf("\nUsage is as follows:\n%s filename\n\n",prog); + puts(DriverUsage); +#ifdef _S9XLUA_H + puts ("--loadlua f Loads lua script from filename f."); +#endif +#ifdef CREATE_AVI + puts ("--videolog c Calls mencoder to grab the video and audio streams to\n encode them. Check the documentation for more on this."); + puts ("--mute {0|1} Mutes FCEUX while still passing the audio stream to\n mencoder during avi creation."); +#endif + puts(""); + printf("Compiled with SDL version %d.%d.%d\n", SDL_MAJOR_VERSION, SDL_MINOR_VERSION, SDL_PATCHLEVEL ); + SDL_version v; + SDL_GetVersion(&v); + printf("Linked with SDL version %d.%d.%d\n", v.major, v.minor, v.patch); + printf("Compiled with QT version %d.%d.%d\n", QT_VERSION_MAJOR, QT_VERSION_MINOR, QT_VERSION_PATCH ); + +} + +int fceuWrapperInit( int argc, char *argv[] ) +{ + int error; + + for (int i=0; iparse(argc, argv); + + // This is here so that a default fceux.cfg will be created on first + // run, even without a valid ROM to play. + // Unless, of course, there's actually --no-config given + // mbg 8/23/2008 - this is also here so that the inputcfg routines can have + // a chance to dump the new inputcfg to the fceux.cfg in case you didnt + // specify a rom filename + g_config->getOption("SDL.NoConfig", &noconfig); + + if (!noconfig) + { + g_config->save(); + } + + std::string s; + + g_config->getOption("SDL.InputCfg", &s); + + if (s.size() != 0) + { + InitVideo(GameInfo); + InputCfg(s); + } + + // update the input devices + UpdateInput(g_config); + + // check for a .fcm file to convert to .fm2 + g_config->getOption ("SDL.FCMConvert", &s); + g_config->setOption ("SDL.FCMConvert", ""); + if (!s.empty()) + { + int okcount = 0; + std::string infname = s.c_str(); + // produce output filename + std::string outname; + size_t dot = infname.find_last_of ("."); + if (dot == std::string::npos) + outname = infname + ".fm2"; + else + outname = infname.substr(0,dot) + ".fm2"; + + MovieData md; + EFCM_CONVERTRESULT result = convert_fcm (md, infname); + + if (result == FCM_CONVERTRESULT_SUCCESS) { + okcount++; + // *outf = new EMUFILE; + EMUFILE_FILE* outf = FCEUD_UTF8_fstream (outname, "wb"); + md.dump (outf,false); + delete outf; + FCEUD_Message ("Your file has been converted to FM2.\n"); + } + else { + FCEUD_Message ("Something went wrong while converting your file...\n"); + } + + DriverKill(); + SDL_Quit(); + return 0; + } + // If x/y res set to 0, store current display res in SDL.LastX/YRes + int yres, xres; + g_config->getOption("SDL.XResolution", &xres); + g_config->getOption("SDL.YResolution", &yres); + + int autoResume; + g_config->getOption("SDL.AutoResume", &autoResume); + if(autoResume) + { + AutoResumePlay = true; + } + else + { + AutoResumePlay = false; + } + + // check to see if recording HUD to AVI is enabled + int rh; + g_config->getOption("SDL.RecordHUD", &rh); + if( rh == 0) + FCEUI_SetAviEnableHUDrecording(true); + else + FCEUI_SetAviEnableHUDrecording(false); + + // check to see if movie messages are disabled + int mm; + g_config->getOption("SDL.MovieMsg", &mm); + if( mm == 0) + FCEUI_SetAviDisableMovieMessages(true); + else + FCEUI_SetAviDisableMovieMessages(false); + + // check for a .fm2 file to rip the subtitles + g_config->getOption("SDL.RipSubs", &s); + g_config->setOption("SDL.RipSubs", ""); + if (!s.empty()) + { + MovieData md; + std::string infname; + infname = s.c_str(); + FCEUFILE *fp = FCEU_fopen(s.c_str(), 0, "rb", 0); + + // load the movie and and subtitles + extern bool LoadFM2(MovieData&, EMUFILE*, int, bool); + LoadFM2(md, fp->stream, INT_MAX, false); + LoadSubtitles(md); // fill subtitleFrames and subtitleMessages + delete fp; + + // produce .srt file's name and open it for writing + std::string outname; + size_t dot = infname.find_last_of ("."); + if (dot == std::string::npos) + outname = infname + ".srt"; + else + outname = infname.substr(0,dot) + ".srt"; + FILE *srtfile; + srtfile = fopen(outname.c_str(), "w"); + + if (srtfile != NULL) + { + extern std::vector subtitleFrames; + extern std::vector subtitleMessages; + float fps = (md.palFlag == 0 ? 60.0988 : 50.0069); // NTSC vs PAL + float subduration = 3; // seconds for the subtitles to be displayed + for (int i = 0; i < subtitleFrames.size(); i++) + { + fprintf(srtfile, "%i\n", i+1); // starts with 1, not 0 + double seconds, ms, endseconds, endms; + seconds = subtitleFrames[i]/fps; + if (i+1 < subtitleFrames.size()) // there's another subtitle coming after this one + { + if (subtitleFrames[i+1]-subtitleFrames[i] < subduration*fps) // avoid two subtitles at the same time + { + endseconds = (subtitleFrames[i+1]-1)/fps; // frame x: subtitle1; frame x+1 subtitle2 + } else { + endseconds = seconds+subduration; + } + } else { + endseconds = seconds+subduration; + } + ms = modf(seconds, &seconds); + endms = modf(endseconds, &endseconds); + // this is just beyond ugly, don't show it to your kids + fprintf(srtfile, + "%02.0f:%02d:%02d,%03d --> %02.0f:%02d:%02d,%03d\n", // hh:mm:ss,ms --> hh:mm:ss,ms + floor(seconds/3600), (int)floor(seconds/60 ) % 60, (int)floor(seconds) % 60, (int)(ms*1000), + floor(endseconds/3600), (int)floor(endseconds/60) % 60, (int)floor(endseconds) % 60, (int)(endms*1000)); + fprintf(srtfile, "%s\n\n", subtitleMessages[i].c_str()); // new line for every subtitle + } + fclose(srtfile); + printf("%d subtitles have been ripped.\n", (int)subtitleFrames.size()); + } else { + FCEUD_Message("Couldn't create output srt file...\n"); + } + + DriverKill(); + SDL_Quit(); + return 0; + } + + nes_shm = open_nes_shm(); + + if ( nes_shm == NULL ) + { + printf("Error: Failed to open NES Shared memory\n"); + return -1; + } + + // update the emu core + UpdateEMUCore(g_config); + + #ifdef CREATE_AVI + g_config->getOption("SDL.VideoLog", &s); + g_config->setOption("SDL.VideoLog", ""); + if(!s.empty()) + { + NESVideoSetVideoCmd(s.c_str()); + LoggingEnabled = 1; + g_config->getOption("SDL.MuteCapture", &mutecapture); + } else { + mutecapture = 0; + } + #endif + + { + int id; + g_config->getOption("SDL.InputDisplay", &id); + extern int input_display; + input_display = id; + // not exactly an id as an true/false switch; still better than creating another int for that + g_config->getOption("SDL.SubtitleDisplay", &id); + extern int movieSubtitles; + movieSubtitles = id; + } + + // load the hotkeys from the config life + setHotKeys(); + + if (romIndex >= 0) + { + // load the specified game + error = LoadGame(argv[romIndex]); + if (error != 1) + { + DriverKill(); + SDL_Quit(); + return -1; + } + g_config->setOption("SDL.LastOpenFile", argv[romIndex]); + g_config->save(); + } + + // movie playback + g_config->getOption("SDL.Movie", &s); + g_config->setOption("SDL.Movie", ""); + if (s != "") + { + if(s.find(".fm2") != std::string::npos || s.find(".fm3") != std::string::npos) + { + static int pauseframe; + g_config->getOption("SDL.PauseFrame", &pauseframe); + g_config->setOption("SDL.PauseFrame", 0); + FCEUI_printf("Playing back movie located at %s\n", s.c_str()); + FCEUI_LoadMovie(s.c_str(), false, pauseframe ? pauseframe : false); + } + else + { + FCEUI_printf("Sorry, I don't know how to play back %s\n", s.c_str()); + } + g_config->getOption("SDL.MovieLength",&KillFCEUXonFrame); + printf("KillFCEUXonFrame %d\n",KillFCEUXonFrame); + } + + int save_state; + g_config->getOption("SDL.PeriodicSaves", &periodic_saves); + g_config->getOption("SDL.AutoSaveState", &save_state); + if(periodic_saves && save_state < 10 && save_state >= 0){ + FCEUI_SelectState(save_state, 0); + } else { + periodic_saves = 0; + } + +#ifdef _S9XLUA_H + // load lua script if option passed + g_config->getOption("SDL.LuaScript", &s); + g_config->setOption("SDL.LuaScript", ""); + if (s != "") + { +#ifdef __linux + // Resolve absolute path to file + char fullpath[2048]; + if ( realpath( s.c_str(), fullpath ) != NULL ) + { + //printf("Fullpath: '%s'\n", fullpath ); + s.assign( fullpath ); + } +#endif + FCEU_LoadLuaCode(s.c_str()); + } +#endif + + { + int id; + g_config->getOption("SDL.NewPPU", &id); + if (id) + newppu = 1; + } + + g_config->getOption("SDL.Frameskip", &frameskip); + + return 0; +} + +int fceuWrapperClose( void ) +{ + CloseGame(); + + // exit the infrastructure + FCEUI_Kill(); + SDL_Quit(); + + return 0; +} + +/** + * Update the video, audio, and input subsystems with the provided + * video (XBuf) and audio (Buffer) information. + */ +void +FCEUD_Update(uint8 *XBuf, + int32 *Buffer, + int Count) +{ + int blitDone = 0; + extern int FCEUDnetplay; + + #ifdef CREATE_AVI + if (LoggingEnabled == 2 || (eoptions&EO_NOTHROTTLE)) + { + if(LoggingEnabled == 2) + { + int16* MonoBuf = new int16[Count]; + int n; + for(n=0; n GetWriteSound()) Count = GetWriteSound(); + + if (!mutecapture) + { + if(Count > 0 && Buffer) WriteSound(Buffer,Count); + } + } + //if (inited & 2) + // FCEUD_UpdateInput(); + if(XBuf && (inited & 4)) BlitScreen(XBuf); + + return; + } + #endif + + int ocount = Count; + // apply frame scaling to Count + Count = (int)(Count / g_fpsScale); + if (Count) + { + int32 can=GetWriteSound(); + static int uflow=0; + int32 tmpcan; + + // don't underflow when scaling fps + if(can >= GetMaxSound() && g_fpsScale==1.0) uflow=1; /* Go into massive underflow mode. */ + + if(can > Count) can=Count; + else uflow=0; + + #ifdef CREATE_AVI + if (!mutecapture) + #endif + WriteSound(Buffer,can); + + //if(uflow) puts("Underflow"); + tmpcan = GetWriteSound(); + // don't underflow when scaling fps + if (g_fpsScale>1.0 || ((tmpcan < Count*0.90) && !uflow)) + { + if (XBuf && (inited&4) && !(NoWaiting & 2)) + { + BlitScreen(XBuf); blitDone = 1; + } + Buffer+=can; + Count-=can; + if(Count) + { + if(NoWaiting) + { + can=GetWriteSound(); + if(Count>can) Count=can; + #ifdef CREATE_AVI + if (!mutecapture) + #endif + WriteSound(Buffer,Count); + } + else + { + while(Count>0) + { + #ifdef CREATE_AVI + if (!mutecapture) + #endif + WriteSound(Buffer,(Count= (Count * 1.8))) + { + if (Count > tmpcan) Count=tmpcan; + while(tmpcan > 0) + { + // printf("Overwrite: %d\n", (Count <= tmpcan)?Count : tmpcan); + #ifdef CREATE_AVI + if (!mutecapture) + #endif + WriteSound(Buffer, (Count <= tmpcan)?Count : tmpcan); + tmpcan -= Count; + } + } + } + else + { + //if (!NoWaiting && (!(eoptions&EO_NOTHROTTLE) || FCEUI_EmulationPaused())) + //{ + // while (SpeedThrottle()) + // { + // FCEUD_UpdateInput(); + // } + //} + if (XBuf && (inited&4)) + { + BlitScreen(XBuf); blitDone = 1; + } + } + if ( !blitDone ) + { + if (XBuf && (inited&4)) + { + BlitScreen(XBuf); blitDone = 1; + } + } + //FCEUD_UpdateInput(); +} + +static void DoFun(int frameskip, int periodic_saves) +{ + uint8 *gfx; + int32 *sound; + int32 ssize; + static int fskipc = 0; + //static int opause = 0; + + //TODO peroidic saves, working on it right now + if (periodic_saves && FCEUD_GetTime() % PERIODIC_SAVE_INTERVAL < 30){ + FCEUI_SaveState(NULL, false); + } +#ifdef FRAMESKIP + fskipc = (fskipc + 1) % (frameskip + 1); +#endif + + if (NoWaiting) + { + gfx = 0; + } + FCEUI_Emulate(&gfx, &sound, &ssize, fskipc); + FCEUD_Update(gfx, sound, ssize); + + //if(opause!=FCEUI_EmulationPaused()) + //{ + // opause=FCEUI_EmulationPaused(); + // SilenceSound(opause); + //} +} + +void fceuWrapperLock(void) +{ + consoleWindow->mutex->lock(); + mutexLocked = 1; +} + +bool fceuWrapperTryLock(int timeout) +{ + bool lockAcq; + + lockAcq = consoleWindow->mutex->tryLock( timeout ); + + if ( lockAcq ) + { + mutexLocked = 1; + } + return lockAcq; +} + +void fceuWrapperUnLock(void) +{ + if ( mutexLocked ) + { + consoleWindow->mutex->unlock(); + mutexLocked = 0; + } + else + { + printf("Error: Mutex is Already UnLocked\n"); + } +} + +bool fceuWrapperIsLocked(void) +{ + return mutexLocked; +} + +int fceuWrapperUpdate( void ) +{ + fceuWrapperLock(); + + if ( GameInfo && !FCEUI_EmulationPaused() ) + { + DoFun(frameskip, periodic_saves); + + fceuWrapperUnLock(); + + while ( SpeedThrottle() ) + { + // Input device processing is in main thread + // because to MAC OS X SDL2 requires it. + //FCEUD_UpdateInput(); + } + } + else + { + fceuWrapperUnLock(); + + usleep( 100000 ); + } + return 0; +} + +// 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..e3ce55a8 --- /dev/null +++ b/src/drivers/Qt/fceuWrapper.h @@ -0,0 +1,36 @@ +// fceuWrapper.h +// +#include "Qt/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); + +int fceuWrapperInit( int argc, char *argv[] ); +int fceuWrapperClose( void ); +int fceuWrapperUpdate( void ); +void fceuWrapperLock(void); +bool fceuWrapperTryLock(int timeout); +bool fceuWrapperIsLocked(void); +void fceuWrapperUnLock(void); +int fceuWrapperSoftReset(void); +int fceuWrapperHardReset(void); +int fceuWrapperTogglePause(void); +bool fceuWrapperGameLoaded(void); + diff --git a/src/drivers/Qt/fceux_git_info.h b/src/drivers/Qt/fceux_git_info.h new file mode 100644 index 00000000..fd9cdb8c --- /dev/null +++ b/src/drivers/Qt/fceux_git_info.h @@ -0,0 +1,4 @@ +// fceux_git_info.h + +const char *fceu_get_git_url(void); +const char *fceu_get_git_rev(void); diff --git a/src/drivers/Qt/icon.xpm b/src/drivers/Qt/icon.xpm new file mode 100644 index 00000000..7c817653 --- /dev/null +++ b/src/drivers/Qt/icon.xpm @@ -0,0 +1,55 @@ +/* XPM */ +static const char * icon_xpm[] = { +"32 32 20 1", +" c None", +". c #040204", +"+ c #84A284", +"@ c #C42204", +"# c #8482C4", +"$ c #FCFEFC", +"% c #848284", +"& c #648284", +"* c #646284", +"= c #444244", +"- c #A4A284", +"; c #C4A284", +"> c #C48284", +", c #A4CAF4", +"' c #244244", +") c #444204", +"! c #442204", +"~ c #446244", +"{ c #646244", +"] c #644244", +" ", +" ........ ", +" ............... ", +" ........................ ", +" ...........................+ ", +" ............@@..@@........... ", +" .#............@@............$$ ", +" .##..........@@.@.....$$%%%%$$ ", +" &...........@....@$$$$$$%%&%$$ ", +" *&...............$$$$$$$%%&%$$ ", +" =&*.......-;;>;...$$,$$$%**&.. ", +" '&&..............$$,,,%=)!~.. ", +" ~&&............-%%##%*.~'=%& ", +" *&&.....+%%****&&%%&*.&!!' ", +" **&%&***********&&&*~{'= ", +" ********=**~**~**~ ", +" *****~******] ", +" **~***]' ", +" ~]== ", +" ", +" ..... .... .... .. ..@@ @@", +" ..... .... .... .. ..@@@ @@@", +" .. .. .. .. .. @@@ @@@ ", +" .... .. .. .. .. @@@@@@ ", +" .... .. ... .. .. @@@@ ", +" .. .. ... .. .. @@@@ ", +" .. .. .. .. .. @@@@@@ ", +" .. .. .. .. .. @@@ @@@ ", +" .. .... .... .....@@@ @@@", +" .. .... .... ... @@ @@", +" ", +" "}; diff --git a/src/drivers/Qt/input.cpp b/src/drivers/Qt/input.cpp new file mode 100644 index 00000000..552f7ad8 --- /dev/null +++ b/src/drivers/Qt/input.cpp @@ -0,0 +1,2386 @@ +/* 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 "Qt/main.h" +#include "Qt/dface.h" +#include "Qt/input.h" +#include "Qt/config.h" + + +#include "Qt/sdl-video.h" +#include "Qt/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; +static int buttonConfigInProgress = 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=0, bcpj=0; + +/** + * 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 (); + + buttonConfigInProgress = 1; + + 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 (); + } + buttonConfigInProgress = 0; +} + +/** + * 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},{-1},0} +#define GPZ() {MKZ(), MKZ(), MKZ(), MKZ()} + +ButtConfig GamePadConfig[ GAMEPAD_NUM_DEVICES ][ GAMEPAD_NUM_BUTTONS ] = +{ +/* 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<ButtonNum[which] == -1) + { + return name; + } + switch (bc->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_t * text, ButtConfig * bc, int wb, int *buttonConfigStatus ) +{ + SDL_Event event; + static int32 LastAx[64][64]; + int x, y; + int timeout_ms = 10000; + + 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; + } + } + + // Purge all pending events, so that this next button press + // will be the one we want. + while (SDL_PollEvent (&event)) + { + + } + + while (1) + { + int done = 0; + + usleep(10000); + timeout_ms -= 10; + + if ( timeout_ms <= 0 ) + { + break; + } + + QCoreApplication::processEvents(); + + while (SDL_PollEvent (&event)) + { + done++; + switch (event.type) + { + case SDL_KEYDOWN: + //printf("SDL KeyDown:%i \n", event.key.keysym.sym ); + 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, -1, -1}, +{-1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, +{-1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, +{-1, -1, -1, -1, -1, -1, -1, -1, -1, -1} +}; + +// 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..d9a70118 --- /dev/null +++ b/src/drivers/Qt/input.h @@ -0,0 +1,67 @@ +#ifndef _aosdfjk02fmasf +#define _aosdfjk02fmasf + +#include + +#include "common/configSys.h" + +#define MAXBUTTCONFIG 4 + +enum { + BUTTC_KEYBOARD = 0, + BUTTC_JOYSTICK = 1, + BUTTC_MOUSE = 2 +}; +struct ButtConfig +{ + int ButtType[MAXBUTTCONFIG]; + int DeviceNum[MAXBUTTCONFIG]; + int ButtonNum[MAXBUTTCONFIG]; + uint32_t NumC; + //uint64 DeviceID[MAXBUTTCONFIG]; /* TODO */ +}; + + +extern int NoWaiting; +extern CFGSTRUCT InputConfig[]; +extern ARGPSTRUCT InputArgs[]; +extern int Hotkeys[]; +void ParseGIInput(FCEUGI *GI); +void setHotKeys(void); +int getKeyState( int k ); +int ButtonConfigBegin(); +void ButtonConfigEnd(); +void ConfigButton(char *text, ButtConfig *bc); +int DWaitButton(const uint8_t *text, ButtConfig *bc, int wb, int *buttonConfigStatus = NULL); + + +#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.cpp b/src/drivers/Qt/keyscan.cpp new file mode 100644 index 00000000..da2b4982 --- /dev/null +++ b/src/drivers/Qt/keyscan.cpp @@ -0,0 +1,985 @@ +// keyscan.cpp +// + +#include +#include + +#include "Qt/keyscan.h" + +using namespace Qt; + +SDL_Scancode convQtKey2SDLScanCode( Qt::Key q ) +{ + SDL_Scancode s = SDL_SCANCODE_UNKNOWN; + + switch (q) + { + case Key_Escape: + s = SDL_SCANCODE_ESCAPE; + break; + case Key_Tab: + case Key_Backtab: + s = SDL_SCANCODE_TAB; + break; + case Key_Backspace: + s = SDL_SCANCODE_BACKSPACE; + break; + case Key_Return: + s = SDL_SCANCODE_RETURN; + break; + case Key_Enter: + s = SDL_SCANCODE_RETURN; + break; + case Key_Insert: + s = SDL_SCANCODE_INSERT; + break; + case Key_Delete: + s = SDL_SCANCODE_DELETE; + break; + case Key_Pause: + s = SDL_SCANCODE_PAUSE; + break; + case Key_Print: + case Key_SysReq: + s = SDL_SCANCODE_PRINTSCREEN; + break; + case Key_Clear: + s = SDL_SCANCODE_CLEAR; + break; + case Key_Home: + s = SDL_SCANCODE_HOME; + break; + case Key_End: + s = SDL_SCANCODE_END; + break; + case Key_Left: + s = SDL_SCANCODE_LEFT; + break; + case Key_Up: + s = SDL_SCANCODE_UP; + break; + case Key_Right: + s = SDL_SCANCODE_RIGHT; + break; + case Key_Down: + s = SDL_SCANCODE_DOWN; + break; + case Key_PageUp: + s = SDL_SCANCODE_PAGEUP; + break; + case Key_PageDown: + s = SDL_SCANCODE_PAGEDOWN; + break; + case Key_Shift: + s = SDL_SCANCODE_LSHIFT; + break; + case Key_Control: + s = SDL_SCANCODE_LCTRL; + break; + case Key_Meta: + s = SDL_SCANCODE_LGUI; + break; + case Key_Alt: + s = SDL_SCANCODE_LALT; + break; + case Key_CapsLock: + s = SDL_SCANCODE_CAPSLOCK; + break; + case Key_NumLock: + s = SDL_SCANCODE_NUMLOCKCLEAR; + break; + case Key_ScrollLock: + s = SDL_SCANCODE_SCROLLLOCK; + break; + case Key_F1: + s = SDL_SCANCODE_F1; + break; + case Key_F2: + s = SDL_SCANCODE_F2; + break; + case Key_F3: + s = SDL_SCANCODE_F3; + break; + case Key_F4: + s = SDL_SCANCODE_F4; + break; + case Key_F5: + s = SDL_SCANCODE_F5; + break; + case Key_F6: + s = SDL_SCANCODE_F6; + break; + case Key_F7: + s = SDL_SCANCODE_F7; + break; + case Key_F8: + s = SDL_SCANCODE_F8; + break; + case Key_F9: + s = SDL_SCANCODE_F9; + break; + case Key_F10: + s = SDL_SCANCODE_F10; + break; + case Key_F11: + s = SDL_SCANCODE_F11; + break; + case Key_F12: + s = SDL_SCANCODE_F12; + break; + case Key_F13: + s = SDL_SCANCODE_F13; + break; + case Key_F14: + s = SDL_SCANCODE_F14; + break; + case Key_F15: + s = SDL_SCANCODE_F15; + break; + case Key_F16: + s = SDL_SCANCODE_F16; + break; + case Key_F17: + s = SDL_SCANCODE_F17; + break; + case Key_F18: + s = SDL_SCANCODE_F18; + break; + case Key_F19: + s = SDL_SCANCODE_F19; + break; + case Key_F20: + s = SDL_SCANCODE_F20; + break; + case Key_F21: + s = SDL_SCANCODE_F21; + break; + case Key_F22: + s = SDL_SCANCODE_F22; + break; + case Key_F23: + s = SDL_SCANCODE_F23; + break; + case Key_F24: + s = SDL_SCANCODE_F24; + break; + //case Key_F25: // F25 .. F35 only on X11 + //case Key_F26: + //case Key_F27: + //case Key_F28: + //case Key_F29: + //case Key_F30: + //case Key_F31: + //case Key_F32: + //case Key_F33: + //case Key_F34: + //case Key_F35: + // s = SDL_SCANCODE_UNKNOWN; + //break; + case Key_Super_L: + case Key_Super_R: + s = SDL_SCANCODE_UNKNOWN; + break; + case Key_Menu: + s = SDL_SCANCODE_MENU; + break; + case Key_Hyper_L: + case Key_Hyper_R: + s = SDL_SCANCODE_UNKNOWN; + break; + case Key_Help: + s = SDL_SCANCODE_HELP; + break; + case Key_Direction_L: + case Key_Direction_R: + s = SDL_SCANCODE_UNKNOWN; + break; + + case Key_Space: + //case Key_Any: + s = SDL_SCANCODE_SPACE; + break; + + case Key_Exclam: + s = SDL_SCANCODE_1; + break; + case Key_QuoteDbl: + s = SDL_SCANCODE_APOSTROPHE; + break; + case Key_NumberSign: + s = SDL_SCANCODE_3; + break; + case Key_Dollar: + s = SDL_SCANCODE_4; + break; + case Key_Percent: + s = SDL_SCANCODE_5; + break; + case Key_Ampersand: + s = SDL_SCANCODE_7; + break; + case Key_Apostrophe: + s = SDL_SCANCODE_APOSTROPHE; + break; + case Key_ParenLeft: + s = SDL_SCANCODE_9; + break; + case Key_ParenRight: + s = SDL_SCANCODE_0; + break; + case Key_Asterisk: + s = SDL_SCANCODE_8; + break; + case Key_Plus: + s = SDL_SCANCODE_EQUALS; + break; + case Key_Comma: + s = SDL_SCANCODE_COMMA; + break; + case Key_Minus: + s = SDL_SCANCODE_MINUS; + break; + case Key_Period: + s = SDL_SCANCODE_PERIOD; + break; + case Key_Slash: + s = SDL_SCANCODE_SLASH; + break; + case Key_0: + s = SDL_SCANCODE_0; + break; + case Key_1: + s = SDL_SCANCODE_1; + break; + case Key_2: + s = SDL_SCANCODE_2; + break; + case Key_3: + s = SDL_SCANCODE_3; + break; + case Key_4: + s = SDL_SCANCODE_4; + break; + case Key_5: + s = SDL_SCANCODE_5; + break; + case Key_6: + s = SDL_SCANCODE_6; + break; + case Key_7: + s = SDL_SCANCODE_7; + break; + case Key_8: + s = SDL_SCANCODE_8; + break; + case Key_9: + s = SDL_SCANCODE_9; + break; + case Key_Colon: + case Key_Semicolon: + s = SDL_SCANCODE_SEMICOLON; + break; + case Key_Less: + s = SDL_SCANCODE_COMMA; + break; + case Key_Equal: + s = SDL_SCANCODE_EQUALS; + break; + case Key_Greater: + s = SDL_SCANCODE_PERIOD; + break; + case Key_Question: + s = SDL_SCANCODE_SLASH; + break; + case Key_At: + s = SDL_SCANCODE_2; + break; + break; + case Key_A: + s = SDL_SCANCODE_A; + break; + case Key_B: + s = SDL_SCANCODE_B; + break; + case Key_C: + s = SDL_SCANCODE_C; + break; + case Key_D: + s = SDL_SCANCODE_D; + break; + case Key_E: + s = SDL_SCANCODE_E; + break; + case Key_F: + s = SDL_SCANCODE_F; + break; + case Key_G: + s = SDL_SCANCODE_G; + break; + case Key_H: + s = SDL_SCANCODE_H; + break; + case Key_I: + s = SDL_SCANCODE_I; + break; + case Key_J: + s = SDL_SCANCODE_J; + break; + case Key_K: + s = SDL_SCANCODE_K; + break; + case Key_L: + s = SDL_SCANCODE_L; + break; + case Key_M: + s = SDL_SCANCODE_M; + break; + case Key_N: + s = SDL_SCANCODE_N; + break; + case Key_O: + s = SDL_SCANCODE_O; + break; + case Key_P: + s = SDL_SCANCODE_P; + break; + case Key_Q: + s = SDL_SCANCODE_Q; + break; + case Key_R: + s = SDL_SCANCODE_R; + break; + case Key_S: + s = SDL_SCANCODE_S; + break; + case Key_T: + s = SDL_SCANCODE_T; + break; + case Key_U: + s = SDL_SCANCODE_U; + break; + case Key_V: + s = SDL_SCANCODE_V; + break; + case Key_W: + s = SDL_SCANCODE_W; + break; + case Key_X: + s = SDL_SCANCODE_X; + break; + case Key_Y: + s = SDL_SCANCODE_Y; + break; + case Key_Z: + s = SDL_SCANCODE_Z; + break; + case Key_BracketLeft: + s = SDL_SCANCODE_LEFTBRACKET; + break; + case Key_Backslash: + s = SDL_SCANCODE_BACKSLASH; + break; + case Key_BracketRight: + s = SDL_SCANCODE_RIGHTBRACKET; + break; + //case Key_AsciiCircum: + // s = SDL_SCANCODE_UNKNOWN; + //break; + case Key_Underscore: + s = SDL_SCANCODE_MINUS; + break; + case Key_QuoteLeft: + s = SDL_SCANCODE_GRAVE; + break; + case Key_BraceLeft: + s = SDL_SCANCODE_LEFTBRACKET; + break; + case Key_Bar: + s = SDL_SCANCODE_BACKSLASH; + break; + case Key_BraceRight: + s = SDL_SCANCODE_RIGHTBRACKET; + break; + case Key_AsciiTilde: + s = SDL_SCANCODE_GRAVE; + break; + + //case Key_nobreakspace: + //case Key_exclamdown: + //case Key_cent: + //case Key_sterling: + //case Key_currency: + //case Key_yen: + //case Key_brokenbar: + //case Key_section: + //case Key_diaeresis: + //case Key_copyright: + //case Key_ordfeminine: + //case Key_guillemotleft: + //case Key_notsign: + //case Key_hyphen: + //case Key_registered: + //case Key_macron: + //case Key_degree: + //case Key_plusminus: + //case Key_twosuperior: + //case Key_threesuperior: + //case Key_acute: + //case Key_mu: + //case Key_paragraph: + //case Key_periodcentered: + //case Key_cedilla: + //case Key_onesuperior: + //case Key_masculine: + //case Key_guillemotright: + //case Key_onequarter: + //case Key_onehalf: + //case Key_threequarters: + //case Key_questiondown: + //case Key_Agrave: + //case Key_Aacute: + //case Key_Acircumflex: + //case Key_Atilde: + //case Key_Adiaeresis: + //case Key_Aring: + //case Key_AE: + //case Key_Ccedilla: + //case Key_Egrave: + //case Key_Eacute: + //case Key_Ecircumflex: + //case Key_Ediaeresis: + //case Key_Igrave: + //case Key_Iacute: + //case Key_Icircumflex: + //case Key_Idiaeresis: + //case Key_ETH: + //case Key_Ntilde: + //case Key_Ograve: + //case Key_Oacute: + //case Key_Ocircumflex: + //case Key_Otilde: + //case Key_Odiaeresis: + //case Key_multiply: + //case Key_Ooblique: + //case Key_Ugrave: + //case Key_Uacute: + //case Key_Ucircumflex: + //case Key_Udiaeresis: + //case Key_Yacute: + //case Key_THORN: + //case Key_ssharp: + //case Key_division: + //case Key_ydiaeresis: + // s = SDL_SCANCODE_UNKNOWN; + //break; + default: + s = SDL_SCANCODE_UNKNOWN; + break; + } + return s; +} + +SDL_Keycode convQtKey2SDLKeyCode( Qt::Key q ) +{ + SDL_Keycode s = SDLK_UNKNOWN; + + switch (q) + { + case Key_Escape: + s = SDLK_ESCAPE; + break; + case Key_Tab: + case Key_Backtab: + s = SDLK_TAB; + break; + case Key_Backspace: + s = SDLK_BACKSPACE; + break; + case Key_Return: + s = SDLK_RETURN; + break; + case Key_Enter: + s = SDLK_KP_ENTER; + break; + case Key_Insert: + s = SDLK_INSERT; + break; + case Key_Delete: + s = SDLK_DELETE; + break; + case Key_Pause: + s = SDLK_PAUSE; + break; + case Key_Print: + s = SDLK_PRINTSCREEN; + break; + case Key_SysReq: + s = SDLK_SYSREQ; + break; + case Key_Clear: + s = SDLK_CLEAR; + break; + case Key_Home: + s = SDLK_HOME; + break; + case Key_End: + s = SDLK_END; + break; + case Key_Left: + s = SDLK_LEFT; + break; + case Key_Up: + s = SDLK_UP; + break; + case Key_Right: + s = SDLK_RIGHT; + break; + case Key_Down: + s = SDLK_DOWN; + break; + case Key_PageUp: + s = SDLK_PAGEUP; + break; + case Key_PageDown: + s = SDLK_PAGEDOWN; + break; + case Key_Shift: + s = SDLK_LSHIFT; + break; + case Key_Control: + s = SDLK_LCTRL; + break; + case Key_Meta: + s = SDLK_LGUI; + break; + case Key_Alt: + s = SDL_SCANCODE_LALT; + break; + case Key_CapsLock: + s = SDLK_LALT; + break; + case Key_NumLock: + s = SDLK_NUMLOCKCLEAR; + break; + case Key_ScrollLock: + s = SDLK_SCROLLLOCK; + break; + case Key_F1: + s = SDLK_F1; + break; + case Key_F2: + s = SDLK_F2; + break; + case Key_F3: + s = SDLK_F3; + break; + case Key_F4: + s = SDLK_F4; + break; + case Key_F5: + s = SDLK_F5; + break; + case Key_F6: + s = SDLK_F6; + break; + case Key_F7: + s = SDLK_F7; + break; + case Key_F8: + s = SDLK_F8; + break; + case Key_F9: + s = SDLK_F9; + break; + case Key_F10: + s = SDLK_F10; + break; + case Key_F11: + s = SDLK_F11; + break; + case Key_F12: + s = SDLK_F12; + break; + case Key_F13: + s = SDLK_F13; + break; + case Key_F14: + s = SDLK_F14; + break; + case Key_F15: + s = SDLK_F15; + break; + case Key_F16: + s = SDLK_F16; + break; + case Key_F17: + s = SDLK_F17; + break; + case Key_F18: + s = SDLK_F18; + break; + case Key_F19: + s = SDLK_F19; + break; + case Key_F20: + s = SDLK_F20; + break; + case Key_F21: + s = SDLK_F21; + break; + case Key_F22: + s = SDLK_F22; + break; + case Key_F23: + s = SDLK_F23; + break; + case Key_F24: + s = SDLK_F24; + break; + //case Key_F25: // F25 .. F35 only on X11 + //case Key_F26: + //case Key_F27: + //case Key_F28: + //case Key_F29: + //case Key_F30: + //case Key_F31: + //case Key_F32: + //case Key_F33: + //case Key_F34: + //case Key_F35: + // s = SDL_SCANCODE_UNKNOWN; + //break; + case Key_Super_L: + case Key_Super_R: + s = SDLK_UNKNOWN; + break; + case Key_Menu: + s = SDLK_MENU; + break; + case Key_Hyper_L: + case Key_Hyper_R: + s = SDLK_UNKNOWN; + break; + case Key_Help: + s = SDLK_HELP; + break; + case Key_Direction_L: + case Key_Direction_R: + s = SDLK_UNKNOWN; + break; + + case Key_Space: + //case Key_Any: + s = SDLK_SPACE; + break; + + case Key_Exclam: + s = SDLK_EXCLAIM; + break; + case Key_QuoteDbl: + s = SDLK_QUOTEDBL; + break; + case Key_NumberSign: + s = SDLK_HASH; + break; + case Key_Dollar: + s = SDLK_DOLLAR; + break; + case Key_Percent: + s = SDLK_PERCENT; + break; + case Key_Ampersand: + s = SDLK_AMPERSAND; + break; + case Key_Apostrophe: + s = SDLK_QUOTE; + break; + case Key_ParenLeft: + s = SDLK_LEFTPAREN; + break; + case Key_ParenRight: + s = SDLK_RIGHTPAREN; + break; + case Key_Asterisk: + s = SDLK_ASTERISK; + break; + case Key_Plus: + s = SDLK_PLUS; + break; + case Key_Comma: + s = SDLK_COMMA; + break; + case Key_Minus: + s = SDLK_MINUS; + break; + case Key_Period: + s = SDLK_PERIOD; + break; + case Key_Slash: + s = SDLK_SLASH; + break; + case Key_0: + s = SDLK_0; + break; + case Key_1: + s = SDLK_1; + break; + case Key_2: + s = SDLK_2; + break; + case Key_3: + s = SDLK_3; + break; + case Key_4: + s = SDLK_4; + break; + case Key_5: + s = SDLK_5; + break; + case Key_6: + s = SDLK_6; + break; + case Key_7: + s = SDLK_7; + break; + case Key_8: + s = SDLK_8; + break; + case Key_9: + s = SDLK_9; + break; + case Key_Colon: + s = SDLK_COLON; + break; + case Key_Semicolon: + s = SDLK_SEMICOLON; + break; + case Key_Less: + s = SDLK_LESS; + break; + case Key_Equal: + s = SDLK_EQUALS; + break; + case Key_Greater: + s = SDLK_GREATER; + break; + case Key_Question: + s = SDLK_QUESTION; + break; + case Key_At: + s = SDLK_AT; + break; + break; + case Key_A: + s = SDLK_a; + break; + case Key_B: + s = SDLK_b; + break; + case Key_C: + s = SDLK_c; + break; + case Key_D: + s = SDLK_d; + break; + case Key_E: + s = SDLK_e; + break; + case Key_F: + s = SDLK_f; + break; + case Key_G: + s = SDLK_g; + break; + case Key_H: + s = SDLK_h; + break; + case Key_I: + s = SDLK_i; + break; + case Key_J: + s = SDLK_j; + break; + case Key_K: + s = SDLK_k; + break; + case Key_L: + s = SDLK_l; + break; + case Key_M: + s = SDLK_m; + break; + case Key_N: + s = SDLK_n; + break; + case Key_O: + s = SDLK_o; + break; + case Key_P: + s = SDLK_p; + break; + case Key_Q: + s = SDLK_q; + break; + case Key_R: + s = SDLK_r; + break; + case Key_S: + s = SDLK_s; + break; + case Key_T: + s = SDLK_t; + break; + case Key_U: + s = SDLK_u; + break; + case Key_V: + s = SDLK_v; + break; + case Key_W: + s = SDLK_w; + break; + case Key_X: + s = SDLK_x; + break; + case Key_Y: + s = SDLK_y; + break; + case Key_Z: + s = SDLK_z; + break; + case Key_BracketLeft: + s = SDLK_LEFTBRACKET; + break; + case Key_Backslash: + s = SDLK_BACKSLASH; + break; + case Key_BracketRight: + s = SDLK_RIGHTBRACKET; + break; + //case Key_AsciiCircum: + // s = SDLK_CARET; + //break; + case Key_Underscore: + s = SDLK_UNDERSCORE; + break; + case Key_QuoteLeft: + s = SDLK_BACKQUOTE; + break; + case Key_BraceLeft: + s = SDLK_LEFTBRACKET; + break; + case Key_Bar: + s = SDLK_BACKSLASH; + break; + case Key_BraceRight: + s = SDLK_RIGHTBRACKET; + break; + case Key_AsciiTilde: + s = SDLK_BACKQUOTE; + break; + + //case Key_nobreakspace: + //case Key_exclamdown: + //case Key_cent: + //case Key_sterling: + //case Key_currency: + //case Key_yen: + //case Key_brokenbar: + //case Key_section: + //case Key_diaeresis: + //case Key_copyright: + //case Key_ordfeminine: + //case Key_guillemotleft: + //case Key_notsign: + //case Key_hyphen: + //case Key_registered: + //case Key_macron: + //case Key_degree: + //case Key_plusminus: + //case Key_twosuperior: + //case Key_threesuperior: + //case Key_acute: + //case Key_mu: + //case Key_paragraph: + //case Key_periodcentered: + //case Key_cedilla: + //case Key_onesuperior: + //case Key_masculine: + //case Key_guillemotright: + //case Key_onequarter: + //case Key_onehalf: + //case Key_threequarters: + //case Key_questiondown: + //case Key_Agrave: + //case Key_Aacute: + //case Key_Acircumflex: + //case Key_Atilde: + //case Key_Adiaeresis: + //case Key_Aring: + //case Key_AE: + //case Key_Ccedilla: + //case Key_Egrave: + //case Key_Eacute: + //case Key_Ecircumflex: + //case Key_Ediaeresis: + //case Key_Igrave: + //case Key_Iacute: + //case Key_Icircumflex: + //case Key_Idiaeresis: + //case Key_ETH: + //case Key_Ntilde: + //case Key_Ograve: + //case Key_Oacute: + //case Key_Ocircumflex: + //case Key_Otilde: + //case Key_Odiaeresis: + //case Key_multiply: + //case Key_Ooblique: + //case Key_Ugrave: + //case Key_Uacute: + //case Key_Ucircumflex: + //case Key_Udiaeresis: + //case Key_Yacute: + //case Key_THORN: + //case Key_ssharp: + //case Key_division: + //case Key_ydiaeresis: + // s = SDL_SCANCODE_UNKNOWN; + //break; + default: + s = SDLK_UNKNOWN; + break; + } + return s; +} + +int pushKeyEvent( QKeyEvent *event, int pressDown ) +{ + SDL_Event sdlev; + + if ( pressDown ) + { + sdlev.type = SDL_KEYDOWN; + sdlev.key.state = SDL_PRESSED; + } + else + { + sdlev.type = SDL_KEYUP; + sdlev.key.state = SDL_RELEASED; + } + + sdlev.key.keysym.sym = convQtKey2SDLKeyCode( (Qt::Key)event->key() ); + + sdlev.key.keysym.scancode = SDL_GetScancodeFromKey( sdlev.key.keysym.sym ); + + sdlev.key.keysym.mod = 0; + sdlev.key.repeat = 0; + + if (sdlev.key.keysym.scancode != SDL_SCANCODE_UNKNOWN) + { + SDL_PushEvent (&sdlev); + } + + return 0; +} diff --git a/src/drivers/Qt/keyscan.h b/src/drivers/Qt/keyscan.h new file mode 100644 index 00000000..2499709f --- /dev/null +++ b/src/drivers/Qt/keyscan.h @@ -0,0 +1,54 @@ +#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 + +#include +#include +#include + +SDL_Keycode convQtKey2SDLKeyCode( Qt::Key q ); + +SDL_Scancode convQtKey2SDLScanCode( Qt::Key q ); + +int pushKeyEvent( QKeyEvent *event, int pressDown ); diff --git a/src/drivers/Qt/main.cpp b/src/drivers/Qt/main.cpp new file mode 100644 index 00000000..0dc688c0 --- /dev/null +++ b/src/drivers/Qt/main.cpp @@ -0,0 +1,30 @@ +#include + +#include "Qt/ConsoleWindow.h" +#include "Qt/fceuWrapper.h" + +consoleWin_t *consoleWindow = NULL; + +int main( int argc, char *argv[] ) +{ + int retval; + QApplication app(argc, argv); + + fceuWrapperInit( argc, argv ); + + consoleWindow = new consoleWin_t(); + + consoleWindow->resize( 512, 512 ); + consoleWindow->show(); + + consoleWindow->viewport->init(); + + retval = app.exec(); + + //printf("App Return: %i \n", retval ); + + delete consoleWindow; + + return retval; +} + diff --git a/src/drivers/Qt/main.h b/src/drivers/Qt/main.h new file mode 100644 index 00000000..35d5026d --- /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/nes_shm.cpp b/src/drivers/Qt/nes_shm.cpp new file mode 100644 index 00000000..59d1e948 --- /dev/null +++ b/src/drivers/Qt/nes_shm.cpp @@ -0,0 +1,54 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "Qt/nes_shm.h" + +nes_shm_t *nes_shm = NULL; + +//************************************************************************ +nes_shm_t *open_nes_shm(void) +{ + int shmId; + nes_shm_t *vaddr; + struct shmid_ds ds; + + shmId = shmget( IPC_PRIVATE, sizeof(struct nes_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 = (nes_shm_t*)shmat( shmId, NULL, 0); + + if ( vaddr == (nes_shm_t*)-1 ) + { + perror("Error: NES shmat Failed:"); + return NULL; + } + memset( vaddr, 0, sizeof(struct nes_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/nes_shm.h b/src/drivers/Qt/nes_shm.h new file mode 100644 index 00000000..0b63998d --- /dev/null +++ b/src/drivers/Qt/nes_shm.h @@ -0,0 +1,86 @@ +// nes_shm.h +// + +#ifndef __NES_SHM_H__ +#define __NES_SHM_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 +#define NES_AUDIO_BUFLEN 480000 + +struct nes_shm_t +{ + int pid; + int run; + uint32_t render_count; + uint32_t blit_count; + + int ncol; + int nrow; + int pitch; + + char runEmulator; + char blitUpdated; + + // 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) ); + } + + struct sndBuf_t + { + int head; + int tail; + int16_t data[NES_AUDIO_BUFLEN]; + unsigned int starveCounter; + } sndBuf; + + void push_sound_sample( int16_t sample ) + { + sndBuf.data[ sndBuf.head ] = sample; + sndBuf.head = (sndBuf.head + 1) % NES_AUDIO_BUFLEN; + } +}; + +extern nes_shm_t *nes_shm; + +nes_shm_t *open_nes_shm(void); + +#endif diff --git a/src/drivers/Qt/sdl-joystick.cpp b/src/drivers/Qt/sdl-joystick.cpp new file mode 100644 index 00000000..71148b2e --- /dev/null +++ b/src/drivers/Qt/sdl-joystick.cpp @@ -0,0 +1,127 @@ +/* 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 "Qt/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] == -1) + { + continue; + } + 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..28c263ba --- /dev/null +++ b/src/drivers/Qt/sdl-sound.cpp @@ -0,0 +1,297 @@ +/* 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 "nes_shm.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) +{ + char bufStarveDetected = 0; + static int16_t sample = 0; + 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 { + // Retain last known sample value, helps avoid clicking + // noise when sound system is starved of audio data. + //sample = 0; + bufStarveDetected = 1; + nes_shm->sndBuf.starveCounter++; + } + + nes_shm->push_sound_sample( sample ); + + *tmps = sample; + tmps++; + len--; + } + if ( bufStarveDetected ) + { + //printf("Starve:%u\n", nes_shm->sndBuf.starveCounter ); + } +} + +/** + * 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..1fba8173 --- /dev/null +++ b/src/drivers/Qt/sdl-throttle.cpp @@ -0,0 +1,169 @@ +/// \file +/// \brief Handles emulation speed throttling using the SDL timing functions. + +#include "Qt/sdl.h" +#include "Qt/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 double desired_frametime = (1.0 / 60.099823); +static int InFrame = 0; +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() +{ + double hz; + int32_t fps = FCEUI_GetDesiredFPS(); // Do >> 24 to get in Hz + int32_t T; + + hz = ( ((double)fps) / 16777216.0 ); + + desired_frametime = 1.0 / ( hz * g_fpsScale ); + + T = (int32_t)( desired_frametime * 1000.0 ); + + if ( T < 0 ) T = 1; + + //printf("FrameTime: %llu %llu %f %lf \n", fps, fps >> 24, hz, desired_frametime ); + + 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..003f8dcd --- /dev/null +++ b/src/drivers/Qt/sdl-video.cpp @@ -0,0 +1,473 @@ +/* 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 "Qt/sdl.h" +#include "Qt/nes_shm.h" +#include "common/vidblit.h" +#include "../../fceu.h" +#include "../../version.h" +#include "../../video.h" + +#include "utils/memory.h" + +//#include "sdl-icon.h" +#include "Qt/dface.h" + +#include "common/configSys.h" +#include "Qt/sdl-video.h" +#include "Qt/fceuWrapper.h" + +#ifdef CREATE_AVI +#include "../videolog/nesvideos-piece.h" +#endif + +#include +#include +#include + +#if __BYTE_ORDER == __LITTLE_ENDIAN +#define LSB_FIRST +#endif + +// 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 ( nes_shm != NULL ) + { + nes_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 = 0x00FF0000; + gmask = 0x0000FF00; + bmask = 0x000000FF; +#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(); + + // flip the fullscreen flag + g_config->setOption("SDL.Fullscreen", !s_fullscreen); + + // TODO Call method to make full Screen + + // 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(){} + +static int testPattern = 0; + +static void WriteTestPattern(void) +{ + int i, j, k; + + k=0; + for (i=0; ipixbuf[k] = 0xffffffff; k++; + } + } +} +/** + * 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*)nes_shm->pixbuf; + w = GL_NES_WIDTH; + h = GL_NES_HEIGHT; + pitch = w*4; + + nes_shm->ncol = NWIDTH; + nes_shm->nrow = s_tlines; + nes_shm->pitch = pitch; + + if ( dest == NULL ) return; + + if ( testPattern ) + { + WriteTestPattern(); + } + else + { + Blit8ToHigh(XBuf + NOFFSET, dest, NWIDTH, s_tlines, pitch, 1, 1); + } + nes_shm->blitUpdated = 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..82870040 --- /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 "Qt/main.h" +#include "Qt/dface.h" +#include "Qt/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..9c538d71 --- /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 "Qt/main.h" +//#include "Qt/input.h" +//#include "Qt/dface.h" +#include "Qt/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/drivers/common/cheat.cpp b/src/drivers/common/cheat.cpp index b03edad9..f985876e 100644 --- a/src/drivers/common/cheat.cpp +++ b/src/drivers/common/cheat.cpp @@ -176,7 +176,7 @@ int AddToList(char *text, uint32 id) **/ typedef struct MENU { - char *text; + const char *text; void *action; int type; // 0 for menu, 1 for function. } MENU; @@ -392,7 +392,7 @@ static void ShowRes(void) } } -static int ShowShortList(char *moe[], int n, int def) +static int ShowShortList(const char *moe[], int n, int def) { int x,c; int baa; //mbg merge 7/17/06 made to normal int @@ -430,7 +430,7 @@ static void DoSearch(void) { static int v1=0,v2=0; static int method=0; - char *m[9]={"O==V1 && C==V2", + const char *m[9]={"O==V1 && C==V2", "O==V1 && |O-C|==V2", "|O-C|==V2", "O!=C", diff --git a/src/drivers/sdl/config.cpp b/src/drivers/sdl/config.cpp index 9774e0d0..4856cbb2 100644 --- a/src/drivers/sdl/config.cpp +++ b/src/drivers/sdl/config.cpp @@ -102,7 +102,7 @@ LoadCPalette(const std::string &file) static void CreateDirs(const std::string &dir) { - char *subs[8]={"fcs","snaps","gameinfo","sav","cheats","movies","cfg.d"}; + const char *subs[8]={"fcs","snaps","gameinfo","sav","cheats","movies","cfg.d"}; std::string subdir; int x; diff --git a/src/drivers/sdl/input.cpp b/src/drivers/sdl/input.cpp index f4246e96..9e7280c9 100644 --- a/src/drivers/sdl/input.cpp +++ b/src/drivers/sdl/input.cpp @@ -1808,7 +1808,7 @@ void ConfigDevice (int which, int arg) char buf[256]; int x; std::string prefix; - char *str[10] = + const char *str[10] = { "A", "B", "SELECT", "START", "UP", "DOWN", "LEFT", "RIGHT", "Rapid A", "Rapid B" }; diff --git a/src/drivers/sdl/sdl.cpp b/src/drivers/sdl/sdl.cpp index fb421832..dd3d1c83 100644 --- a/src/drivers/sdl/sdl.cpp +++ b/src/drivers/sdl/sdl.cpp @@ -493,12 +493,12 @@ FILE *FCEUD_UTF8fopen(const char *fn, const char *mode) return(fopen(fn,mode)); } -static char *s_linuxCompilerString = "g++ " __VERSION__; +static const char *s_linuxCompilerString = "g++ " __VERSION__; /** * Returns the compiler string. */ const char *FCEUD_GetCompilerString() { - return (const char *)s_linuxCompilerString; + return s_linuxCompilerString; } /** @@ -590,7 +590,7 @@ int main(int argc, char *argv[]) else if(strcmp(argv[i], "--nogui") == 0) { noGui = 1; - argv[i] = ""; + //argv[i] = ""; } #endif } diff --git a/src/drivers/sdl/unix-netplay.cpp b/src/drivers/sdl/unix-netplay.cpp index 66f8a687..1150fcdc 100644 --- a/src/drivers/sdl/unix-netplay.cpp +++ b/src/drivers/sdl/unix-netplay.cpp @@ -117,7 +117,7 @@ FCEUD_NetworkConnect(void) TSocket = socket(AF_INET, SOCK_STREAM, 0); if(TSocket < 0) { - char* s = "Error creating stream socket."; + const char* s = "Error creating stream socket."; puts(s); FCEU_DispMessage(s,0); FCEUD_NetworkClose(); @@ -252,9 +252,14 @@ FCEUD_SendData(void *data, if(!error && check) { char buf[1024]; char *f; - fgets(buf, 1024, stdin); - if((f=strrchr(buf,'\n'))) { - *f = 0; + + buf[0] = 0; + + if ( fgets(buf, 1024, stdin) ) + { + if((f=strrchr(buf,'\n'))) { + *f = 0; + } } FCEUI_NetplayText((uint8 *)buf); } diff --git a/src/drivers/win/guiconfig.cpp b/src/drivers/win/guiconfig.cpp index 93c19ee0..2e67ac9b 100644 --- a/src/drivers/win/guiconfig.cpp +++ b/src/drivers/win/guiconfig.cpp @@ -85,7 +85,7 @@ void CloseGuiDialog(HWND hwndDlg) " manifestVersion=\"1.0\">\n" "\n" "FCEUX\n" diff --git a/src/drivers/win/main.cpp b/src/drivers/win/main.cpp index 9963fdca..802c6ba1 100644 --- a/src/drivers/win/main.cpp +++ b/src/drivers/win/main.cpp @@ -112,6 +112,15 @@ extern bool taseditorEnableAcceleratorKeys; #define __COMPILER__STRING__ "unknown" #endif +// 64-bit build requires manifest to use common controls 6 (style adapts to windows version) +#pragma comment(linker, \ + "\"/manifestdependency:type='win32' "\ + "name='Microsoft.Windows.Common-Controls' "\ + "version='6.0.0.0' "\ + "processorArchitecture='*' "\ + "publicKeyToken='6595b64144ccf1df' "\ + "language='*'\"") + // External functions extern std::string cfgFile; //Contains the filename of the config file used. extern bool turbo; //Is game in turbo mode? diff --git a/src/drivers/win/mapinput.cpp b/src/drivers/win/mapinput.cpp index aca19ad1..662fa969 100644 --- a/src/drivers/win/mapinput.cpp +++ b/src/drivers/win/mapinput.cpp @@ -543,7 +543,7 @@ void PopulateMappingDisplay(HWND hwndDlg) lvi.mask = LVIF_TEXT; lvi.iItem = idx; lvi.iSubItem = 1; - lvi.pszText = FCEUI_CommandTable[i].name; + lvi.pszText = (char*)FCEUI_CommandTable[i].name; SendMessage(hwndListView, LVM_SETITEM, (WPARAM)0, (LPARAM)&lvi); diff --git a/src/drivers/win/ram_search.cpp b/src/drivers/win/ram_search.cpp index ae045ce7..03440fb3 100644 --- a/src/drivers/win/ram_search.cpp +++ b/src/drivers/win/ram_search.cpp @@ -1538,10 +1538,10 @@ INT_PTR CALLBACK RamSearchProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lPara SendDlgItemMessage(hDlg, IDC_EDIT_COMPAREADDRESS, EM_SETLIMITTEXT, 4, 0); - DefaultEditCtrlProc = (WNDPROC)SetWindowLongPtr(GetDlgItem(hDlg, IDC_EDIT_DIFFBY), GWL_WNDPROC, (LONG)FilterEditCtrlProc); - SetWindowLongPtr(GetDlgItem(hDlg, IDC_EDIT_MODBY), GWL_WNDPROC, (LONG)FilterEditCtrlProc); - SetWindowLongPtr(GetDlgItem(hDlg, IDC_EDIT_COMPAREVALUE), GWL_WNDPROC, (LONG)FilterEditCtrlProc); - SetWindowLongPtr(GetDlgItem(hDlg, IDC_EDIT_COMPAREADDRESS), GWL_WNDPROC, (LONG)FilterEditCtrlProc); + DefaultEditCtrlProc = (WNDPROC)SetWindowLongPtr(GetDlgItem(hDlg, IDC_EDIT_DIFFBY), GWLP_WNDPROC, (LONG_PTR)FilterEditCtrlProc); + SetWindowLongPtr(GetDlgItem(hDlg, IDC_EDIT_MODBY), GWLP_WNDPROC, (LONG_PTR)FilterEditCtrlProc); + SetWindowLongPtr(GetDlgItem(hDlg, IDC_EDIT_COMPAREVALUE), GWLP_WNDPROC, (LONG_PTR)FilterEditCtrlProc); + SetWindowLongPtr(GetDlgItem(hDlg, IDC_EDIT_COMPAREADDRESS), GWLP_WNDPROC, (LONG_PTR)FilterEditCtrlProc); return true; } diff --git a/src/drivers/win/ramwatch.cpp b/src/drivers/win/ramwatch.cpp index 0a885b79..602e117a 100644 --- a/src/drivers/win/ramwatch.cpp +++ b/src/drivers/win/ramwatch.cpp @@ -912,7 +912,7 @@ INT_PTR CALLBACK EditWatchProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lPara } // limit the text - DefaultEditCtrlProc = (WNDPROC)SetWindowLongPtr(GetDlgItem(hDlg, addrCtrlID), GWL_WNDPROC, (LONG)FilterEditCtrlProc); + DefaultEditCtrlProc = (WNDPROC)SetWindowLongPtr(GetDlgItem(hDlg, addrCtrlID), GWLP_WNDPROC, (LONG_PTR)FilterEditCtrlProc); SetWindowText(hDlg, title); } diff --git a/src/drivers/win/taseditor/taseditor_project.cpp b/src/drivers/win/taseditor/taseditor_project.cpp index c3b09fa1..4baad00b 100644 --- a/src/drivers/win/taseditor/taseditor_project.cpp +++ b/src/drivers/win/taseditor/taseditor_project.cpp @@ -35,7 +35,7 @@ extern SPLICER splicer; extern FCEUGI *GameInfo; -extern void FCEU_PrintError(char *format, ...); +extern void FCEU_PrintError(const char *format, ...); extern bool saveProject(bool save_compact = false); extern bool saveProjectAs(bool save_compact = false); extern int getInputType(MovieData& md); diff --git a/src/fceu.cpp b/src/fceu.cpp index f97595d4..96aa9a5d 100644 --- a/src/fceu.cpp +++ b/src/fceu.cpp @@ -75,8 +75,12 @@ extern void RefreshThrottleFPS(); #include "drivers/win/memwatch.h" #include "drivers/win/tracer.h" #else +#ifdef __QT_DRIVER__ +#include "drivers/Qt/sdl.h" +#else #include "drivers/sdl/sdl.h" #endif +#endif #include #include @@ -980,7 +984,8 @@ void FCEU_ResetVidSys(void) { FCEUS FSettings; -void FCEU_printf(char *format, ...) { +void FCEU_printf(const char *format, ...) +{ char temp[2048]; va_list ap; @@ -999,7 +1004,8 @@ void FCEU_printf(char *format, ...) { va_end(ap); } -void FCEU_PrintError(char *format, ...) { +void FCEU_PrintError(const char *format, ...) +{ char temp[2048]; va_list ap; @@ -1048,38 +1054,34 @@ void FCEUI_SetRegion(int region, int notify) { normalscanlines = 240; pal_emulation = 0; dendy = 0; -// until it's fixed on sdl. see issue #740 -#ifdef WIN32 + if (notify) { FCEU_DispMessage("NTSC mode set", 0); FCEUI_printf("NTSC mode set"); } -#endif break; case 1: // PAL normalscanlines = 240; pal_emulation = 1; dendy = 0; -#ifdef WIN32 + if (notify) { FCEU_DispMessage("PAL mode set", 0); FCEUI_printf("PAL mode set"); } -#endif break; case 2: // Dendy normalscanlines = 290; pal_emulation = 0; dendy = 1; -#ifdef WIN32 + if (notify) { FCEU_DispMessage("Dendy mode set", 0); FCEUI_printf("Dendy mode set"); } -#endif break; } normalscanlines += newppu; diff --git a/src/fceu.h b/src/fceu.h index a15da070..a9075f4f 100644 --- a/src/fceu.h +++ b/src/fceu.h @@ -133,10 +133,10 @@ extern FCEUS FSettings; bool CheckFileExists(const char* filename); //Receives a filename (fullpath) and checks to see if that file exists -void FCEU_PrintError(char *format, ...); -void FCEU_printf(char *format, ...); -void FCEU_DispMessage(char *format, int disppos, ...); -void FCEU_DispMessageOnMovie(char *format, ...); +void FCEU_PrintError(const char *format, ...); +void FCEU_printf(const char *format, ...); +void FCEU_DispMessage(const char *format, int disppos, ...); +void FCEU_DispMessageOnMovie(const char *format, ...); void FCEU_TogglePPU(); void SetNESDeemph_OldHacky(uint8 d, int force); diff --git a/src/file.cpp b/src/file.cpp index dfbba02e..f7f58cbd 100644 --- a/src/file.cpp +++ b/src/file.cpp @@ -33,7 +33,11 @@ #include "utils/memory.h" #include "utils/md5.h" #ifdef _SYSTEM_MINIZIP +#ifdef __linux #include +#else // Apple Most Likely +#include +#endif #else #include "utils/unzip.h" #endif @@ -260,7 +264,7 @@ zpfail: return 0; } -FCEUFILE * FCEU_fopen(const char *path, const char *ipsfn, char *mode, char *ext, int index, const char** extensions, int* userCancel) +FCEUFILE * FCEU_fopen(const char *path, const char *ipsfn, const char *mode, char *ext, int index, const char** extensions, int* userCancel) { FILE *ipsfile=0; FCEUFILE *fceufp=0; diff --git a/src/file.h b/src/file.h index f5dcf426..84235f70 100644 --- a/src/file.h +++ b/src/file.h @@ -122,7 +122,7 @@ struct ArchiveScanRecord }; -FCEUFILE *FCEU_fopen(const char *path, const char *ipsfn, char *mode, char *ext, int index=-1, const char** extensions = 0, int* userCancel = 0); +FCEUFILE *FCEU_fopen(const char *path, const char *ipsfn, const char *mode, char *ext, int index=-1, const char** extensions = 0, int* userCancel = 0); bool FCEU_isFileInArchive(const char *path); int FCEU_fclose(FCEUFILE*); uint64 FCEU_fread(void *ptr, size_t size, size_t nmemb, FCEUFILE*); diff --git a/src/ines.cpp b/src/ines.cpp index 48f00b61..1b75ae07 100644 --- a/src/ines.cpp +++ b/src/ines.cpp @@ -233,7 +233,7 @@ static void SetInput(void) { struct BADINF { uint64 md5partial; - char *name; + const char *name; uint32 type; }; @@ -417,7 +417,7 @@ static void CheckHInfo(void) { if (tofix & 1) sprintf(gigastr + strlen(gigastr), "The mapper number should be set to %d. ", MapperNo); if (tofix & 2) { - char *mstr[3] = { "Horizontal", "Vertical", "Four-screen" }; + const char *mstr[3] = { "Horizontal", "Vertical", "Four-screen" }; sprintf(gigastr + strlen(gigastr), "Mirroring should be set to \"%s\". ", mstr[Mirroring & 3]); } if (tofix & 4) @@ -839,7 +839,7 @@ int iNESLoad(const char *name, FCEUFILE *fp, int OverwriteVidMode) { FCEU_printf("\n"); } - char* mappername = "Not Listed"; + const char* mappername = "Not Listed"; for (int mappertest = 0; mappertest < (sizeof bmap / sizeof bmap[0]) - 1; mappertest++) { if (bmap[mappertest].number == MapperNo) { diff --git a/src/ines.h b/src/ines.h index f82f7a86..6ad2657b 100644 --- a/src/ines.h +++ b/src/ines.h @@ -270,7 +270,7 @@ void Mapper254_Init(CartInfo *); void Mapper406_Init(CartInfo *); typedef struct { - char *name; + const char *name; int32 number; void (*init)(CartInfo *); } BMAPPINGLocal; diff --git a/src/input.h b/src/input.h index b3c4199a..d2eb2053 100644 --- a/src/input.h +++ b/src/input.h @@ -295,7 +295,7 @@ struct EMUCMDTABLE EMUCMDFN* fn_on; EMUCMDFN* fn_off; int state; - char* name; + const char* name; int flags; //EMUCMDFLAG }; diff --git a/src/lua-engine.cpp b/src/lua-engine.cpp index 76f99cb3..645eaf31 100644 --- a/src/lua-engine.cpp +++ b/src/lua-engine.cpp @@ -515,6 +515,7 @@ static int emu_getdir(lua_State *L) { return 1; #endif + return 0; } @@ -545,6 +546,7 @@ static int emu_loadrom(lua_State *L) { return 1; } #endif + return 1; } @@ -5227,7 +5229,7 @@ static int doPopup(lua_State *L, const char* deftype, const char* deficon) { return 1; #else - char *t; + const char *t; #ifdef __linux int pid; // appease compiler @@ -5285,9 +5287,9 @@ static int doPopup(lua_State *L, const char* deftype, const char* deficon) { // I'm gonna be dead in a matter of microseconds anyways, so wasted memory doesn't matter to me. // Go ahead and abuse strdup. - char * parameters[] = {"xmessage", "-buttons", t, strdup(str), NULL}; + const char * parameters[] = {"xmessage", "-buttons", t, strdup(str), NULL}; - execvp("xmessage", parameters); + execvp("xmessage", (char* const*)parameters); // Aw shitty perror("exec xmessage"); diff --git a/src/movie.cpp b/src/movie.cpp index 4ba7e29c..0a33f5f0 100644 --- a/src/movie.cpp +++ b/src/movie.cpp @@ -2000,7 +2000,7 @@ void ProcessSubtitles(void) } } -void FCEU_DisplaySubtitles(char *format, ...) +void FCEU_DisplaySubtitles(const char *format, ...) { va_list ap; diff --git a/src/movie.h b/src/movie.h index 0824db17..10b7979a 100644 --- a/src/movie.h +++ b/src/movie.h @@ -309,7 +309,7 @@ void FCEUI_ToggleInputDisplay(void); void LoadSubtitles(MovieData &); void ProcessSubtitles(void); -void FCEU_DisplaySubtitles(char *format, ...); +void FCEU_DisplaySubtitles(const char *format, ...); void poweron(bool shouldDisableBatteryLoading); diff --git a/src/nsf.cpp b/src/nsf.cpp index 453e4fa9..129e045d 100644 --- a/src/nsf.cpp +++ b/src/nsf.cpp @@ -262,7 +262,7 @@ int NSFLoad(const char *name, FCEUFILE *fp) FCEU_printf(" Name: %s\n Artist: %s\n Copyright: %s\n\n",NSFHeader.SongName,NSFHeader.Artist,NSFHeader.Copyright); if(NSFHeader.SoundChip) { - static char *tab[6]={"Konami VRCVI","Konami VRCVII","Nintendo FDS","Nintendo MMC5","Namco 106","Sunsoft FME-07"}; + static const char *tab[6]={"Konami VRCVI","Konami VRCVII","Nintendo FDS","Nintendo MMC5","Namco 106","Sunsoft FME-07"}; for(x=0;x<6;x++) if(NSFHeader.SoundChip&(1<vidsys = GIV_NTSC; FCEUI_SetVidSystem(0); diff --git a/src/utils/xstring.cpp b/src/utils/xstring.cpp index 831aebd9..8f8b66d3 100644 --- a/src/utils/xstring.cpp +++ b/src/utils/xstring.cpp @@ -157,7 +157,7 @@ int chr_replace(char *str, char search, char replace) { ///Replaces all instances of 'search' with 'replace' ///Returns number of sub-strings modified, or -1 on error -int str_replace(char *str, char *search, char *replace) { +int str_replace(char *str, const char *search, const char *replace) { unsigned int i=0,j=0; //mbg merge 7/17/06 changed to unsigned int int searchlen,replacelen; char *astr; diff --git a/src/utils/xstring.h b/src/utils/xstring.h index b42aec12..9d860486 100644 --- a/src/utils/xstring.h +++ b/src/utils/xstring.h @@ -43,7 +43,7 @@ int str_ltrim(char *str, int flags); int str_rtrim(char *str, int flags); int str_strip(char *str, int flags); int chr_replace(char *str, char search, char replace); -int str_replace(char *str, char *search, char *replace); +int str_replace(char *str, const char *search, const char *replace); int HexStringToBytesLength(const std::string& str); int Base64StringToBytesLength(const std::string& str); @@ -129,4 +129,4 @@ std::string wcstombs(std::wstring str); std::string getExtension(const char* input); std::string StripExtension(std::string filename); -std::string StripPath(std::string filename); \ No newline at end of file +std::string StripPath(std::string filename); diff --git a/src/video.cpp b/src/video.cpp index d9654c96..3c43d7bd 100644 --- a/src/video.cpp +++ b/src/video.cpp @@ -398,7 +398,7 @@ void snapAVI() FCEUI_AviVideoUpdate(XBuf); } -void FCEU_DispMessageOnMovie(char *format, ...) +void FCEU_DispMessageOnMovie(const char *format, ...) { va_list ap; @@ -414,7 +414,7 @@ void FCEU_DispMessageOnMovie(char *format, ...) guiMessage.howlong = 0; } -void FCEU_DispMessage(char *format, int disppos=0, ...) +void FCEU_DispMessage(const char *format, int disppos=0, ...) { va_list ap; @@ -455,7 +455,7 @@ void FCEU_ResetMessages() } -static int WritePNGChunk(FILE *fp, uint32 size, char *type, uint8 *data) +static int WritePNGChunk(FILE *fp, uint32 size, const char *type, uint8 *data) { uint32 crc; diff --git a/src/vsuni.cpp b/src/vsuni.cpp index 26e6ab62..c2e64766 100644 --- a/src/vsuni.cpp +++ b/src/vsuni.cpp @@ -35,7 +35,7 @@ #define IOPTION_PREDIP 0x10 typedef struct { - char *name; + const char *name; uint64 md5partial; int mapper; int mirroring; diff --git a/vc/vc14_fceux.vcxproj b/vc/vc14_fceux.vcxproj index c56b0458..54d4ed15 100644 --- a/vc/vc14_fceux.vcxproj +++ b/vc/vc14_fceux.vcxproj @@ -138,6 +138,12 @@ true + + $(ProjectName) + + + $(ProjectName)64 + "%windir%\Sysnative\cscript" /nologo /E:JScript "defaultconfig\make_scmrev.h.js" diff --git a/web/contact.html b/web/contact.html index 0c967465..e730f709 100644 --- a/web/contact.html +++ b/web/contact.html @@ -50,7 +50,7 @@

Project Administrators

If you would are interesting in joining the FCEUX project please contact our project administrators.

If you've read the Help file, and you still don't understand a problem, you can discuss it on the TASVideos Forums.

-

If you have a bug report or feature request please post it in our Sourceforge tracker.

+

If you have a bug report or feature request please post it in our Github Issues.

If you wish to contact someone, the best way is on IRC in #fceu on irc.freenode.net diff --git a/web/download.html b/web/download.html index ce46695b..8c2b2faf 100644 --- a/web/download.html +++ b/web/download.html @@ -79,8 +79,12 @@

  • FCEUX 2.2.3 src
  • -

    If you are working with a developer to fix an issue affecting you then this is where you will find your fixed build:

    - +

    If you would like to test the current in-development version of FCEUX, interim builds are available here:

    +

    Source Code