Merge branch 'master' of github.com:TASEmulators/fceux
This commit is contained in:
commit
d72d9daebb
|
@ -61,6 +61,13 @@ echo '****************************************'
|
||||||
sudo apt-get --assume-yes install libminizip-dev
|
sudo apt-get --assume-yes install libminizip-dev
|
||||||
pkg-config --cflags --libs minizip
|
pkg-config --cflags --libs minizip
|
||||||
|
|
||||||
|
# Install libarchive-dev
|
||||||
|
echo '****************************************'
|
||||||
|
echo 'Install Dependency libarchive-dev'
|
||||||
|
echo '****************************************'
|
||||||
|
sudo apt-get --assume-yes install libarchive-dev
|
||||||
|
pkg-config --cflags --libs libarchive
|
||||||
|
|
||||||
# GTK+-2 is no longer needed
|
# GTK+-2 is no longer needed
|
||||||
#sudo apt-get install libgtk2.0-dev
|
#sudo apt-get install libgtk2.0-dev
|
||||||
|
|
||||||
|
|
|
@ -70,6 +70,12 @@ echo 'Install Dependency minizip'
|
||||||
echo '****************************************'
|
echo '****************************************'
|
||||||
brew install minizip
|
brew install minizip
|
||||||
|
|
||||||
|
echo '****************************************'
|
||||||
|
echo 'Install Optional Dependency libarchive'
|
||||||
|
echo '****************************************'
|
||||||
|
brew install libarchive
|
||||||
|
LIBARCHIVE_PATH=`brew --prefix libarchive`;
|
||||||
|
|
||||||
echo '****************************************'
|
echo '****************************************'
|
||||||
echo 'Install Optional Dependency x264'
|
echo 'Install Optional Dependency x264'
|
||||||
echo '****************************************'
|
echo '****************************************'
|
||||||
|
@ -87,7 +93,7 @@ brew install ffmpeg
|
||||||
|
|
||||||
#brew install zlib # Already installed in appveyor macOS
|
#brew install zlib # Already installed in appveyor macOS
|
||||||
|
|
||||||
export PKG_CONFIG_PATH=$PKG_CONFIG_PATH:/usr/local/lib/pkgconfig:
|
export PKG_CONFIG_PATH=$PKG_CONFIG_PATH:/usr/local/lib/pkgconfig:$LIBARCHIVE_PATH:
|
||||||
|
|
||||||
ls -ltr $HOME/Qt;
|
ls -ltr $HOME/Qt;
|
||||||
|
|
||||||
|
|
|
@ -24,28 +24,33 @@ mkdir bin
|
||||||
|
|
||||||
set SDL_VERSION=2.24.1
|
set SDL_VERSION=2.24.1
|
||||||
set FFMPEG_VERSION=5.1.2
|
set FFMPEG_VERSION=5.1.2
|
||||||
|
set LIBARCHIVE_VERSION=3.6.2
|
||||||
|
|
||||||
curl -s -LO https://github.com/libsdl-org/SDL/releases/download/release-%SDL_VERSION%/SDL2-devel-%SDL_VERSION%-VC.zip
|
curl -s -LO https://github.com/libsdl-org/SDL/releases/download/release-%SDL_VERSION%/SDL2-devel-%SDL_VERSION%-VC.zip
|
||||||
curl -s -LO https://github.com/GyanD/codexffmpeg/releases/download/%FFMPEG_VERSION%/ffmpeg-%FFMPEG_VERSION%-full_build-shared.zip
|
curl -s -LO https://github.com/GyanD/codexffmpeg/releases/download/%FFMPEG_VERSION%/ffmpeg-%FFMPEG_VERSION%-full_build-shared.zip
|
||||||
|
curl -s -LO https://www.libarchive.org/downloads/libarchive-v%LIBARCHIVE_VERSION%-amd64.zip
|
||||||
|
|
||||||
REM rmdir /q /s SDL2
|
REM rmdir /q /s SDL2
|
||||||
|
|
||||||
powershell -command "Expand-Archive" SDL2-devel-%SDL_VERSION%-VC.zip .
|
powershell -command "Expand-Archive" SDL2-devel-%SDL_VERSION%-VC.zip .
|
||||||
powershell -command "Expand-Archive" ffmpeg-%FFMPEG_VERSION%-full_build-shared.zip
|
powershell -command "Expand-Archive" ffmpeg-%FFMPEG_VERSION%-full_build-shared.zip
|
||||||
|
powershell -command "Expand-Archive" libarchive-v%LIBARCHIVE_VERSION%-amd64.zip
|
||||||
|
|
||||||
rename SDL2-%SDL_VERSION% SDL2
|
rename SDL2-%SDL_VERSION% SDL2
|
||||||
move ffmpeg-%FFMPEG_VERSION%-full_build-shared\ffmpeg-%FFMPEG_VERSION%-full_build-shared ffmpeg
|
move ffmpeg-%FFMPEG_VERSION%-full_build-shared\ffmpeg-%FFMPEG_VERSION%-full_build-shared ffmpeg
|
||||||
rmdir ffmpeg-%FFMPEG_VERSION%-full_build-shared
|
rmdir ffmpeg-%FFMPEG_VERSION%-full_build-shared
|
||||||
del ffmpeg-%FFMPEG_VERSION%-full_build-shared.zip
|
del ffmpeg-%FFMPEG_VERSION%-full_build-shared.zip
|
||||||
|
move libarchive-v%LIBARCHIVE_VERSION%-amd64\libarchive libarchive
|
||||||
|
|
||||||
set SDL_INSTALL_PREFIX=%CD%
|
set SDL_INSTALL_PREFIX=%CD%
|
||||||
set FFMPEG_INSTALL_PREFIX=%CD%
|
set FFMPEG_INSTALL_PREFIX=%CD%
|
||||||
|
set LIBARCHIVE_INSTALL_PREFIX=%CD%
|
||||||
set PUBLIC_RELEASE=0
|
set PUBLIC_RELEASE=0
|
||||||
IF DEFINED FCEU_RELEASE_VERSION (set PUBLIC_RELEASE=1)
|
IF DEFINED FCEU_RELEASE_VERSION (set PUBLIC_RELEASE=1)
|
||||||
|
|
||||||
REM cmake -h
|
REM cmake -h
|
||||||
REM cmake -G "NMake Makefiles" -DCMAKE_BUILD_TYPE=Release -DSDL_INSTALL_PREFIX=%SDL_INSTALL_PREFIX% ..
|
REM cmake -G "NMake Makefiles" -DCMAKE_BUILD_TYPE=Release -DSDL_INSTALL_PREFIX=%SDL_INSTALL_PREFIX% ..
|
||||||
cmake -DQT6=0 -DPUBLIC_RELEASE=%PUBLIC_RELEASE% -DSDL_INSTALL_PREFIX=%SDL_INSTALL_PREFIX% -DUSE_LIBAV=1 -DFFMPEG_INSTALL_PREFIX=%FFMPEG_INSTALL_PREFIX% -G"Visual Studio 16" -T"v142" ..
|
cmake -DQT6=0 -DPUBLIC_RELEASE=%PUBLIC_RELEASE% -DSDL_INSTALL_PREFIX=%SDL_INSTALL_PREFIX% -DLIBARCHIVE_INSTALL_PREFIX=%LIBARCHIVE_INSTALL_PREFIX% -DUSE_LIBAV=1 -DFFMPEG_INSTALL_PREFIX=%FFMPEG_INSTALL_PREFIX% -G"Visual Studio 16" -T"v142" ..
|
||||||
|
|
||||||
REM nmake
|
REM nmake
|
||||||
msbuild /m fceux.sln /p:Configuration=Release
|
msbuild /m fceux.sln /p:Configuration=Release
|
||||||
|
@ -53,9 +58,10 @@ if %ERRORLEVEL% NEQ 0 EXIT /B 1
|
||||||
|
|
||||||
copy src\Release\fceux.exe bin\qfceux.exe
|
copy src\Release\fceux.exe bin\qfceux.exe
|
||||||
copy %PROJECT_ROOT%\src\auxlib.lua bin\.
|
copy %PROJECT_ROOT%\src\auxlib.lua bin\.
|
||||||
REM copy %PROJECT_ROOT%\src\drivers\win\lua\x64\lua51.dll bin\.
|
copy %PROJECT_ROOT%\src\drivers\win\lua\x64\lua51.dll bin\.
|
||||||
REM copy %PROJECT_ROOT%\src\drivers\win\lua\x64\lua5.1.dll bin\.
|
copy %PROJECT_ROOT%\src\drivers\win\lua\x64\lua5.1.dll bin\.
|
||||||
copy %SDL_INSTALL_PREFIX%\SDL2\lib\x64\SDL2.dll bin\.
|
copy %SDL_INSTALL_PREFIX%\SDL2\lib\x64\SDL2.dll bin\.
|
||||||
|
copy %LIBARCHIVE_INSTALL_PREFIX%\libarchive\bin\archive.dll bin\.
|
||||||
copy %FFMPEG_INSTALL_PREFIX%\ffmpeg\bin\*.dll bin\.
|
copy %FFMPEG_INSTALL_PREFIX%\ffmpeg\bin\*.dll bin\.
|
||||||
|
|
||||||
windeployqt --no-compiler-runtime bin\qfceux.exe
|
windeployqt --no-compiler-runtime bin\qfceux.exe
|
||||||
|
|
|
@ -41,12 +41,15 @@ if(WIN32)
|
||||||
add_definitions( -DMSVC -D_CRT_SECURE_NO_WARNINGS )
|
add_definitions( -DMSVC -D_CRT_SECURE_NO_WARNINGS )
|
||||||
add_definitions( -D__SDL__ -D__QT_DRIVER__ -DQT_DEPRECATED_WARNINGS )
|
add_definitions( -D__SDL__ -D__QT_DRIVER__ -DQT_DEPRECATED_WARNINGS )
|
||||||
add_definitions( -DFCEUDEF_DEBUGGER )
|
add_definitions( -DFCEUDEF_DEBUGGER )
|
||||||
|
add_definitions( -D_USE_LIBARCHIVE )
|
||||||
add_definitions( /wd4267 /wd4244 )
|
add_definitions( /wd4267 /wd4244 )
|
||||||
#add_definitions( /wd4018 ) # Integer comparison sign mismatch warnings
|
#add_definitions( /wd4018 ) # Integer comparison sign mismatch warnings
|
||||||
include_directories( ${SDL_INSTALL_PREFIX}/SDL2/include )
|
include_directories( ${SDL_INSTALL_PREFIX}/SDL2/include )
|
||||||
|
include_directories( ${LIBARCHIVE_INSTALL_PREFIX}/libarchive/include )
|
||||||
include_directories( ${CMAKE_CURRENT_SOURCE_DIR}/drivers/win/zlib )
|
include_directories( ${CMAKE_CURRENT_SOURCE_DIR}/drivers/win/zlib )
|
||||||
set( OPENGL_LDFLAGS OpenGL::GL )
|
set( OPENGL_LDFLAGS OpenGL::GL )
|
||||||
set( SDL2_LDFLAGS ${SDL_INSTALL_PREFIX}/SDL2/lib/x64/SDL2.lib )
|
set( SDL2_LDFLAGS ${SDL_INSTALL_PREFIX}/SDL2/lib/x64/SDL2.lib )
|
||||||
|
set( LIBARCHIVE_LDFLAGS ${LIBARCHIVE_INSTALL_PREFIX}/libarchive/lib/archive.lib )
|
||||||
set( SYS_LIBS wsock32 ws2_32 vfw32 Htmlhelp )
|
set( SYS_LIBS wsock32 ws2_32 vfw32 Htmlhelp )
|
||||||
set(APP_ICON_RESOURCES_WINDOWS ${CMAKE_SOURCE_DIR}/icons/fceux.rc )
|
set(APP_ICON_RESOURCES_WINDOWS ${CMAKE_SOURCE_DIR}/icons/fceux.rc )
|
||||||
|
|
||||||
|
@ -110,6 +113,13 @@ else(WIN32)
|
||||||
add_definitions( -D_SYSTEM_MINIZIP ${MINIZIP_CFLAGS} )
|
add_definitions( -D_SYSTEM_MINIZIP ${MINIZIP_CFLAGS} )
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
pkg_check_modules( LIBARCHIVE libarchive)
|
||||||
|
|
||||||
|
if ( ${LIBARCHIVE_FOUND} )
|
||||||
|
message( STATUS "Using System Libarchive Library ${LIBARCHIVE_VERSION}" )
|
||||||
|
add_definitions( -D_USE_LIBARCHIVE ${LIBARCHIVE_CFLAGS} )
|
||||||
|
endif()
|
||||||
|
|
||||||
pkg_check_modules( X264 x264)
|
pkg_check_modules( X264 x264)
|
||||||
|
|
||||||
if ( ${X264_FOUND} )
|
if ( ${X264_FOUND} )
|
||||||
|
@ -643,7 +653,7 @@ target_link_libraries( ${APP_NAME} ${ASAN_LDFLAGS}
|
||||||
${${Qt}OpenGLWidgets_LIBRARIES}
|
${${Qt}OpenGLWidgets_LIBRARIES}
|
||||||
${OPENGL_LDFLAGS}
|
${OPENGL_LDFLAGS}
|
||||||
${SDL2_LDFLAGS}
|
${SDL2_LDFLAGS}
|
||||||
${MINIZIP_LDFLAGS} ${ZLIB_LIBRARIES}
|
${MINIZIP_LDFLAGS} ${ZLIB_LIBRARIES} ${LIBARCHIVE_LDFLAGS}
|
||||||
${LUA_LDFLAGS} ${X264_LDFLAGS} ${X265_LDFLAGS} ${LIBAV_LDFLAGS}
|
${LUA_LDFLAGS} ${X264_LDFLAGS} ${X265_LDFLAGS} ${LIBAV_LDFLAGS}
|
||||||
${SYS_LIBS}
|
${SYS_LIBS}
|
||||||
)
|
)
|
||||||
|
|
|
@ -27,6 +27,7 @@ static void (*WSync)(void);
|
||||||
static readfunc defread;
|
static readfunc defread;
|
||||||
static uint8 *WRAM = NULL;
|
static uint8 *WRAM = NULL;
|
||||||
static uint32 WRAMSIZE=0;
|
static uint32 WRAMSIZE=0;
|
||||||
|
static uint8 hasBattery = 0;
|
||||||
|
|
||||||
static DECLFW(LatchWrite) {
|
static DECLFW(LatchWrite) {
|
||||||
latche = A;
|
latche = A;
|
||||||
|
@ -358,20 +359,17 @@ void Mapper217_Init(CartInfo *info) {
|
||||||
}
|
}
|
||||||
|
|
||||||
//------------------ Map 227 ---------------------------
|
//------------------ Map 227 ---------------------------
|
||||||
|
|
||||||
static void M227Sync(void) {
|
static void M227Sync(void) {
|
||||||
uint32 S = latche & 1;
|
uint32 S = latche & 1;
|
||||||
uint32 p = ((latche >> 2) & 0x1F) + ((latche & 0x100) >> 3);
|
uint32 p = ((latche >> 2) & 0x1F) + ((latche & 0x100) >> 3);
|
||||||
uint32 L = (latche >> 9) & 1;
|
uint32 L = (latche >> 9) & 1;
|
||||||
|
|
||||||
// ok, according to nesdev wiki (refrenced to the nesdev dumping thread) there is a CHR write protection bit7.
|
// Only Waixing appear to have battery flag enabled, while multicarts don't.
|
||||||
// however, this bit clearly determined a specific PRG layout for some game but does not meant to have additional
|
// Multicarts needs CHR-RAM protect in NROM modes, so only apply CHR-RAM protect
|
||||||
// functionality. as I see from the menu code, it disables the chr writing before run an actual game.
|
// on non battery-enabled carts.
|
||||||
// this fix here makes happy both waixing rpgs and multigame menus at once. can't veryfy it on a hardware
|
if (!hasBattery && (latche & 0x80) == 0x80)
|
||||||
// but if I find some i'll definitly do this.
|
/* CHR-RAM write protect hack, needed for some multicarts */
|
||||||
|
SetupCartCHRMapping(0, CHRptr[0], 0x2000, 0);
|
||||||
if ((latche & 0xF000) == 0xF000)
|
|
||||||
SetupCartCHRMapping(0, CHRptr[0], 0x2000, 0);
|
|
||||||
else
|
else
|
||||||
SetupCartCHRMapping(0, CHRptr[0], 0x2000, 1);
|
SetupCartCHRMapping(0, CHRptr[0], 0x2000, 1);
|
||||||
|
|
||||||
|
@ -409,6 +407,7 @@ static void M227Sync(void) {
|
||||||
|
|
||||||
void Mapper227_Init(CartInfo *info) {
|
void Mapper227_Init(CartInfo *info) {
|
||||||
Latch_Init(info, M227Sync, NULL, 0x0000, 0x8000, 0xFFFF, 1);
|
Latch_Init(info, M227Sync, NULL, 0x0000, 0x8000, 0xFFFF, 1);
|
||||||
|
hasBattery = info->battery;
|
||||||
}
|
}
|
||||||
|
|
||||||
//------------------ Map 229 ---------------------------
|
//------------------ Map 229 ---------------------------
|
||||||
|
|
|
@ -52,17 +52,17 @@
|
||||||
#include <cctype>
|
#include <cctype>
|
||||||
|
|
||||||
uint16 debugLastAddress = 0; // used by 'T' and 'R' conditions
|
uint16 debugLastAddress = 0; // used by 'T' and 'R' conditions
|
||||||
uint8 debugLastOpcode; // used to evaluate 'W' condition
|
uint8 debugLastOpcode = 0; // used to evaluate 'W' condition
|
||||||
|
|
||||||
// Next non-whitespace character in string
|
// Next non-whitespace character in string
|
||||||
char next;
|
static char next = 0;
|
||||||
|
|
||||||
int ishex(char c)
|
static int ishex(char c)
|
||||||
{
|
{
|
||||||
return isdigit(c) || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F');
|
return isdigit(c) || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F');
|
||||||
}
|
}
|
||||||
|
|
||||||
void scan(const char** str)
|
static void scan(const char** str)
|
||||||
{
|
{
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
|
@ -71,40 +71,37 @@ void scan(const char** str)
|
||||||
} while (isspace(next));
|
} while (isspace(next));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Frees a condition and all of it's sub conditions
|
|
||||||
void freeTree(Condition* c)
|
|
||||||
{
|
|
||||||
if (c->lhs) freeTree(c->lhs);
|
|
||||||
if (c->rhs) freeTree(c->rhs);
|
|
||||||
|
|
||||||
free(c);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Generic function to handle all infix operators but the last one in the precedence hierarchy. : '(' E ')'
|
// Generic function to handle all infix operators but the last one in the precedence hierarchy. : '(' E ')'
|
||||||
Condition* InfixOperator(const char** str, Condition(*nextPart(const char**)), int(*operators)(const char**))
|
static Condition* InfixOperator(const char** str, Condition(*nextPart(const char**)), int(*operators)(const char**))
|
||||||
{
|
{
|
||||||
Condition* t = nextPart(str);
|
Condition* t = nextPart(str);
|
||||||
Condition* t1;
|
Condition* t1;
|
||||||
Condition* mid;
|
Condition* mid;
|
||||||
int op;
|
int op;
|
||||||
|
|
||||||
|
if (t == nullptr)
|
||||||
|
{
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
while ((op = operators(str)))
|
while ((op = operators(str)))
|
||||||
{
|
{
|
||||||
scan(str);
|
scan(str);
|
||||||
|
|
||||||
t1 = nextPart(str);
|
t1 = nextPart(str);
|
||||||
|
|
||||||
if (t1 == 0)
|
if (t1 == nullptr)
|
||||||
{
|
{
|
||||||
if(t)
|
delete t;
|
||||||
freeTree(t);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
mid = (Condition*)FCEU_dmalloc(sizeof(Condition));
|
mid = new Condition();
|
||||||
if (!mid)
|
if (mid == nullptr)
|
||||||
return NULL;
|
{
|
||||||
memset(mid, 0, sizeof(Condition));
|
delete t;
|
||||||
|
delete t1;
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
mid->lhs = t;
|
mid->lhs = t;
|
||||||
mid->rhs = t1;
|
mid->rhs = t1;
|
||||||
|
@ -117,7 +114,7 @@ Condition* InfixOperator(const char** str, Condition(*nextPart(const char**)), i
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generic handler for two-character operators
|
// Generic handler for two-character operators
|
||||||
int TwoCharOperator(const char** str, char c1, char c2, int op)
|
static int TwoCharOperator(const char** str, char c1, char c2, int op)
|
||||||
{
|
{
|
||||||
if (next == c1 && **str == c2)
|
if (next == c1 && **str == c2)
|
||||||
{
|
{
|
||||||
|
@ -131,43 +128,43 @@ int TwoCharOperator(const char** str, char c1, char c2, int op)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Determines if a character is a flag
|
// Determines if a character is a flag
|
||||||
int isFlag(char c)
|
static int isFlag(char c)
|
||||||
{
|
{
|
||||||
return c == 'N' || c == 'I' || c == 'C' || c == 'V' || c == 'Z' || c == 'B' || c == 'U' || c == 'D';
|
return c == 'N' || c == 'I' || c == 'C' || c == 'V' || c == 'Z' || c == 'B' || c == 'U' || c == 'D';
|
||||||
}
|
}
|
||||||
|
|
||||||
// Determines if a character is a register
|
// Determines if a character is a register
|
||||||
int isRegister(char c)
|
static int isRegister(char c)
|
||||||
{
|
{
|
||||||
return c == 'A' || c == 'X' || c == 'Y' || c == 'P' || c == 'S';
|
return c == 'A' || c == 'X' || c == 'Y' || c == 'P' || c == 'S';
|
||||||
}
|
}
|
||||||
|
|
||||||
// Determines if a character is for PC bank
|
// Determines if a character is for PC bank
|
||||||
int isPCBank(char c)
|
static int isPCBank(char c)
|
||||||
{
|
{
|
||||||
return c == 'K';
|
return c == 'K';
|
||||||
}
|
}
|
||||||
|
|
||||||
// Determines if a character is for Data bank
|
// Determines if a character is for Data bank
|
||||||
int isDataBank(char c)
|
static int isDataBank(char c)
|
||||||
{
|
{
|
||||||
return c == 'T';
|
return c == 'T';
|
||||||
}
|
}
|
||||||
|
|
||||||
// Determines if a character is for value read
|
// Determines if a character is for value read
|
||||||
int isValueRead(char c)
|
static int isValueRead(char c)
|
||||||
{
|
{
|
||||||
return c == 'R';
|
return c == 'R';
|
||||||
}
|
}
|
||||||
|
|
||||||
// Determines if a character is for value write
|
// Determines if a character is for value write
|
||||||
int isValueWrite(char c)
|
static int isValueWrite(char c)
|
||||||
{
|
{
|
||||||
return c == 'W';
|
return c == 'W';
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reads a hexadecimal number from str
|
// Reads a hexadecimal number from str
|
||||||
int getNumber(unsigned int* number, const char** str)
|
static int getNumber(unsigned int* number, const char** str)
|
||||||
{
|
{
|
||||||
// char buffer[5];
|
// char buffer[5];
|
||||||
|
|
||||||
|
@ -185,10 +182,10 @@ int getNumber(unsigned int* number, const char** str)
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
Condition* Connect(const char** str);
|
static Condition* Connect(const char** str);
|
||||||
|
|
||||||
// Handles the following part of the grammar: '(' E ')'
|
// Handles the following part of the grammar: '(' E ')'
|
||||||
Condition* Parentheses(const char** str, Condition* c, char openPar, char closePar)
|
static Condition* Parentheses(const char** str, Condition* c, char openPar, char closePar)
|
||||||
{
|
{
|
||||||
if (next == openPar)
|
if (next == openPar)
|
||||||
{
|
{
|
||||||
|
@ -216,7 +213,7 @@ Condition* Parentheses(const char** str, Condition* c, char openPar, char closeP
|
||||||
* Check for primitives
|
* Check for primitives
|
||||||
* Flags, Registers, Numbers, Addresses and parentheses
|
* Flags, Registers, Numbers, Addresses and parentheses
|
||||||
*/
|
*/
|
||||||
Condition* Primitive(const char** str, Condition* c)
|
static Condition* Primitive(const char** str, Condition* c)
|
||||||
{
|
{
|
||||||
if (isFlag(next)) /* Flags */
|
if (isFlag(next)) /* Flags */
|
||||||
{
|
{
|
||||||
|
@ -394,24 +391,22 @@ Condition* Primitive(const char** str, Condition* c)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Handle * and / operators */
|
/* Handle * and / operators */
|
||||||
Condition* Term(const char** str)
|
static Condition* Term(const char** str)
|
||||||
{
|
{
|
||||||
Condition* t;
|
Condition* t;
|
||||||
Condition* t1;
|
Condition* t1;
|
||||||
Condition* mid;
|
Condition* mid;
|
||||||
|
|
||||||
t = (Condition*)FCEU_dmalloc(sizeof(Condition));
|
t = new Condition();
|
||||||
|
|
||||||
if (!t)
|
if (t == nullptr)
|
||||||
{
|
{
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
memset(t, 0, sizeof(Condition));
|
|
||||||
|
|
||||||
if (!Primitive(str, t))
|
if (!Primitive(str, t))
|
||||||
{
|
{
|
||||||
freeTree(t);
|
delete t;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -421,22 +416,25 @@ Condition* Term(const char** str)
|
||||||
|
|
||||||
scan(str);
|
scan(str);
|
||||||
|
|
||||||
if (!(t1 = (Condition*)FCEU_dmalloc(sizeof(Condition))))
|
if ((t1 = new Condition()) == nullptr)
|
||||||
return NULL;
|
{
|
||||||
|
delete t;
|
||||||
memset(t1, 0, sizeof(Condition));
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
if (!Primitive(str, t1))
|
if (!Primitive(str, t1))
|
||||||
{
|
{
|
||||||
freeTree(t);
|
delete t;
|
||||||
freeTree(t1);
|
delete t1;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(mid = (Condition*)FCEU_dmalloc(sizeof(Condition))))
|
if ((mid = new Condition()) == nullptr)
|
||||||
return NULL;
|
{
|
||||||
|
delete t;
|
||||||
memset(mid, 0, sizeof(Condition));
|
delete t1;
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
mid->lhs = t;
|
mid->lhs = t;
|
||||||
mid->rhs = t1;
|
mid->rhs = t1;
|
||||||
|
@ -449,7 +447,7 @@ Condition* Term(const char** str)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check for + and - operators */
|
/* Check for + and - operators */
|
||||||
int SumOperators(const char** str)
|
static int SumOperators(const char** str)
|
||||||
{
|
{
|
||||||
switch (next)
|
switch (next)
|
||||||
{
|
{
|
||||||
|
@ -460,13 +458,13 @@ int SumOperators(const char** str)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Handle + and - operators */
|
/* Handle + and - operators */
|
||||||
Condition* Sum(const char** str)
|
static Condition* Sum(const char** str)
|
||||||
{
|
{
|
||||||
return InfixOperator(str, Term, SumOperators);
|
return InfixOperator(str, Term, SumOperators);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check for <=, =>, ==, !=, > and < operators */
|
/* Check for <=, =>, ==, !=, > and < operators */
|
||||||
int CompareOperators(const char** str)
|
static int CompareOperators(const char** str)
|
||||||
{
|
{
|
||||||
int val = TwoCharOperator(str, '=', '=', OP_EQ);
|
int val = TwoCharOperator(str, '=', '=', OP_EQ);
|
||||||
if (val) return val;
|
if (val) return val;
|
||||||
|
@ -490,13 +488,13 @@ int CompareOperators(const char** str)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Handle <=, =>, ==, !=, > and < operators */
|
/* Handle <=, =>, ==, !=, > and < operators */
|
||||||
Condition* Compare(const char** str)
|
static Condition* Compare(const char** str)
|
||||||
{
|
{
|
||||||
return InfixOperator(str, Sum, CompareOperators);
|
return InfixOperator(str, Sum, CompareOperators);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check for || or && operators */
|
/* Check for || or && operators */
|
||||||
int ConnectOperators(const char** str)
|
static int ConnectOperators(const char** str)
|
||||||
{
|
{
|
||||||
int val = TwoCharOperator(str, '|', '|', OP_OR);
|
int val = TwoCharOperator(str, '|', '|', OP_OR);
|
||||||
if(val) return val;
|
if(val) return val;
|
||||||
|
@ -508,7 +506,7 @@ int ConnectOperators(const char** str)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Handle || and && operators */
|
/* Handle || and && operators */
|
||||||
Condition* Connect(const char** str)
|
static Condition* Connect(const char** str)
|
||||||
{
|
{
|
||||||
return InfixOperator(str, Compare, ConnectOperators);
|
return InfixOperator(str, Compare, ConnectOperators);
|
||||||
}
|
}
|
||||||
|
@ -521,6 +519,10 @@ Condition* generateCondition(const char* str)
|
||||||
scan(&str);
|
scan(&str);
|
||||||
c = Connect(&str);
|
c = Connect(&str);
|
||||||
|
|
||||||
if (!c || next != 0) return 0;
|
if (!c || next != 0)
|
||||||
|
{
|
||||||
|
if (c) delete c;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
else return c;
|
else return c;
|
||||||
}
|
}
|
||||||
|
|
|
@ -61,9 +61,28 @@ struct Condition
|
||||||
|
|
||||||
unsigned int type2;
|
unsigned int type2;
|
||||||
unsigned int value2;
|
unsigned int value2;
|
||||||
|
|
||||||
|
Condition(void)
|
||||||
|
{
|
||||||
|
op = 0;
|
||||||
|
lhs = rhs = nullptr;
|
||||||
|
type1 = value1 = 0;
|
||||||
|
type2 = value2 = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
~Condition(void)
|
||||||
|
{
|
||||||
|
if (lhs)
|
||||||
|
{
|
||||||
|
delete lhs;
|
||||||
|
}
|
||||||
|
if (rhs)
|
||||||
|
{
|
||||||
|
delete rhs;
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
void freeTree(Condition* c);
|
|
||||||
Condition* generateCondition(const char* str);
|
Condition* generateCondition(const char* str);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -19,10 +19,15 @@ unsigned int debuggerPageSize = 14;
|
||||||
int vblankScanLines = 0; //Used to calculate scanlines 240-261 (vblank)
|
int vblankScanLines = 0; //Used to calculate scanlines 240-261 (vblank)
|
||||||
int vblankPixel = 0; //Used to calculate the pixels in vblank
|
int vblankPixel = 0; //Used to calculate the pixels in vblank
|
||||||
|
|
||||||
int offsetStringToInt(unsigned int type, const char* offsetBuffer)
|
int offsetStringToInt(unsigned int type, const char* offsetBuffer, bool *conversionOk)
|
||||||
{
|
{
|
||||||
int offset = -1;
|
int offset = -1;
|
||||||
|
|
||||||
|
if (conversionOk)
|
||||||
|
{
|
||||||
|
*conversionOk = false;
|
||||||
|
}
|
||||||
|
|
||||||
if (sscanf(offsetBuffer,"%7X",(unsigned int *)&offset) == EOF)
|
if (sscanf(offsetBuffer,"%7X",(unsigned int *)&offset) == EOF)
|
||||||
{
|
{
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -30,14 +35,26 @@ int offsetStringToInt(unsigned int type, const char* offsetBuffer)
|
||||||
|
|
||||||
if (type & BT_P)
|
if (type & BT_P)
|
||||||
{
|
{
|
||||||
|
if (conversionOk)
|
||||||
|
{
|
||||||
|
*conversionOk = (offset >= 0) && (offset < 0x4000);
|
||||||
|
}
|
||||||
return offset & 0x3FFF;
|
return offset & 0x3FFF;
|
||||||
}
|
}
|
||||||
else if (type & BT_S)
|
else if (type & BT_S)
|
||||||
{
|
{
|
||||||
|
if (conversionOk)
|
||||||
|
{
|
||||||
|
*conversionOk = (offset >= 0) && (offset < 0x100);
|
||||||
|
}
|
||||||
return offset & 0x00FF;
|
return offset & 0x00FF;
|
||||||
}
|
}
|
||||||
else if (type & BT_R)
|
else if (type & BT_R)
|
||||||
{
|
{
|
||||||
|
if (conversionOk)
|
||||||
|
{
|
||||||
|
*conversionOk = (offset >= 0);
|
||||||
|
}
|
||||||
return offset;
|
return offset;
|
||||||
}
|
}
|
||||||
else // BT_C
|
else // BT_C
|
||||||
|
@ -46,6 +63,10 @@ int offsetStringToInt(unsigned int type, const char* offsetBuffer)
|
||||||
|
|
||||||
if (sym)
|
if (sym)
|
||||||
{
|
{
|
||||||
|
if (conversionOk)
|
||||||
|
{
|
||||||
|
*conversionOk = true;
|
||||||
|
}
|
||||||
return sym->offset() & 0xFFFF;
|
return sym->offset() & 0xFFFF;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -56,21 +77,26 @@ int offsetStringToInt(unsigned int type, const char* offsetBuffer)
|
||||||
type = GameInfo->type;
|
type = GameInfo->type;
|
||||||
}
|
}
|
||||||
if (type == GIT_NSF) { //NSF Breakpoint keywords
|
if (type == GIT_NSF) { //NSF Breakpoint keywords
|
||||||
if (strcmp(offsetBuffer,"LOAD") == 0) return (NSFHeader.LoadAddressLow | (NSFHeader.LoadAddressHigh<<8));
|
if (strcmp(offsetBuffer,"LOAD") == 0) offset = (NSFHeader.LoadAddressLow | (NSFHeader.LoadAddressHigh<<8));
|
||||||
if (strcmp(offsetBuffer,"INIT") == 0) return (NSFHeader.InitAddressLow | (NSFHeader.InitAddressHigh<<8));
|
else if (strcmp(offsetBuffer,"INIT") == 0) offset = (NSFHeader.InitAddressLow | (NSFHeader.InitAddressHigh<<8));
|
||||||
if (strcmp(offsetBuffer,"PLAY") == 0) return (NSFHeader.PlayAddressLow | (NSFHeader.PlayAddressHigh<<8));
|
else if (strcmp(offsetBuffer,"PLAY") == 0) offset = (NSFHeader.PlayAddressLow | (NSFHeader.PlayAddressHigh<<8));
|
||||||
}
|
}
|
||||||
else if (type == GIT_FDS) { //FDS Breakpoint keywords
|
else if (type == GIT_FDS) { //FDS Breakpoint keywords
|
||||||
if (strcmp(offsetBuffer,"NMI1") == 0) return (GetMem(0xDFF6) | (GetMem(0xDFF7)<<8));
|
if (strcmp(offsetBuffer,"NMI1") == 0) offset = (GetMem(0xDFF6) | (GetMem(0xDFF7)<<8));
|
||||||
if (strcmp(offsetBuffer,"NMI2") == 0) return (GetMem(0xDFF8) | (GetMem(0xDFF9)<<8));
|
else if (strcmp(offsetBuffer,"NMI2") == 0) offset = (GetMem(0xDFF8) | (GetMem(0xDFF9)<<8));
|
||||||
if (strcmp(offsetBuffer,"NMI3") == 0) return (GetMem(0xDFFA) | (GetMem(0xDFFB)<<8));
|
else if (strcmp(offsetBuffer,"NMI3") == 0) offset = (GetMem(0xDFFA) | (GetMem(0xDFFB)<<8));
|
||||||
if (strcmp(offsetBuffer,"RST") == 0) return (GetMem(0xDFFC) | (GetMem(0xDFFD)<<8));
|
else if (strcmp(offsetBuffer,"RST") == 0) offset = (GetMem(0xDFFC) | (GetMem(0xDFFD)<<8));
|
||||||
if ((strcmp(offsetBuffer,"IRQ") == 0) || (strcmp(offsetBuffer,"BRK") == 0)) return (GetMem(0xDFFE) | (GetMem(0xDFFF)<<8));
|
else if ((strcmp(offsetBuffer,"IRQ") == 0) || (strcmp(offsetBuffer,"BRK") == 0)) offset = (GetMem(0xDFFE) | (GetMem(0xDFFF)<<8));
|
||||||
}
|
}
|
||||||
else { //NES Breakpoint keywords
|
else { //NES Breakpoint keywords
|
||||||
if ((strcmp(offsetBuffer,"NMI") == 0) || (strcmp(offsetBuffer,"VBL") == 0)) return (GetMem(0xFFFA) | (GetMem(0xFFFB)<<8));
|
if ((strcmp(offsetBuffer,"NMI") == 0) || (strcmp(offsetBuffer,"VBL") == 0)) offset = (GetMem(0xFFFA) | (GetMem(0xFFFB)<<8));
|
||||||
if (strcmp(offsetBuffer,"RST") == 0) return (GetMem(0xFFFC) | (GetMem(0xFFFD)<<8));
|
else if (strcmp(offsetBuffer,"RST") == 0) offset = (GetMem(0xFFFC) | (GetMem(0xFFFD)<<8));
|
||||||
if ((strcmp(offsetBuffer,"IRQ") == 0) || (strcmp(offsetBuffer,"BRK") == 0)) return (GetMem(0xFFFE) | (GetMem(0xFFFF)<<8));
|
else if ((strcmp(offsetBuffer,"IRQ") == 0) || (strcmp(offsetBuffer,"BRK") == 0)) offset = (GetMem(0xFFFE) | (GetMem(0xFFFF)<<8));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (conversionOk)
|
||||||
|
{
|
||||||
|
*conversionOk = (offset >= 0) && (offset < 0x10000);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -139,7 +165,7 @@ int checkCondition(const char* condition, int num)
|
||||||
// Remove the old breakpoint condition before adding a new condition.
|
// Remove the old breakpoint condition before adding a new condition.
|
||||||
if (watchpoint[num].cond)
|
if (watchpoint[num].cond)
|
||||||
{
|
{
|
||||||
freeTree(watchpoint[num].cond);
|
delete watchpoint[num].cond;
|
||||||
free(watchpoint[num].condText);
|
free(watchpoint[num].condText);
|
||||||
watchpoint[num].cond = 0;
|
watchpoint[num].cond = 0;
|
||||||
watchpoint[num].condText = 0;
|
watchpoint[num].condText = 0;
|
||||||
|
@ -153,8 +179,8 @@ int checkCondition(const char* condition, int num)
|
||||||
{
|
{
|
||||||
watchpoint[num].cond = c;
|
watchpoint[num].cond = c;
|
||||||
watchpoint[num].condText = (char*)malloc(strlen(condition) + 1);
|
watchpoint[num].condText = (char*)malloc(strlen(condition) + 1);
|
||||||
if (!watchpoint[num].condText)
|
if (!watchpoint[num].condText)
|
||||||
return 0;
|
return 0;
|
||||||
strcpy(watchpoint[num].condText, condition);
|
strcpy(watchpoint[num].condText, condition);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -169,7 +195,7 @@ int checkCondition(const char* condition, int num)
|
||||||
// Remove the old breakpoint condition
|
// Remove the old breakpoint condition
|
||||||
if (watchpoint[num].cond)
|
if (watchpoint[num].cond)
|
||||||
{
|
{
|
||||||
freeTree(watchpoint[num].cond);
|
delete watchpoint[num].cond;
|
||||||
free(watchpoint[num].condText);
|
free(watchpoint[num].condText);
|
||||||
watchpoint[num].cond = 0;
|
watchpoint[num].cond = 0;
|
||||||
watchpoint[num].condText = 0;
|
watchpoint[num].condText = 0;
|
||||||
|
|
|
@ -172,7 +172,7 @@ DebuggerState &FCEUI_Debugger();
|
||||||
//#define WRITE_BREAKPOINT 16
|
//#define WRITE_BREAKPOINT 16
|
||||||
//#define EXECUTE_BREAKPOINT 32
|
//#define EXECUTE_BREAKPOINT 32
|
||||||
|
|
||||||
int offsetStringToInt(unsigned int type, const char* offsetBuffer);
|
int offsetStringToInt(unsigned int type, const char* offsetBuffer, bool *conversionOk = nullptr);
|
||||||
unsigned int NewBreak(const char* name, int start, int end, unsigned int type, const char* condition, unsigned int num, bool enable);
|
unsigned int NewBreak(const char* name, int start, int end, unsigned int type, const char* condition, unsigned int num, bool enable);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -346,7 +346,7 @@ void FCEU_DrawRecordingStatus(uint8* XBuf)
|
||||||
hasPlayRecIcon = true;
|
hasPlayRecIcon = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(FCEUI_EmulationPaused())
|
if( EmulationPaused & (EMULATIONPAUSED_PAUSED | EMULATIONPAUSED_TIMER) )
|
||||||
drawstatus(XBuf-ClipSidesOffset,3,28,hasPlayRecIcon?-16:0);
|
drawstatus(XBuf-ClipSidesOffset,3,28,hasPlayRecIcon?-16:0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -273,6 +273,8 @@ void FCEUI_ClearEmulationFrameStepped();
|
||||||
void FCEUI_SetEmulationPaused(int val);
|
void FCEUI_SetEmulationPaused(int val);
|
||||||
///toggles the paused bit (bit0) for EmulationPaused. caused FCEUD_DebugUpdate() to fire if the emulation pauses
|
///toggles the paused bit (bit0) for EmulationPaused. caused FCEUD_DebugUpdate() to fire if the emulation pauses
|
||||||
void FCEUI_ToggleEmulationPause();
|
void FCEUI_ToggleEmulationPause();
|
||||||
|
void FCEUI_PauseForDuration(int secs);
|
||||||
|
int FCEUI_PauseFramesRemaining();
|
||||||
|
|
||||||
//indicates whether input aids should be drawn (such as crosshairs, etc; usually in fullscreen mode)
|
//indicates whether input aids should be drawn (such as crosshairs, etc; usually in fullscreen mode)
|
||||||
bool FCEUD_ShouldDrawInputAids();
|
bool FCEUD_ShouldDrawInputAids();
|
||||||
|
|
|
@ -30,9 +30,14 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef _USE_X264
|
#ifdef _USE_X264
|
||||||
|
#include <cstdint>
|
||||||
#include "x264.h"
|
#include "x264.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef _USE_LIBARCHIVE
|
||||||
|
#include <archive.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef _USE_LIBAV
|
#ifdef _USE_LIBAV
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C"
|
extern "C"
|
||||||
|
@ -201,6 +206,23 @@ AboutWindow::AboutWindow(QWidget *parent)
|
||||||
sprintf( stmp, " Compiled with zlib %s\n", ZLIB_VERSION );
|
sprintf( stmp, " Compiled with zlib %s\n", ZLIB_VERSION );
|
||||||
credits->insertPlainText( stmp );
|
credits->insertPlainText( stmp );
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef _USE_LIBARCHIVE
|
||||||
|
sprintf( stmp, " Compiled with libarchive %s\n", ARCHIVE_VERSION_ONLY_STRING );
|
||||||
|
credits->insertPlainText( stmp );
|
||||||
|
const char *libArcName[] = { "zlib", "liblzma", "bzlib", "liblz4", "libzstd", nullptr };
|
||||||
|
const char *libArcVersion[] = { archive_zlib_version(), archive_liblzma_version(),
|
||||||
|
archive_bzlib_version(), archive_liblz4_version(), archive_libzstd_version(), nullptr };
|
||||||
|
i=0;
|
||||||
|
while (libArcName[i])
|
||||||
|
{
|
||||||
|
if (libArcVersion[i])
|
||||||
|
{
|
||||||
|
sprintf( stmp, " %s %s\n", libArcName[i], libArcVersion[i]);
|
||||||
|
credits->insertPlainText( stmp );
|
||||||
|
}
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef _S9XLUA_H
|
#ifdef _S9XLUA_H
|
||||||
sprintf( stmp, " Compiled with %s\n", LUA_RELEASE );
|
sprintf( stmp, " Compiled with %s\n", LUA_RELEASE );
|
||||||
|
|
|
@ -54,7 +54,6 @@ void openCheatDialog(QWidget *parent)
|
||||||
{
|
{
|
||||||
win->activateWindow();
|
win->activateWindow();
|
||||||
win->raise();
|
win->raise();
|
||||||
win->setFocus();
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
win = new GuiCheatsDialog_t(parent);
|
win = new GuiCheatsDialog_t(parent);
|
||||||
|
@ -705,14 +704,10 @@ int GuiCheatsDialog_t::activeCheatListCB(const char *name, uint32 a, uint8 v, in
|
||||||
|
|
||||||
if (item == NULL)
|
if (item == NULL)
|
||||||
{
|
{
|
||||||
item = new QTreeWidgetItem();
|
item = new QTreeWidgetItem(actvCheatList);
|
||||||
|
|
||||||
actvCheatList->addTopLevelItem(item);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//item->setFlags( Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsEditable | Qt::ItemIsUserCheckable );
|
|
||||||
item->setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsUserCheckable | Qt::ItemNeverHasChildren);
|
item->setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsUserCheckable | Qt::ItemNeverHasChildren);
|
||||||
|
|
||||||
item->setCheckState(0, s ? Qt::Checked : Qt::Unchecked);
|
item->setCheckState(0, s ? Qt::Checked : Qt::Unchecked);
|
||||||
|
|
||||||
item->setText(0, tr(codeStr));
|
item->setText(0, tr(codeStr));
|
||||||
|
@ -738,8 +733,6 @@ void GuiCheatsDialog_t::showActiveCheatList(bool redraw)
|
||||||
|
|
||||||
enaCheats->setChecked(!globalCheatDisabled);
|
enaCheats->setChecked(!globalCheatDisabled);
|
||||||
|
|
||||||
actvCheatRedraw = redraw;
|
|
||||||
|
|
||||||
if (redraw)
|
if (redraw)
|
||||||
{
|
{
|
||||||
actvCheatList->clear();
|
actvCheatList->clear();
|
||||||
|
@ -747,6 +740,8 @@ void GuiCheatsDialog_t::showActiveCheatList(bool redraw)
|
||||||
actvCheatIdx = 0;
|
actvCheatIdx = 0;
|
||||||
|
|
||||||
FCEUI_ListCheats(::activeCheatListCB, (void *)this);
|
FCEUI_ListCheats(::activeCheatListCB, (void *)this);
|
||||||
|
|
||||||
|
actvCheatList->viewport()->update();
|
||||||
}
|
}
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
void GuiCheatsDialog_t::openCheatFile(void)
|
void GuiCheatsDialog_t::openCheatFile(void)
|
||||||
|
|
|
@ -72,7 +72,6 @@ protected:
|
||||||
|
|
||||||
int fontCharWidth;
|
int fontCharWidth;
|
||||||
int actvCheatIdx;
|
int actvCheatIdx;
|
||||||
bool actvCheatRedraw;
|
|
||||||
bool pauseWhileActive;
|
bool pauseWhileActive;
|
||||||
bool wasPausedByCheats;
|
bool wasPausedByCheats;
|
||||||
|
|
||||||
|
|
|
@ -63,7 +63,6 @@ int openCDLWindow( QWidget *parent )
|
||||||
{
|
{
|
||||||
cdlWin->activateWindow();
|
cdlWin->activateWindow();
|
||||||
cdlWin->raise();
|
cdlWin->raise();
|
||||||
cdlWin->setFocus();
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
|
@ -172,7 +172,7 @@ ConsoleDebugger::ConsoleDebugger(QWidget *parent)
|
||||||
|
|
||||||
loadDisplayViews();
|
loadDisplayViews();
|
||||||
|
|
||||||
windowUpdateReq = true;
|
windowUpdateReq = QAsmView::UPDATE_ALL;
|
||||||
|
|
||||||
dbgWin = this;
|
dbgWin = this;
|
||||||
|
|
||||||
|
@ -373,7 +373,7 @@ void ConsoleDebugger::ld65ImportDebug(void)
|
||||||
|
|
||||||
debugSymbolTable.ld65LoadDebugFile( filename.toStdString().c_str() );
|
debugSymbolTable.ld65LoadDebugFile( filename.toStdString().c_str() );
|
||||||
|
|
||||||
queueUpdate();
|
queueUpdate(QAsmView::UPDATE_ALL);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -1834,28 +1834,26 @@ void ConsoleDebugger::selBmAddrChanged(const QString &txt)
|
||||||
//printf("selBmAddrVal = %04X\n", selBmAddrVal );
|
//printf("selBmAddrVal = %04X\n", selBmAddrVal );
|
||||||
}
|
}
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
void ConsoleDebugger::openBpEditWindow( int editIdx, watchpointinfo *wp, bool forceAccept )
|
DebuggerBreakpointEditor::DebuggerBreakpointEditor(int editIndex, watchpointinfo *wpIn, QWidget *parent)
|
||||||
|
: QDialog(parent)
|
||||||
{
|
{
|
||||||
int ret;
|
editIdx = editIndex;
|
||||||
QDialog dialog(this);
|
wp = wpIn;
|
||||||
|
|
||||||
QHBoxLayout *hbox;
|
QHBoxLayout *hbox;
|
||||||
QVBoxLayout *mainLayout, *vbox;
|
QVBoxLayout *mainLayout, *vbox;
|
||||||
QLabel *lbl;
|
QLabel *lbl;
|
||||||
QLineEdit *addr1, *addr2, *cond, *name;
|
|
||||||
QCheckBox *forbidChkBox, *rbp, *wbp, *xbp, *ebp;
|
|
||||||
QGridLayout *grid;
|
QGridLayout *grid;
|
||||||
QFrame *frame;
|
QFrame *frame;
|
||||||
QGroupBox *gbox;
|
QGroupBox *gbox;
|
||||||
QPushButton *okButton, *cancelButton;
|
|
||||||
QRadioButton *cpu_radio, *ppu_radio, *oam_radio, *rom_radio;
|
|
||||||
|
|
||||||
if ( editIdx >= 0 )
|
if ( editIdx >= 0 )
|
||||||
{
|
{
|
||||||
dialog.setWindowTitle( tr("Edit Breakpoint") );
|
setWindowTitle( tr("Edit Breakpoint") );
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
dialog.setWindowTitle( tr("Add Breakpoint") );
|
setWindowTitle( tr("Add Breakpoint") );
|
||||||
}
|
}
|
||||||
|
|
||||||
hbox = new QHBoxLayout();
|
hbox = new QHBoxLayout();
|
||||||
|
@ -1874,6 +1872,9 @@ void ConsoleDebugger::openBpEditWindow( int editIdx, watchpointinfo *wp, bool fo
|
||||||
hbox->addWidget( lbl );
|
hbox->addWidget( lbl );
|
||||||
hbox->addWidget( addr2 );
|
hbox->addWidget( addr2 );
|
||||||
|
|
||||||
|
connect( addr1, SIGNAL(textChanged(const QString &)), this, SLOT(addressTextChanged(const QString &)));
|
||||||
|
connect( addr2, SIGNAL(textChanged(const QString &)), this, SLOT(addressTextChanged(const QString &)));
|
||||||
|
|
||||||
forbidChkBox = new QCheckBox( tr("Forbid") );
|
forbidChkBox = new QCheckBox( tr("Forbid") );
|
||||||
hbox->addWidget( forbidChkBox );
|
hbox->addWidget( forbidChkBox );
|
||||||
|
|
||||||
|
@ -1906,6 +1907,11 @@ void ConsoleDebugger::openBpEditWindow( int editIdx, watchpointinfo *wp, bool fo
|
||||||
rom_radio = new QRadioButton( tr("ROM") );
|
rom_radio = new QRadioButton( tr("ROM") );
|
||||||
cpu_radio->setChecked(true);
|
cpu_radio->setChecked(true);
|
||||||
|
|
||||||
|
connect( cpu_radio, SIGNAL(toggled(bool)), this, SLOT(typeChanged(bool)));
|
||||||
|
connect( ppu_radio, SIGNAL(toggled(bool)), this, SLOT(typeChanged(bool)));
|
||||||
|
connect( oam_radio, SIGNAL(toggled(bool)), this, SLOT(typeChanged(bool)));
|
||||||
|
connect( rom_radio, SIGNAL(toggled(bool)), this, SLOT(typeChanged(bool)));
|
||||||
|
|
||||||
gbox->setLayout( hbox );
|
gbox->setLayout( hbox );
|
||||||
hbox->addWidget( cpu_radio );
|
hbox->addWidget( cpu_radio );
|
||||||
hbox->addWidget( ppu_radio );
|
hbox->addWidget( ppu_radio );
|
||||||
|
@ -1917,6 +1923,9 @@ void ConsoleDebugger::openBpEditWindow( int editIdx, watchpointinfo *wp, bool fo
|
||||||
mainLayout->addLayout( grid );
|
mainLayout->addLayout( grid );
|
||||||
lbl = new QLabel( tr("Condition") );
|
lbl = new QLabel( tr("Condition") );
|
||||||
cond = new QLineEdit();
|
cond = new QLineEdit();
|
||||||
|
condValid = true;
|
||||||
|
|
||||||
|
connect( cond, SIGNAL(textChanged(const QString &)), this, SLOT(conditionTextChanged(const QString &)));
|
||||||
|
|
||||||
grid->addWidget( lbl, 0, 0 );
|
grid->addWidget( lbl, 0, 0 );
|
||||||
grid->addWidget( cond, 0, 1 );
|
grid->addWidget( cond, 0, 1 );
|
||||||
|
@ -1928,15 +1937,17 @@ void ConsoleDebugger::openBpEditWindow( int editIdx, watchpointinfo *wp, bool fo
|
||||||
grid->addWidget( name, 1, 1 );
|
grid->addWidget( name, 1, 1 );
|
||||||
|
|
||||||
hbox = new QHBoxLayout();
|
hbox = new QHBoxLayout();
|
||||||
|
msgLbl = new QLabel();
|
||||||
okButton = new QPushButton( tr("OK") );
|
okButton = new QPushButton( tr("OK") );
|
||||||
cancelButton = new QPushButton( tr("Cancel") );
|
cancelButton = new QPushButton( tr("Cancel") );
|
||||||
|
|
||||||
mainLayout->addLayout( hbox );
|
mainLayout->addLayout( hbox );
|
||||||
hbox->addWidget( cancelButton );
|
hbox->addWidget( msgLbl, 5 );
|
||||||
hbox->addWidget( okButton );
|
hbox->addWidget( cancelButton, 1 );
|
||||||
|
hbox->addWidget( okButton, 1 );
|
||||||
|
|
||||||
connect( okButton, SIGNAL(clicked(void)), &dialog, SLOT(accept(void)) );
|
connect( okButton, SIGNAL(clicked(void)), this, SLOT(accept(void)) );
|
||||||
connect( cancelButton, SIGNAL(clicked(void)), &dialog, SLOT(reject(void)) );
|
connect( cancelButton, SIGNAL(clicked(void)), this, SLOT(reject(void)) );
|
||||||
|
|
||||||
okButton->setIcon( style()->standardIcon( QStyle::SP_DialogOkButton ) );
|
okButton->setIcon( style()->standardIcon( QStyle::SP_DialogOkButton ) );
|
||||||
cancelButton->setIcon( style()->standardIcon( QStyle::SP_DialogCancelButton ) );
|
cancelButton->setIcon( style()->standardIcon( QStyle::SP_DialogCancelButton ) );
|
||||||
|
@ -2036,99 +2047,270 @@ void ConsoleDebugger::openBpEditWindow( int editIdx, watchpointinfo *wp, bool fo
|
||||||
ebp->setChecked(true);
|
ebp->setChecked(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
dialog.setLayout( mainLayout );
|
setLayout( mainLayout );
|
||||||
|
|
||||||
|
connect( this , SIGNAL(finished(int)), this, SLOT(closeWindow(int)) );
|
||||||
|
}
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
DebuggerBreakpointEditor::~DebuggerBreakpointEditor(void)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
void DebuggerBreakpointEditor::closeEvent(QCloseEvent *event)
|
||||||
|
{
|
||||||
|
//printf("Close Window Event\n");
|
||||||
|
done(QDialog::Rejected);
|
||||||
|
deleteLater();
|
||||||
|
event->accept();
|
||||||
|
}
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
void DebuggerBreakpointEditor::closeWindow(int ret)
|
||||||
|
{
|
||||||
|
//printf("Close Window %i\n", ret);
|
||||||
|
if ( ret == QDialog::Accepted )
|
||||||
|
{
|
||||||
|
loadBreakpoint();
|
||||||
|
}
|
||||||
|
deleteLater();
|
||||||
|
}
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
void DebuggerBreakpointEditor::checkDataValid(void)
|
||||||
|
{
|
||||||
|
int type = 0;
|
||||||
|
bool startAddrValid = false;
|
||||||
|
bool endAddrValid = false;
|
||||||
|
bool allEntriesValid = false;
|
||||||
|
int addrLowerBound = 0;
|
||||||
|
int addrUpperBound = 0;
|
||||||
|
int start_addr = 0, end_addr = 0;
|
||||||
|
|
||||||
|
if ( cpu_radio->isChecked() )
|
||||||
|
{
|
||||||
|
type |= BT_C;
|
||||||
|
addrLowerBound = 0;
|
||||||
|
addrUpperBound = 0x10000;
|
||||||
|
}
|
||||||
|
else if ( ppu_radio->isChecked() )
|
||||||
|
{
|
||||||
|
type |= BT_P;
|
||||||
|
addrLowerBound = 0;
|
||||||
|
addrUpperBound = 0x4000;
|
||||||
|
}
|
||||||
|
else if ( oam_radio->isChecked() )
|
||||||
|
{
|
||||||
|
type |= BT_S;
|
||||||
|
addrLowerBound = 0;
|
||||||
|
addrUpperBound = 0x100;
|
||||||
|
}
|
||||||
|
else if ( rom_radio->isChecked() )
|
||||||
|
{
|
||||||
|
type |= BT_R;
|
||||||
|
addrLowerBound = 0;
|
||||||
|
addrUpperBound = 0x10000;
|
||||||
|
|
||||||
|
if (GameInfo != nullptr)
|
||||||
|
{
|
||||||
|
addrUpperBound = 16+PRGsize[0]+CHRsize[0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( addr1->text().size() > 0 )
|
||||||
|
{
|
||||||
|
bool convOk = false;
|
||||||
|
|
||||||
|
start_addr = offsetStringToInt( type, addr1->text().toStdString().c_str(), &convOk );
|
||||||
|
|
||||||
|
//printf("StartAddr:0x%04X Upper:0x%04X\n", start_addr, addrUpperBound);
|
||||||
|
startAddrValid = convOk && (start_addr >= addrLowerBound) && (start_addr < addrUpperBound);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
startAddrValid = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( addr2->text().size() > 0 )
|
||||||
|
{
|
||||||
|
bool convOk = false;
|
||||||
|
|
||||||
|
end_addr = offsetStringToInt( type, addr2->text().toStdString().c_str(), &convOk );
|
||||||
|
|
||||||
|
endAddrValid = convOk && (end_addr >= addrLowerBound) &&
|
||||||
|
(end_addr < addrUpperBound) && (start_addr < end_addr);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
endAddrValid = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
allEntriesValid = startAddrValid && endAddrValid && condValid;
|
||||||
|
|
||||||
|
okButton->setEnabled( allEntriesValid );
|
||||||
|
|
||||||
|
if (allEntriesValid)
|
||||||
|
{
|
||||||
|
msgLbl->clear();
|
||||||
|
}
|
||||||
|
else if (!startAddrValid)
|
||||||
|
{
|
||||||
|
msgLbl->setText(tr("Start Address Invalid"));
|
||||||
|
}
|
||||||
|
else if (!endAddrValid)
|
||||||
|
{
|
||||||
|
msgLbl->setText(tr("End Address Invalid"));
|
||||||
|
}
|
||||||
|
else if (!condValid)
|
||||||
|
{
|
||||||
|
msgLbl->setText(tr("Condition Invalid"));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
msgLbl->clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
void DebuggerBreakpointEditor::typeChanged(bool checked)
|
||||||
|
{
|
||||||
|
if (checked)
|
||||||
|
{
|
||||||
|
checkDataValid();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
void DebuggerBreakpointEditor::addressTextChanged(const QString &txt)
|
||||||
|
{
|
||||||
|
checkDataValid();
|
||||||
|
}
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
void DebuggerBreakpointEditor::conditionTextChanged(const QString &txt)
|
||||||
|
{
|
||||||
|
if ( txt.size() > 0 )
|
||||||
|
{
|
||||||
|
Condition *c = generateCondition( txt.toStdString().c_str() );
|
||||||
|
|
||||||
|
condValid = (c != nullptr);
|
||||||
|
|
||||||
|
if (c)
|
||||||
|
{
|
||||||
|
delete c; c = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
condValid = true;
|
||||||
|
}
|
||||||
|
checkDataValid();
|
||||||
|
}
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
void DebuggerBreakpointEditor::loadBreakpoint(void)
|
||||||
|
{
|
||||||
|
int start_addr = -1, end_addr = -1, type = 0, enable = 1, slot;
|
||||||
|
std::string s;
|
||||||
|
|
||||||
|
FCEU_WRAPPER_LOCK();
|
||||||
|
|
||||||
|
slot = (editIdx < 0) ? numWPs : editIdx;
|
||||||
|
|
||||||
|
if ( cpu_radio->isChecked() )
|
||||||
|
{
|
||||||
|
type |= BT_C;
|
||||||
|
}
|
||||||
|
else if ( ppu_radio->isChecked() )
|
||||||
|
{
|
||||||
|
type |= BT_P;
|
||||||
|
}
|
||||||
|
else if ( oam_radio->isChecked() )
|
||||||
|
{
|
||||||
|
type |= BT_S;
|
||||||
|
}
|
||||||
|
else if ( rom_radio->isChecked() )
|
||||||
|
{
|
||||||
|
type |= BT_R;
|
||||||
|
}
|
||||||
|
|
||||||
|
s = addr1->text().toStdString();
|
||||||
|
|
||||||
|
if ( s.size() > 0 )
|
||||||
|
{
|
||||||
|
start_addr = offsetStringToInt( type, s.c_str() );
|
||||||
|
}
|
||||||
|
|
||||||
|
s = addr2->text().toStdString();
|
||||||
|
|
||||||
|
if ( s.size() > 0 )
|
||||||
|
{
|
||||||
|
end_addr = offsetStringToInt( type, s.c_str() );
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( rbp->isChecked() )
|
||||||
|
{
|
||||||
|
type |= WP_R;
|
||||||
|
}
|
||||||
|
if ( wbp->isChecked() )
|
||||||
|
{
|
||||||
|
type |= WP_W;
|
||||||
|
}
|
||||||
|
if ( xbp->isChecked() )
|
||||||
|
{
|
||||||
|
type |= WP_X;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( forbidChkBox->isChecked() )
|
||||||
|
{
|
||||||
|
type |= WP_F;
|
||||||
|
}
|
||||||
|
|
||||||
|
enable = ebp->isChecked();
|
||||||
|
|
||||||
|
if ( (start_addr >= 0) && (numWPs < 64) )
|
||||||
|
{
|
||||||
|
unsigned int retval;
|
||||||
|
std::string nameString, condString;
|
||||||
|
|
||||||
|
nameString = name->text().toStdString();
|
||||||
|
condString = cond->text().toStdString();
|
||||||
|
|
||||||
|
retval = NewBreak( nameString.c_str(), start_addr, end_addr, type, condString.c_str(), slot, enable);
|
||||||
|
|
||||||
|
if ( (retval == 1) || (retval == 2) )
|
||||||
|
{
|
||||||
|
printf("Breakpoint Add Failed\n");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (editIdx < 0)
|
||||||
|
{
|
||||||
|
numWPs++;
|
||||||
|
}
|
||||||
|
|
||||||
|
//bpListUpdate( false );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
FCEU_WRAPPER_UNLOCK();
|
||||||
|
}
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
//int editIndex, watchpointinfo *wp, bool forceAccept,
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
void ConsoleDebugger::openBpEditWindow( int editIdx, watchpointinfo *wp, bool forceAccept )
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
DebuggerBreakpointEditor *dialog = new DebuggerBreakpointEditor( editIdx, wp, this );
|
||||||
|
|
||||||
if ( forceAccept )
|
if ( forceAccept )
|
||||||
{
|
{
|
||||||
|
dialog->loadBreakpoint();
|
||||||
|
dialog->deleteLater();
|
||||||
ret = QDialog::Accepted;
|
ret = QDialog::Accepted;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
ret = dialog.exec();
|
ret = dialog->exec();
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( ret == QDialog::Accepted )
|
if (ret == QDialog::Accepted)
|
||||||
{
|
{
|
||||||
int start_addr = -1, end_addr = -1, type = 0, enable = 1, slot;
|
bpListUpdate( false );
|
||||||
std::string s;
|
|
||||||
|
|
||||||
slot = (editIdx < 0) ? numWPs : editIdx;
|
|
||||||
|
|
||||||
if ( cpu_radio->isChecked() )
|
|
||||||
{
|
|
||||||
type |= BT_C;
|
|
||||||
}
|
|
||||||
else if ( ppu_radio->isChecked() )
|
|
||||||
{
|
|
||||||
type |= BT_P;
|
|
||||||
}
|
|
||||||
else if ( oam_radio->isChecked() )
|
|
||||||
{
|
|
||||||
type |= BT_S;
|
|
||||||
}
|
|
||||||
else if ( rom_radio->isChecked() )
|
|
||||||
{
|
|
||||||
type |= BT_R;
|
|
||||||
}
|
|
||||||
|
|
||||||
s = addr1->text().toStdString();
|
|
||||||
|
|
||||||
if ( s.size() > 0 )
|
|
||||||
{
|
|
||||||
start_addr = offsetStringToInt( type, s.c_str() );
|
|
||||||
}
|
|
||||||
|
|
||||||
s = addr2->text().toStdString();
|
|
||||||
|
|
||||||
if ( s.size() > 0 )
|
|
||||||
{
|
|
||||||
end_addr = offsetStringToInt( type, s.c_str() );
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( rbp->isChecked() )
|
|
||||||
{
|
|
||||||
type |= WP_R;
|
|
||||||
}
|
|
||||||
if ( wbp->isChecked() )
|
|
||||||
{
|
|
||||||
type |= WP_W;
|
|
||||||
}
|
|
||||||
if ( xbp->isChecked() )
|
|
||||||
{
|
|
||||||
type |= WP_X;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( forbidChkBox->isChecked() )
|
|
||||||
{
|
|
||||||
type |= WP_F;
|
|
||||||
}
|
|
||||||
|
|
||||||
enable = ebp->isChecked();
|
|
||||||
|
|
||||||
if ( (start_addr >= 0) && (numWPs < 64) )
|
|
||||||
{
|
|
||||||
unsigned int retval;
|
|
||||||
std::string nameString, condString;
|
|
||||||
|
|
||||||
nameString = name->text().toStdString();
|
|
||||||
condString = cond->text().toStdString();
|
|
||||||
|
|
||||||
retval = NewBreak( nameString.c_str(), start_addr, end_addr, type, condString.c_str(), slot, enable);
|
|
||||||
|
|
||||||
if ( (retval == 1) || (retval == 2) )
|
|
||||||
{
|
|
||||||
printf("Breakpoint Add Failed\n");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (editIdx < 0)
|
|
||||||
{
|
|
||||||
numWPs++;
|
|
||||||
}
|
|
||||||
|
|
||||||
bpListUpdate( false );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
|
@ -2439,7 +2621,7 @@ static void DeleteBreak(int sel)
|
||||||
|
|
||||||
if (watchpoint[sel].cond)
|
if (watchpoint[sel].cond)
|
||||||
{
|
{
|
||||||
freeTree(watchpoint[sel].cond);
|
delete watchpoint[sel].cond;
|
||||||
}
|
}
|
||||||
if (watchpoint[sel].condText)
|
if (watchpoint[sel].condText)
|
||||||
{
|
{
|
||||||
|
@ -2488,7 +2670,7 @@ void debuggerClearAllBreakpoints(void)
|
||||||
{
|
{
|
||||||
if (watchpoint[i].cond)
|
if (watchpoint[i].cond)
|
||||||
{
|
{
|
||||||
freeTree(watchpoint[i].cond);
|
delete watchpoint[i].cond;
|
||||||
}
|
}
|
||||||
if (watchpoint[i].condText)
|
if (watchpoint[i].condText)
|
||||||
{
|
{
|
||||||
|
@ -2499,7 +2681,7 @@ void debuggerClearAllBreakpoints(void)
|
||||||
free(watchpoint[i].desc);
|
free(watchpoint[i].desc);
|
||||||
}
|
}
|
||||||
|
|
||||||
watchpoint[i].address = 0;
|
watchpoint[i].address = 0;
|
||||||
watchpoint[i].endaddress = 0;
|
watchpoint[i].endaddress = 0;
|
||||||
watchpoint[i].flags = 0;
|
watchpoint[i].flags = 0;
|
||||||
watchpoint[i].cond = 0;
|
watchpoint[i].cond = 0;
|
||||||
|
@ -2898,7 +3080,7 @@ void ConsoleDebugger::debugStepBackCB(void)
|
||||||
{
|
{
|
||||||
FCEU_WRAPPER_LOCK();
|
FCEU_WRAPPER_LOCK();
|
||||||
FCEUD_TraceLoggerBackUpInstruction();
|
FCEUD_TraceLoggerBackUpInstruction();
|
||||||
updateWindowData();
|
updateWindowData(QAsmView::UPDATE_ALL);
|
||||||
hexEditorUpdateMemoryValues(true);
|
hexEditorUpdateMemoryValues(true);
|
||||||
hexEditorRequestUpdateAll();
|
hexEditorRequestUpdateAll();
|
||||||
lastBpIdx = BREAK_TYPE_STEP;
|
lastBpIdx = BREAK_TYPE_STEP;
|
||||||
|
@ -3093,8 +3275,7 @@ void ConsoleDebugger::seekPCCB (void)
|
||||||
setRegsFromEntry();
|
setRegsFromEntry();
|
||||||
//updateAllDebugWindows();
|
//updateAllDebugWindows();
|
||||||
}
|
}
|
||||||
windowUpdateReq = true;
|
windowUpdateReq = QAsmView::UPDATE_ALL;
|
||||||
//asmView->scrollToPC();
|
|
||||||
}
|
}
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
void ConsoleDebugger::openChangePcDialog(void)
|
void ConsoleDebugger::openChangePcDialog(void)
|
||||||
|
@ -3148,7 +3329,7 @@ void ConsoleDebugger::openChangePcDialog(void)
|
||||||
{
|
{
|
||||||
X.PC = sbox->value();
|
X.PC = sbox->value();
|
||||||
|
|
||||||
windowUpdateReq = true;
|
windowUpdateReq = QAsmView::UPDATE_ALL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
|
@ -4142,20 +4323,25 @@ void ConsoleDebugger::updateRegisterView(void)
|
||||||
ppuScrollY->setText( tr(stmp) );
|
ppuScrollY->setText( tr(stmp) );
|
||||||
}
|
}
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
void ConsoleDebugger::updateWindowData(void)
|
void ConsoleDebugger::updateWindowData(enum QAsmView::UpdateType type)
|
||||||
{
|
{
|
||||||
asmView->updateAssemblyView();
|
if (type == QAsmView::UPDATE_ALL)
|
||||||
|
{
|
||||||
asmView->scrollToPC();
|
asmView->updateAssemblyView();
|
||||||
|
asmView->scrollToPC();
|
||||||
|
updateRegisterView();
|
||||||
|
} else if (type == QAsmView::UPDATE_NO_SCROLL)
|
||||||
|
{
|
||||||
|
asmView->updateAssemblyView();
|
||||||
|
updateRegisterView();
|
||||||
|
}
|
||||||
|
|
||||||
updateRegisterView();
|
windowUpdateReq = QAsmView::UPDATE_NONE;
|
||||||
|
|
||||||
windowUpdateReq = false;
|
|
||||||
}
|
}
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
void ConsoleDebugger::queueUpdate(void)
|
void ConsoleDebugger::queueUpdate(enum QAsmView::UpdateType type)
|
||||||
{
|
{
|
||||||
windowUpdateReq = true;
|
windowUpdateReq = type;
|
||||||
}
|
}
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
void ConsoleDebugger::updatePeriodic(void)
|
void ConsoleDebugger::updatePeriodic(void)
|
||||||
|
@ -4173,10 +4359,10 @@ void ConsoleDebugger::updatePeriodic(void)
|
||||||
bpNotifyReq = false;
|
bpNotifyReq = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( windowUpdateReq )
|
if ( windowUpdateReq != QAsmView::UPDATE_NONE )
|
||||||
{
|
{
|
||||||
FCEU_WRAPPER_LOCK();
|
FCEU_WRAPPER_LOCK();
|
||||||
updateWindowData();
|
updateWindowData(windowUpdateReq);
|
||||||
FCEU_WRAPPER_UNLOCK();
|
FCEU_WRAPPER_UNLOCK();
|
||||||
}
|
}
|
||||||
asmView->update();
|
asmView->update();
|
||||||
|
@ -4346,7 +4532,7 @@ void ConsoleDebugger::breakPointNotify( int bpNum )
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
windowUpdateReq = true;
|
windowUpdateReq = QAsmView::UPDATE_ALL;
|
||||||
}
|
}
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
void ConsoleDebugger::hbarChanged(int value)
|
void ConsoleDebugger::hbarChanged(int value)
|
||||||
|
@ -4461,7 +4647,6 @@ void debuggerWindowSetFocus(bool val)
|
||||||
{
|
{
|
||||||
dbgWin->activateWindow();
|
dbgWin->activateWindow();
|
||||||
dbgWin->raise();
|
dbgWin->raise();
|
||||||
dbgWin->setFocus();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
|
@ -4470,11 +4655,11 @@ bool debuggerWaitingAtBreakpoint(void)
|
||||||
return waitingAtBp;
|
return waitingAtBp;
|
||||||
}
|
}
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
void updateAllDebuggerWindows( void )
|
void updateAllDebuggerWindows( enum QAsmView::UpdateType type )
|
||||||
{
|
{
|
||||||
if ( dbgWin )
|
if ( dbgWin )
|
||||||
{
|
{
|
||||||
dbgWin->queueUpdate();
|
dbgWin->queueUpdate(type);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
|
|
|
@ -167,6 +167,8 @@ class QAsmView : public QWidget
|
||||||
|
|
||||||
QFont getFont(void){ return font; };
|
QFont getFont(void){ return font; };
|
||||||
|
|
||||||
|
enum UpdateType { UPDATE_NONE, UPDATE_ALL, UPDATE_NO_SCROLL };
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
bool event(QEvent *event) override;
|
bool event(QEvent *event) override;
|
||||||
void paintEvent(QPaintEvent *event) override;
|
void paintEvent(QPaintEvent *event) override;
|
||||||
|
@ -420,6 +422,51 @@ class DebugBreakOnDialog : public QDialog
|
||||||
void resetDeltas(void);
|
void resetDeltas(void);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class DebuggerBreakpointEditor : public QDialog
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
DebuggerBreakpointEditor(int editIndex = -1, watchpointinfo *wpIn = nullptr, QWidget *parent = 0);
|
||||||
|
~DebuggerBreakpointEditor(void);
|
||||||
|
|
||||||
|
void loadBreakpoint(void);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void closeEvent(QCloseEvent *event) override;
|
||||||
|
void checkDataValid(void);
|
||||||
|
|
||||||
|
private:
|
||||||
|
int editIdx;
|
||||||
|
watchpointinfo *wp;
|
||||||
|
|
||||||
|
QLineEdit *addr1;
|
||||||
|
QLineEdit *addr2;
|
||||||
|
QLineEdit *cond;
|
||||||
|
QLineEdit *name;
|
||||||
|
QCheckBox *forbidChkBox;
|
||||||
|
QCheckBox *rbp;
|
||||||
|
QCheckBox *wbp;
|
||||||
|
QCheckBox *xbp;
|
||||||
|
QCheckBox *ebp;
|
||||||
|
QLabel *msgLbl;
|
||||||
|
|
||||||
|
QPushButton *okButton;
|
||||||
|
QPushButton *cancelButton;
|
||||||
|
QRadioButton *cpu_radio;
|
||||||
|
QRadioButton *ppu_radio;
|
||||||
|
QRadioButton *oam_radio;
|
||||||
|
QRadioButton *rom_radio;
|
||||||
|
|
||||||
|
bool condValid;
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void closeWindow(int ret);
|
||||||
|
void typeChanged(bool checked);
|
||||||
|
void addressTextChanged( const QString &text );
|
||||||
|
void conditionTextChanged( const QString &text );
|
||||||
|
};
|
||||||
|
|
||||||
class ConsoleDebugger : public QDialog
|
class ConsoleDebugger : public QDialog
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
@ -428,7 +475,7 @@ class ConsoleDebugger : public QDialog
|
||||||
ConsoleDebugger(QWidget *parent = 0);
|
ConsoleDebugger(QWidget *parent = 0);
|
||||||
~ConsoleDebugger(void);
|
~ConsoleDebugger(void);
|
||||||
|
|
||||||
void updateWindowData(void);
|
void updateWindowData(enum QAsmView::UpdateType type);
|
||||||
void updateRegisterView(void);
|
void updateRegisterView(void);
|
||||||
void updateTabVisibility(void);
|
void updateTabVisibility(void);
|
||||||
void breakPointNotify(int bpNum);
|
void breakPointNotify(int bpNum);
|
||||||
|
@ -437,7 +484,7 @@ class ConsoleDebugger : public QDialog
|
||||||
void setBookmarkSelectedAddress( int addr );
|
void setBookmarkSelectedAddress( int addr );
|
||||||
int getBookmarkSelectedAddress(void){ return selBmAddrVal; };
|
int getBookmarkSelectedAddress(void){ return selBmAddrVal; };
|
||||||
void edit_BM_name( int addr );
|
void edit_BM_name( int addr );
|
||||||
void queueUpdate(void);
|
void queueUpdate(enum QAsmView::UpdateType type);
|
||||||
|
|
||||||
QLabel *asmLineSelLbl;
|
QLabel *asmLineSelLbl;
|
||||||
|
|
||||||
|
@ -530,7 +577,8 @@ class ConsoleDebugger : public QDialog
|
||||||
ColorMenuItem *pcColorAct;
|
ColorMenuItem *pcColorAct;
|
||||||
|
|
||||||
int selBmAddrVal;
|
int selBmAddrVal;
|
||||||
bool windowUpdateReq;
|
enum QAsmView::UpdateType windowUpdateReq;
|
||||||
|
|
||||||
bool startedTraceLogger;
|
bool startedTraceLogger;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -625,6 +673,6 @@ void saveGameDebugBreakpoints( bool force = false );
|
||||||
void loadGameDebugBreakpoints(void);
|
void loadGameDebugBreakpoints(void);
|
||||||
void debuggerClearAllBreakpoints(void);
|
void debuggerClearAllBreakpoints(void);
|
||||||
void debuggerClearAllBookmarks(void);
|
void debuggerClearAllBookmarks(void);
|
||||||
void updateAllDebuggerWindows(void);
|
void updateAllDebuggerWindows(enum QAsmView::UpdateType type);
|
||||||
|
|
||||||
extern debuggerBookmarkManager_t dbgBmMgr;
|
extern debuggerBookmarkManager_t dbgBmMgr;
|
||||||
|
|
|
@ -2388,7 +2388,7 @@ void consoleWin_t::openROMFile(void)
|
||||||
QDir d;
|
QDir d;
|
||||||
|
|
||||||
const QStringList filters(
|
const QStringList filters(
|
||||||
{ "All Useable files (*.nes *.NES *.nsf *.NSF *.fds *.FDS *.unf *.UNF *.unif *.UNIF *.zip *.ZIP)",
|
{ "All Useable files (*.nes *.NES *.nsf *.NSF *.fds *.FDS *.unf *.UNF *.unif *.UNIF *.zip *.ZIP, *.7z *.7zip)",
|
||||||
"NES files (*.nes *.NES)",
|
"NES files (*.nes *.NES)",
|
||||||
"NSF files (*.nsf *.NSF)",
|
"NSF files (*.nsf *.NSF)",
|
||||||
"UNF files (*.unf *.UNF *.unif *.UNIF)",
|
"UNF files (*.unf *.UNF *.unif *.UNIF)",
|
||||||
|
@ -2758,14 +2758,14 @@ void consoleWin_t::loadState9(void){ loadState(9); }
|
||||||
void consoleWin_t::loadPrevState(void)
|
void consoleWin_t::loadPrevState(void)
|
||||||
{
|
{
|
||||||
FCEU_WRAPPER_LOCK();
|
FCEU_WRAPPER_LOCK();
|
||||||
FCEU_StateRecorderLoadState( FCEU_StateRecorderGetStateIndex()-1 );
|
FCEU_StateRecorderLoadPrevState();
|
||||||
FCEU_WRAPPER_UNLOCK();
|
FCEU_WRAPPER_UNLOCK();
|
||||||
}
|
}
|
||||||
|
|
||||||
void consoleWin_t::loadNextState(void)
|
void consoleWin_t::loadNextState(void)
|
||||||
{
|
{
|
||||||
FCEU_WRAPPER_LOCK();
|
FCEU_WRAPPER_LOCK();
|
||||||
FCEU_StateRecorderLoadState( FCEU_StateRecorderGetStateIndex()-1 );
|
FCEU_StateRecorderLoadNextState();
|
||||||
FCEU_WRAPPER_UNLOCK();
|
FCEU_WRAPPER_UNLOCK();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -126,7 +126,6 @@ int openFamilyKeyboardDialog(QWidget *parent)
|
||||||
{
|
{
|
||||||
fkbWin->activateWindow();
|
fkbWin->activateWindow();
|
||||||
fkbWin->raise();
|
fkbWin->raise();
|
||||||
fkbWin->setFocus();
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
|
@ -42,6 +42,7 @@
|
||||||
#include "Qt/config.h"
|
#include "Qt/config.h"
|
||||||
#include "Qt/keyscan.h"
|
#include "Qt/keyscan.h"
|
||||||
#include "Qt/fceuWrapper.h"
|
#include "Qt/fceuWrapper.h"
|
||||||
|
#include "Qt/CheatsConf.h"
|
||||||
#include "Qt/HexEditor.h"
|
#include "Qt/HexEditor.h"
|
||||||
#include "Qt/GameGenie.h"
|
#include "Qt/GameGenie.h"
|
||||||
|
|
||||||
|
@ -278,6 +279,7 @@ void GameGenieDialog_t::addCheatClicked(void)
|
||||||
|
|
||||||
FCEU_WRAPPER_LOCK();
|
FCEU_WRAPPER_LOCK();
|
||||||
FCEUI_AddCheat( name.c_str(), a, v, c, 1 );
|
FCEUI_AddCheat( name.c_str(), a, v, c, 1 );
|
||||||
|
updateCheatDialog();
|
||||||
FCEU_WRAPPER_UNLOCK();
|
FCEU_WRAPPER_UNLOCK();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -399,7 +399,7 @@ static int writeMem( int mode, unsigned int addr, int value )
|
||||||
{
|
{
|
||||||
if (debuggerWindowIsOpen())
|
if (debuggerWindowIsOpen())
|
||||||
{
|
{
|
||||||
updateAllDebuggerWindows();
|
updateAllDebuggerWindows(QAsmView::UPDATE_NO_SCROLL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1853,7 +1853,7 @@ void HexEditorDialog_t::openDebugSymbolEditWindow( int addr )
|
||||||
|
|
||||||
if ( ret == QDialog::Accepted )
|
if ( ret == QDialog::Accepted )
|
||||||
{
|
{
|
||||||
updateAllDebuggerWindows();
|
updateAllDebuggerWindows(QAsmView::UPDATE_NO_SCROLL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
|
@ -2777,7 +2777,13 @@ void QHexEdit::keyPressEvent(QKeyEvent *event)
|
||||||
event->accept();
|
event->accept();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{ // Use the input text to modify the values in the editor area.
|
||||||
|
|
||||||
|
if (event->text().isEmpty())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
int key;
|
int key;
|
||||||
if ( cursorPosX >= 32 )
|
if ( cursorPosX >= 32 )
|
||||||
{ // Edit Area is ASCII
|
{ // Edit Area is ASCII
|
||||||
|
@ -2830,6 +2836,7 @@ void QHexEdit::keyPressEvent(QKeyEvent *event)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{ // Edit Area is Hex
|
{ // Edit Area is Hex
|
||||||
|
|
||||||
key = int(event->text()[0].toUpper().toLatin1());
|
key = int(event->text()[0].toUpper().toLatin1());
|
||||||
|
|
||||||
if ( ::isxdigit( key ) )
|
if ( ::isxdigit( key ) )
|
||||||
|
@ -4222,7 +4229,6 @@ int hexEditorOpenFromDebugger( int mode, int addr )
|
||||||
{
|
{
|
||||||
win->activateWindow();
|
win->activateWindow();
|
||||||
win->raise();
|
win->raise();
|
||||||
win->setFocus();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
win->editor->setMode( mode );
|
win->editor->setMode( mode );
|
||||||
|
|
|
@ -108,7 +108,6 @@ int openNameTableViewWindow( QWidget *parent )
|
||||||
{
|
{
|
||||||
nameTableViewWindow->activateWindow();
|
nameTableViewWindow->activateWindow();
|
||||||
nameTableViewWindow->raise();
|
nameTableViewWindow->raise();
|
||||||
nameTableViewWindow->setFocus();
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
initNameTableViewer();
|
initNameTableViewer();
|
||||||
|
|
|
@ -27,22 +27,25 @@
|
||||||
#include <QCloseEvent>
|
#include <QCloseEvent>
|
||||||
#include <QGridLayout>
|
#include <QGridLayout>
|
||||||
#include <QSettings>
|
#include <QSettings>
|
||||||
|
#include <QMessageBox>
|
||||||
|
|
||||||
|
#include "Qt/throttle.h"
|
||||||
#include "Qt/fceuWrapper.h"
|
#include "Qt/fceuWrapper.h"
|
||||||
#include "Qt/StateRecorderConf.h"
|
#include "Qt/StateRecorderConf.h"
|
||||||
|
|
||||||
#include "../../fceu.h"
|
#include "../../fceu.h"
|
||||||
#include "../../state.h"
|
#include "../../state.h"
|
||||||
|
#include "../../driver.h"
|
||||||
#include "../../emufile.h"
|
#include "../../emufile.h"
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
StateRecorderDialog_t::StateRecorderDialog_t(QWidget *parent)
|
StateRecorderDialog_t::StateRecorderDialog_t(QWidget *parent)
|
||||||
: QDialog(parent)
|
: QDialog(parent)
|
||||||
{
|
{
|
||||||
QVBoxLayout *mainLayout;
|
QVBoxLayout *mainLayout, *vbox1;
|
||||||
QHBoxLayout *hbox, *hbox1;
|
QHBoxLayout *hbox, *hbox1;
|
||||||
QGroupBox *frame, *frame1;
|
QGroupBox *frame, *frame1;
|
||||||
QGridLayout *grid, *memStatsGrid;
|
QGridLayout *grid, *memStatsGrid, *sysStatusGrid;
|
||||||
QSettings settings;
|
QSettings settings;
|
||||||
int opt;
|
int opt;
|
||||||
|
|
||||||
|
@ -52,14 +55,19 @@ StateRecorderDialog_t::StateRecorderDialog_t(QWidget *parent)
|
||||||
grid = new QGridLayout();
|
grid = new QGridLayout();
|
||||||
|
|
||||||
recorderEnable = new QCheckBox(tr("Auto Start Recorder at ROM Load"));
|
recorderEnable = new QCheckBox(tr("Auto Start Recorder at ROM Load"));
|
||||||
|
snapFrames = new QSpinBox();
|
||||||
snapMinutes = new QSpinBox();
|
snapMinutes = new QSpinBox();
|
||||||
snapSeconds = new QSpinBox();
|
snapSeconds = new QSpinBox();
|
||||||
historyDuration = new QSpinBox();
|
historyDuration = new QSpinBox();
|
||||||
|
snapFrameSelBtn = new QRadioButton( tr("By Frames") );
|
||||||
|
snapTimeSelBtn = new QRadioButton( tr("By Time") );
|
||||||
|
|
||||||
recorderEnable->setChecked( FCEU_StateRecorderIsEnabled() );
|
recorderEnable->setChecked( FCEU_StateRecorderIsEnabled() );
|
||||||
|
|
||||||
connect( recorderEnable, SIGNAL(stateChanged(int)), this, SLOT(enableChanged(int)) );
|
connect( recorderEnable, SIGNAL(stateChanged(int)), this, SLOT(enableChanged(int)) );
|
||||||
|
|
||||||
|
snapFrames->setMinimum(1);
|
||||||
|
snapFrames->setMaximum(10000);
|
||||||
snapSeconds->setMinimum(0);
|
snapSeconds->setMinimum(0);
|
||||||
snapSeconds->setMaximum(60);
|
snapSeconds->setMaximum(60);
|
||||||
snapMinutes->setMinimum(0);
|
snapMinutes->setMinimum(0);
|
||||||
|
@ -67,6 +75,10 @@ StateRecorderDialog_t::StateRecorderDialog_t(QWidget *parent)
|
||||||
historyDuration->setMinimum(1);
|
historyDuration->setMinimum(1);
|
||||||
historyDuration->setMaximum(180);
|
historyDuration->setMaximum(180);
|
||||||
|
|
||||||
|
opt = 10;
|
||||||
|
g_config->getOption("SDL.StateRecorderFramesBetweenSnaps", &opt);
|
||||||
|
snapFrames->setValue(opt);
|
||||||
|
|
||||||
opt = 15;
|
opt = 15;
|
||||||
g_config->getOption("SDL.StateRecorderHistoryDurationMin", &opt );
|
g_config->getOption("SDL.StateRecorderHistoryDurationMin", &opt );
|
||||||
historyDuration->setValue(opt);
|
historyDuration->setValue(opt);
|
||||||
|
@ -79,6 +91,14 @@ StateRecorderDialog_t::StateRecorderDialog_t(QWidget *parent)
|
||||||
g_config->getOption("SDL.StateRecorderTimeBetweenSnapsSec", &opt);
|
g_config->getOption("SDL.StateRecorderTimeBetweenSnapsSec", &opt);
|
||||||
snapSeconds->setValue(opt);
|
snapSeconds->setValue(opt);
|
||||||
|
|
||||||
|
opt = 0;
|
||||||
|
g_config->getOption("SDL.StateRecorderTimingMode", &opt);
|
||||||
|
|
||||||
|
snapFrameSelBtn->setChecked(opt == 0);
|
||||||
|
snapTimeSelBtn->setChecked(opt == 1);
|
||||||
|
snapUseTime = opt ? true : false;
|
||||||
|
|
||||||
|
connect( snapFrames , SIGNAL(valueChanged(int)), this, SLOT(spinBoxValueChanged(int)) );
|
||||||
connect( snapSeconds, SIGNAL(valueChanged(int)), this, SLOT(spinBoxValueChanged(int)) );
|
connect( snapSeconds, SIGNAL(valueChanged(int)), this, SLOT(spinBoxValueChanged(int)) );
|
||||||
connect( snapMinutes, SIGNAL(valueChanged(int)), this, SLOT(spinBoxValueChanged(int)) );
|
connect( snapMinutes, SIGNAL(valueChanged(int)), this, SLOT(spinBoxValueChanged(int)) );
|
||||||
connect( historyDuration, SIGNAL(valueChanged(int)), this, SLOT(spinBoxValueChanged(int)) );
|
connect( historyDuration, SIGNAL(valueChanged(int)), this, SLOT(spinBoxValueChanged(int)) );
|
||||||
|
@ -113,16 +133,38 @@ StateRecorderDialog_t::StateRecorderDialog_t(QWidget *parent)
|
||||||
g_config->getOption("SDL.StateRecorderCompressionLevel", &opt);
|
g_config->getOption("SDL.StateRecorderCompressionLevel", &opt);
|
||||||
cmprLvlCbox->setCurrentIndex(opt);
|
cmprLvlCbox->setCurrentIndex(opt);
|
||||||
|
|
||||||
|
connect( cmprLvlCbox, SIGNAL(currentIndexChanged(int)), this, SLOT(compressionLevelChanged(int)) );
|
||||||
|
|
||||||
hbox->addWidget(cmprLvlCbox);
|
hbox->addWidget(cmprLvlCbox);
|
||||||
|
|
||||||
frame->setLayout(hbox);
|
frame->setLayout(hbox);
|
||||||
grid->addWidget( frame, 1, 1 );
|
grid->addWidget( frame, 1, 1 );
|
||||||
|
|
||||||
frame1 = new QGroupBox(tr("Time Between Snapshots:"));
|
frame1 = new QGroupBox(tr("Snapshot Timing Setting:"));
|
||||||
hbox1 = new QHBoxLayout();
|
hbox1 = new QHBoxLayout();
|
||||||
frame1->setLayout(hbox1);
|
frame1->setLayout(hbox1);
|
||||||
grid->addWidget( frame1, 2, 0, 1, 2 );
|
grid->addWidget( frame1, 2, 0, 1, 2 );
|
||||||
|
|
||||||
|
g_config->getOption("SDL.StateRecorderTimingMode", &opt);
|
||||||
|
|
||||||
|
hbox1->addWidget( snapFrameSelBtn );
|
||||||
|
hbox1->addWidget( snapTimeSelBtn );
|
||||||
|
|
||||||
|
snapFramesGroup = new QGroupBox(tr("Frames Between Snapshots:"));
|
||||||
|
hbox1 = new QHBoxLayout();
|
||||||
|
snapFramesGroup->setLayout(hbox1);
|
||||||
|
snapFramesGroup->setEnabled(snapFrameSelBtn->isChecked());
|
||||||
|
grid->addWidget( snapFramesGroup, 3, 0, 1, 2 );
|
||||||
|
|
||||||
|
hbox1->addWidget( snapFrames);
|
||||||
|
hbox1->addWidget( new QLabel( tr("Range (1 - 10000)") ) );
|
||||||
|
|
||||||
|
snapTimeGroup = new QGroupBox(tr("Time Between Snapshots:"));
|
||||||
|
hbox1 = new QHBoxLayout();
|
||||||
|
snapTimeGroup->setLayout(hbox1);
|
||||||
|
snapTimeGroup->setEnabled(snapTimeSelBtn->isChecked());
|
||||||
|
grid->addWidget( snapTimeGroup, 4, 0, 1, 2 );
|
||||||
|
|
||||||
frame = new QGroupBox();
|
frame = new QGroupBox();
|
||||||
hbox = new QHBoxLayout();
|
hbox = new QHBoxLayout();
|
||||||
|
|
||||||
|
@ -141,16 +183,53 @@ StateRecorderDialog_t::StateRecorderDialog_t(QWidget *parent)
|
||||||
|
|
||||||
frame->setLayout(hbox);
|
frame->setLayout(hbox);
|
||||||
|
|
||||||
|
frame1 = new QGroupBox(tr("Pause on State Load:"));
|
||||||
|
vbox1 = new QVBoxLayout();
|
||||||
|
frame1->setLayout(vbox1);
|
||||||
|
|
||||||
|
g_config->getOption("SDL.StateRecorderPauseOnLoad", &opt);
|
||||||
|
|
||||||
|
pauseOnLoadCbox = new QComboBox();
|
||||||
|
pauseOnLoadCbox->addItem( tr("No"), StateRecorderConfigData::NO_PAUSE );
|
||||||
|
pauseOnLoadCbox->addItem( tr("Temporary"), StateRecorderConfigData::TEMPORARY_PAUSE );
|
||||||
|
pauseOnLoadCbox->addItem( tr("Full"), StateRecorderConfigData::FULL_PAUSE );
|
||||||
|
|
||||||
|
pauseOnLoadCbox->setCurrentIndex( opt );
|
||||||
|
|
||||||
|
connect( pauseOnLoadCbox, SIGNAL(currentIndexChanged(int)), this, SLOT(pauseOnLoadChanged(int)) );
|
||||||
|
|
||||||
|
g_config->getOption("SDL.StateRecorderPauseDuration", &opt);
|
||||||
|
|
||||||
|
pauseDuration = new QSpinBox();
|
||||||
|
pauseDuration->setMinimum(0);
|
||||||
|
pauseDuration->setMaximum(60);
|
||||||
|
pauseDuration->setValue(opt);
|
||||||
|
|
||||||
|
vbox1->addWidget(pauseOnLoadCbox);
|
||||||
|
|
||||||
|
frame = new QGroupBox( tr("Duration:") );
|
||||||
|
hbox = new QHBoxLayout();
|
||||||
|
|
||||||
|
vbox1->addWidget(frame);
|
||||||
|
hbox->addWidget( pauseDuration);
|
||||||
|
hbox->addWidget( new QLabel( tr("Seconds") ) );
|
||||||
|
|
||||||
|
frame->setLayout(hbox);
|
||||||
|
|
||||||
|
grid->addWidget(frame1, 4, 3, 2, 1);
|
||||||
|
|
||||||
frame = new QGroupBox( tr("Memory Usage:") );
|
frame = new QGroupBox( tr("Memory Usage:") );
|
||||||
memStatsGrid = new QGridLayout();
|
memStatsGrid = new QGridLayout();
|
||||||
|
|
||||||
numSnapsLbl = new QLineEdit();
|
numSnapsLbl = new QLineEdit();
|
||||||
snapMemSizeLbl = new QLineEdit();
|
snapMemSizeLbl = new QLineEdit();
|
||||||
totalMemUsageLbl = new QLineEdit();
|
totalMemUsageLbl = new QLineEdit();
|
||||||
|
saveTimeLbl = new QLineEdit();
|
||||||
|
|
||||||
numSnapsLbl->setReadOnly(true);
|
numSnapsLbl->setReadOnly(true);
|
||||||
snapMemSizeLbl->setReadOnly(true);
|
snapMemSizeLbl->setReadOnly(true);
|
||||||
totalMemUsageLbl->setReadOnly(true);
|
totalMemUsageLbl->setReadOnly(true);
|
||||||
|
saveTimeLbl->setReadOnly(true);
|
||||||
|
|
||||||
grid->addWidget(frame, 1, 3, 2, 2);
|
grid->addWidget(frame, 1, 3, 2, 2);
|
||||||
frame->setLayout(memStatsGrid);
|
frame->setLayout(memStatsGrid);
|
||||||
|
@ -163,8 +242,71 @@ StateRecorderDialog_t::StateRecorderDialog_t(QWidget *parent)
|
||||||
memStatsGrid->addWidget( new QLabel( tr("Total Size:") ), 2, 0 );
|
memStatsGrid->addWidget( new QLabel( tr("Total Size:") ), 2, 0 );
|
||||||
memStatsGrid->addWidget( totalMemUsageLbl, 2, 1 );
|
memStatsGrid->addWidget( totalMemUsageLbl, 2, 1 );
|
||||||
|
|
||||||
|
frame = new QGroupBox( tr("CPU Usage:") );
|
||||||
|
hbox = new QHBoxLayout();
|
||||||
|
frame->setLayout(hbox);
|
||||||
|
|
||||||
|
hbox->addWidget(new QLabel(tr("Snapshot\nSave Time:")), 2);
|
||||||
|
hbox->addWidget(saveTimeLbl, 2);
|
||||||
|
|
||||||
|
grid->addWidget(frame, 3, 3, 1, 1);
|
||||||
|
|
||||||
mainLayout->addLayout(grid);
|
mainLayout->addLayout(grid);
|
||||||
|
|
||||||
|
frame1 = new QGroupBox(tr("Recorder Status"));
|
||||||
|
sysStatusGrid = new QGridLayout();
|
||||||
|
frame1->setLayout(sysStatusGrid);
|
||||||
|
|
||||||
|
frame = new QGroupBox();
|
||||||
|
hbox = new QHBoxLayout();
|
||||||
|
|
||||||
|
sysStatusGrid->addWidget( frame, 0, 0, 1, 2);
|
||||||
|
frame->setLayout(hbox);
|
||||||
|
|
||||||
|
recStatusLbl = new QLineEdit();
|
||||||
|
recStatusLbl->setReadOnly(true);
|
||||||
|
startStopButton = new QPushButton( tr("Start") );
|
||||||
|
hbox->addWidget( new QLabel(tr("State:")), 1 );
|
||||||
|
hbox->addWidget( recStatusLbl, 2 );
|
||||||
|
hbox->addWidget( startStopButton, 1 );
|
||||||
|
|
||||||
|
updateStartStopBuffon();
|
||||||
|
updateRecorderStatusLabel();
|
||||||
|
|
||||||
|
connect(startStopButton, SIGNAL(clicked(void)), this, SLOT(startStopClicked(void)));
|
||||||
|
connect(snapFrameSelBtn, SIGNAL(clicked(void)), this, SLOT(snapFrameModeClicked(void)));
|
||||||
|
connect(snapTimeSelBtn , SIGNAL(clicked(void)), this, SLOT(snapTimeModeClicked(void)));
|
||||||
|
|
||||||
|
frame = new QGroupBox();
|
||||||
|
hbox = new QHBoxLayout();
|
||||||
|
|
||||||
|
sysStatusGrid->addWidget( frame, 0, 2, 1, 1);
|
||||||
|
frame->setLayout(hbox);
|
||||||
|
|
||||||
|
recBufSizeLbl = new QLineEdit();
|
||||||
|
recBufSizeLbl->setReadOnly(true);
|
||||||
|
hbox->addWidget( new QLabel(tr("Buffer Size:")), 1 );
|
||||||
|
hbox->addWidget( recBufSizeLbl, 1 );
|
||||||
|
|
||||||
|
frame = new QGroupBox( tr("Buffer Use:") );
|
||||||
|
hbox = new QHBoxLayout();
|
||||||
|
|
||||||
|
sysStatusGrid->addWidget( frame, 1, 0, 1, 3);
|
||||||
|
frame->setLayout(hbox);
|
||||||
|
|
||||||
|
bufUsage = new QProgressBar();
|
||||||
|
bufUsage->setToolTip( tr("% use of history record buffer.") );
|
||||||
|
bufUsage->setOrientation( Qt::Horizontal );
|
||||||
|
bufUsage->setMinimum( 0 );
|
||||||
|
bufUsage->setMaximum( 100 );
|
||||||
|
bufUsage->setValue( 0 );
|
||||||
|
|
||||||
|
hbox->addWidget(bufUsage);
|
||||||
|
|
||||||
|
updateBufferSizeStatus();
|
||||||
|
|
||||||
|
mainLayout->addWidget(frame1);
|
||||||
|
|
||||||
hbox = new QHBoxLayout();
|
hbox = new QHBoxLayout();
|
||||||
mainLayout->addLayout(hbox);
|
mainLayout->addLayout(hbox);
|
||||||
|
|
||||||
|
@ -186,6 +328,14 @@ StateRecorderDialog_t::StateRecorderDialog_t(QWidget *parent)
|
||||||
restoreGeometry(settings.value("stateRecorderWindow/geometry").toByteArray());
|
restoreGeometry(settings.value("stateRecorderWindow/geometry").toByteArray());
|
||||||
|
|
||||||
recalcMemoryUsage();
|
recalcMemoryUsage();
|
||||||
|
|
||||||
|
pauseOnLoadChanged( pauseOnLoadCbox->currentIndex() );
|
||||||
|
|
||||||
|
updateTimer = new QTimer(this);
|
||||||
|
|
||||||
|
connect(updateTimer, &QTimer::timeout, this, &StateRecorderDialog_t::updatePeriodic);
|
||||||
|
|
||||||
|
updateTimer->start(1000); // 1hz
|
||||||
}
|
}
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
StateRecorderDialog_t::~StateRecorderDialog_t(void)
|
StateRecorderDialog_t::~StateRecorderDialog_t(void)
|
||||||
|
@ -197,44 +347,206 @@ void StateRecorderDialog_t::closeEvent(QCloseEvent *event)
|
||||||
{
|
{
|
||||||
QSettings settings;
|
QSettings settings;
|
||||||
settings.setValue("stateRecorderWindow/geometry", saveGeometry());
|
settings.setValue("stateRecorderWindow/geometry", saveGeometry());
|
||||||
done(0);
|
|
||||||
deleteLater();
|
if (dataSavedCheck())
|
||||||
event->accept();
|
{
|
||||||
|
done(0);
|
||||||
|
deleteLater();
|
||||||
|
event->accept();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
void StateRecorderDialog_t::closeWindow(void)
|
void StateRecorderDialog_t::closeWindow(void)
|
||||||
{
|
{
|
||||||
QSettings settings;
|
QSettings settings;
|
||||||
settings.setValue("stateRecorderWindow/geometry", saveGeometry());
|
settings.setValue("stateRecorderWindow/geometry", saveGeometry());
|
||||||
done(0);
|
|
||||||
deleteLater();
|
if (dataSavedCheck())
|
||||||
|
{
|
||||||
|
done(0);
|
||||||
|
deleteLater();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
void StateRecorderDialog_t::packConfig( StateRecorderConfigData &config )
|
||||||
|
{
|
||||||
|
config.timingMode = snapTimeSelBtn->isChecked() ?
|
||||||
|
StateRecorderConfigData::TIME : StateRecorderConfigData::FRAMES;
|
||||||
|
|
||||||
|
config.framesBetweenSnaps = snapFrames->value();
|
||||||
|
config.historyDurationMinutes = static_cast<float>( historyDuration->value() );
|
||||||
|
config.timeBetweenSnapsMinutes = static_cast<float>( snapMinutes->value() ) +
|
||||||
|
( static_cast<float>( snapSeconds->value() ) / 60.0f );
|
||||||
|
config.compressionLevel = cmprLvlCbox->currentData().toInt();
|
||||||
|
config.loadPauseTimeSeconds = pauseDuration->value();
|
||||||
|
config.pauseOnLoad = static_cast<StateRecorderConfigData::PauseType>( pauseOnLoadCbox->currentData().toInt() );
|
||||||
|
}
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
bool StateRecorderDialog_t::dataSavedCheck(void)
|
||||||
|
{
|
||||||
|
bool okToClose = true;
|
||||||
|
const StateRecorderConfigData &curConfig = FCEU_StateRecorderGetConfigData();
|
||||||
|
|
||||||
|
StateRecorderConfigData selConfig;
|
||||||
|
|
||||||
|
packConfig( selConfig );
|
||||||
|
|
||||||
|
if ( selConfig.compare( curConfig ) == false )
|
||||||
|
{
|
||||||
|
QMessageBox msgBox(QMessageBox::Question, tr("State Recorder"),
|
||||||
|
tr("Setting selections have not yet been saved.\nDo you wish to save/apply the new settings?"),
|
||||||
|
QMessageBox::No | QMessageBox::Yes, this);
|
||||||
|
|
||||||
|
msgBox.setDefaultButton( QMessageBox::Yes );
|
||||||
|
|
||||||
|
int ret = msgBox.exec();
|
||||||
|
|
||||||
|
if ( ret == QMessageBox::Yes )
|
||||||
|
{
|
||||||
|
applyChanges();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return okToClose;
|
||||||
}
|
}
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
void StateRecorderDialog_t::applyChanges(void)
|
void StateRecorderDialog_t::applyChanges(void)
|
||||||
{
|
{
|
||||||
StateRecorderConfigData config;
|
StateRecorderConfigData config;
|
||||||
|
|
||||||
config.historyDurationMinutes = static_cast<float>( historyDuration->value() );
|
packConfig( config );
|
||||||
config.timeBetweenSnapsMinutes = static_cast<float>( snapMinutes->value() ) +
|
|
||||||
( static_cast<float>( snapSeconds->value() ) / 60.0f );
|
|
||||||
config.compressionLevel = cmprLvlCbox->currentData().toInt();
|
|
||||||
|
|
||||||
FCEU_WRAPPER_LOCK();
|
FCEU_WRAPPER_LOCK();
|
||||||
FCEU_StateRecorderSetEnabled( recorderEnable->isChecked() );
|
FCEU_StateRecorderSetEnabled( recorderEnable->isChecked() );
|
||||||
FCEU_StateRecorderSetConfigData( config );
|
FCEU_StateRecorderSetConfigData( config );
|
||||||
if (FCEU_StateRecorderRunning())
|
if (FCEU_StateRecorderRunning())
|
||||||
{
|
{
|
||||||
// TODO restart with new settings
|
QMessageBox msgBox(QMessageBox::Question, tr("State Recorder"),
|
||||||
|
tr("New settings will not take effect until state recorder is restarted. Do you wish to restart?"),
|
||||||
|
QMessageBox::No | QMessageBox::Yes, this);
|
||||||
|
|
||||||
|
msgBox.setDefaultButton( QMessageBox::Yes );
|
||||||
|
|
||||||
|
int ret = msgBox.exec();
|
||||||
|
|
||||||
|
if ( ret == QMessageBox::Yes )
|
||||||
|
{
|
||||||
|
FCEU_StateRecorderStop();
|
||||||
|
FCEU_StateRecorderStart();
|
||||||
|
updateStatusDisplay();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
FCEU_WRAPPER_UNLOCK();
|
FCEU_WRAPPER_UNLOCK();
|
||||||
|
|
||||||
g_config->setOption("SDL.StateRecorderHistoryDurationMin", historyDuration->value() );
|
g_config->setOption("SDL.StateRecorderHistoryDurationMin", historyDuration->value() );
|
||||||
|
g_config->setOption("SDL.StateRecorderTimingMode", snapTimeSelBtn->isChecked() ? 1 : 0);
|
||||||
|
g_config->setOption("SDL.StateRecorderFramesBetweenSnaps", snapFrames->value() );
|
||||||
g_config->setOption("SDL.StateRecorderTimeBetweenSnapsMin", snapMinutes->value() );
|
g_config->setOption("SDL.StateRecorderTimeBetweenSnapsMin", snapMinutes->value() );
|
||||||
g_config->setOption("SDL.StateRecorderTimeBetweenSnapsSec", snapSeconds->value() );
|
g_config->setOption("SDL.StateRecorderTimeBetweenSnapsSec", snapSeconds->value() );
|
||||||
|
g_config->setOption("SDL.StateRecorderCompressionLevel", config.compressionLevel);
|
||||||
|
g_config->setOption("SDL.StateRecorderPauseOnLoad", config.pauseOnLoad);
|
||||||
|
g_config->setOption("SDL.StateRecorderPauseDuration", config.loadPauseTimeSeconds);
|
||||||
g_config->setOption("SDL.StateRecorderEnable", recorderEnable->isChecked() );
|
g_config->setOption("SDL.StateRecorderEnable", recorderEnable->isChecked() );
|
||||||
g_config->save();
|
g_config->save();
|
||||||
}
|
}
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
|
void StateRecorderDialog_t::startStopClicked(void)
|
||||||
|
{
|
||||||
|
FCEU_WRAPPER_LOCK();
|
||||||
|
bool isRunning = FCEU_StateRecorderRunning();
|
||||||
|
|
||||||
|
if (isRunning)
|
||||||
|
{
|
||||||
|
FCEU_StateRecorderStop();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
FCEU_StateRecorderStart();
|
||||||
|
}
|
||||||
|
updateStatusDisplay();
|
||||||
|
|
||||||
|
FCEU_WRAPPER_UNLOCK();
|
||||||
|
}
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
void StateRecorderDialog_t::snapFrameModeClicked(void)
|
||||||
|
{
|
||||||
|
snapUseTime = false;
|
||||||
|
snapTimeGroup->setEnabled(false);
|
||||||
|
snapFramesGroup->setEnabled(true);
|
||||||
|
|
||||||
|
recalcMemoryUsage();
|
||||||
|
}
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
void StateRecorderDialog_t::snapTimeModeClicked(void)
|
||||||
|
{
|
||||||
|
snapUseTime = true;
|
||||||
|
snapFramesGroup->setEnabled(false);
|
||||||
|
snapTimeGroup->setEnabled(true);
|
||||||
|
|
||||||
|
recalcMemoryUsage();
|
||||||
|
}
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
void StateRecorderDialog_t::updateStartStopBuffon(void)
|
||||||
|
{
|
||||||
|
bool isRunning = FCEU_StateRecorderRunning();
|
||||||
|
|
||||||
|
if (isRunning)
|
||||||
|
{
|
||||||
|
startStopButton->setText( tr("Stop") );
|
||||||
|
startStopButton->setIcon( style()->standardIcon( QStyle::SP_MediaStop ) );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
startStopButton->setText( tr("Start") );
|
||||||
|
startStopButton->setIcon( QIcon(":icons/media-record.png") );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
void StateRecorderDialog_t::updateBufferSizeStatus(void)
|
||||||
|
{
|
||||||
|
char stmp[64];
|
||||||
|
|
||||||
|
int numSnapsSaved = FCEU_StateRecorderGetNumSnapsSaved();
|
||||||
|
int maxSnaps = FCEU_StateRecorderGetMaxSnaps();
|
||||||
|
|
||||||
|
snprintf( stmp, sizeof(stmp), "%i", maxSnaps );
|
||||||
|
|
||||||
|
recBufSizeLbl->setText( tr(stmp) );
|
||||||
|
|
||||||
|
if (maxSnaps > 0)
|
||||||
|
{
|
||||||
|
bufUsage->setMaximum( maxSnaps );
|
||||||
|
}
|
||||||
|
bufUsage->setValue( numSnapsSaved );
|
||||||
|
}
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
void StateRecorderDialog_t::updateRecorderStatusLabel(void)
|
||||||
|
{
|
||||||
|
bool isRunning = FCEU_StateRecorderRunning();
|
||||||
|
|
||||||
|
if (isRunning)
|
||||||
|
{
|
||||||
|
recStatusLbl->setText( tr("Recording") );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
recStatusLbl->setText( tr("Off") );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
void StateRecorderDialog_t::updateStatusDisplay(void)
|
||||||
|
{
|
||||||
|
updateStartStopBuffon();
|
||||||
|
updateRecorderStatusLabel();
|
||||||
|
updateBufferSizeStatus();
|
||||||
|
}
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
void StateRecorderDialog_t::updatePeriodic(void)
|
||||||
|
{
|
||||||
|
FCEU_WRAPPER_LOCK();
|
||||||
|
updateStatusDisplay();
|
||||||
|
FCEU_WRAPPER_UNLOCK();
|
||||||
|
}
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
void StateRecorderDialog_t::enableChanged(int val)
|
void StateRecorderDialog_t::enableChanged(int val)
|
||||||
{
|
{
|
||||||
bool ena = val ? true : false;
|
bool ena = val ? true : false;
|
||||||
|
@ -252,13 +564,39 @@ void StateRecorderDialog_t::spinBoxValueChanged(int newValue)
|
||||||
recalcMemoryUsage();
|
recalcMemoryUsage();
|
||||||
}
|
}
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
|
void StateRecorderDialog_t::compressionLevelChanged(int newValue)
|
||||||
|
{
|
||||||
|
recalcMemoryUsage();
|
||||||
|
}
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
void StateRecorderDialog_t::pauseOnLoadChanged(int index)
|
||||||
|
{
|
||||||
|
StateRecorderConfigData::PauseType pauseOnLoad;
|
||||||
|
|
||||||
|
pauseOnLoad = static_cast<StateRecorderConfigData::PauseType>( pauseOnLoadCbox->currentData().toInt() );
|
||||||
|
|
||||||
|
pauseDuration->setEnabled( pauseOnLoad == StateRecorderConfigData::TEMPORARY_PAUSE );
|
||||||
|
}
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
void StateRecorderDialog_t::recalcMemoryUsage(void)
|
void StateRecorderDialog_t::recalcMemoryUsage(void)
|
||||||
{
|
{
|
||||||
char stmp[64];
|
char stmp[64];
|
||||||
|
|
||||||
|
float fsnapMin = 1.0;
|
||||||
float fhistMin = static_cast<float>( historyDuration->value() );
|
float fhistMin = static_cast<float>( historyDuration->value() );
|
||||||
float fsnapMin = static_cast<float>( snapMinutes->value() ) +
|
|
||||||
|
if (snapUseTime)
|
||||||
|
{
|
||||||
|
fsnapMin = static_cast<float>( snapMinutes->value() ) +
|
||||||
( static_cast<float>( snapSeconds->value() ) / 60.0f );
|
( static_cast<float>( snapSeconds->value() ) / 60.0f );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
int32_t fps = FCEUI_GetDesiredFPS(); // Do >> 24 to get in Hz
|
||||||
|
double hz = ( ((double)fps) / 16777216.0 );
|
||||||
|
|
||||||
|
fsnapMin = static_cast<double>(snapFrames->value()) / (hz * 60.0);
|
||||||
|
}
|
||||||
|
|
||||||
float fnumSnaps = fhistMin / fsnapMin;
|
float fnumSnaps = fhistMin / fsnapMin;
|
||||||
float fsnapSize = 10.0f * 1024.0f;
|
float fsnapSize = 10.0f * 1024.0f;
|
||||||
|
@ -272,16 +610,32 @@ void StateRecorderDialog_t::recalcMemoryUsage(void)
|
||||||
|
|
||||||
numSnapsLbl->setText( tr(stmp) );
|
numSnapsLbl->setText( tr(stmp) );
|
||||||
|
|
||||||
|
saveTimeMs = 0.0;
|
||||||
|
|
||||||
if (GameInfo)
|
if (GameInfo)
|
||||||
{
|
{
|
||||||
|
constexpr int numIterations = 10;
|
||||||
|
double ts_start, ts_end;
|
||||||
|
|
||||||
FCEU_WRAPPER_LOCK();
|
FCEU_WRAPPER_LOCK();
|
||||||
|
|
||||||
EMUFILE_MEMORY em;
|
EMUFILE_MEMORY em;
|
||||||
int compressionLevel = 0;
|
int compressionLevel = cmprLvlCbox->currentData().toInt();
|
||||||
|
|
||||||
FCEUSS_SaveMS( &em, compressionLevel );
|
ts_start = getHighPrecTimeStamp();
|
||||||
|
|
||||||
fsnapSize = static_cast<float>( em.size() ) / 1024.0f;
|
// Perform State Save multiple times to get a good average
|
||||||
|
// on what the compression delays will be.
|
||||||
|
for (int i=0; i<numIterations; i++)
|
||||||
|
{
|
||||||
|
em.set_len(0);
|
||||||
|
FCEUSS_SaveMS( &em, compressionLevel );
|
||||||
|
}
|
||||||
|
ts_end = getHighPrecTimeStamp();
|
||||||
|
|
||||||
|
saveTimeMs = (ts_end - ts_start) * 1000.0 / static_cast<double>(numIterations);
|
||||||
|
|
||||||
|
fsnapSize = static_cast<float>( em.size() );
|
||||||
|
|
||||||
FCEU_WRAPPER_UNLOCK();
|
FCEU_WRAPPER_UNLOCK();
|
||||||
}
|
}
|
||||||
|
@ -313,5 +667,8 @@ void StateRecorderDialog_t::recalcMemoryUsage(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
totalMemUsageLbl->setText( tr(stmp) );
|
totalMemUsageLbl->setText( tr(stmp) );
|
||||||
|
|
||||||
|
sprintf( stmp, "%.02f ms", saveTimeMs);
|
||||||
|
saveTimeLbl->setText( tr(stmp) );
|
||||||
}
|
}
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
|
|
|
@ -12,10 +12,15 @@
|
||||||
#include <QSpinBox>
|
#include <QSpinBox>
|
||||||
#include <QComboBox>
|
#include <QComboBox>
|
||||||
#include <QPushButton>
|
#include <QPushButton>
|
||||||
|
#include <QRadioButton>
|
||||||
|
#include <QProgressBar>
|
||||||
#include <QLineEdit>
|
#include <QLineEdit>
|
||||||
#include <QLabel>
|
#include <QLabel>
|
||||||
#include <QFrame>
|
#include <QFrame>
|
||||||
#include <QGroupBox>
|
#include <QGroupBox>
|
||||||
|
#include <QTimer>
|
||||||
|
|
||||||
|
struct StateRecorderConfigData;
|
||||||
|
|
||||||
class StateRecorderDialog_t : public QDialog
|
class StateRecorderDialog_t : public QDialog
|
||||||
{
|
{
|
||||||
|
@ -28,23 +33,51 @@ public:
|
||||||
protected:
|
protected:
|
||||||
void closeEvent(QCloseEvent *event);
|
void closeEvent(QCloseEvent *event);
|
||||||
|
|
||||||
QSpinBox *snapMinutes;
|
QSpinBox *snapMinutes;
|
||||||
QSpinBox *snapSeconds;
|
QSpinBox *snapSeconds;
|
||||||
QSpinBox *historyDuration;
|
QSpinBox *snapFrames;
|
||||||
QCheckBox *recorderEnable;
|
QSpinBox *historyDuration;
|
||||||
QLineEdit *numSnapsLbl;
|
QSpinBox *pauseDuration;
|
||||||
QLineEdit *snapMemSizeLbl;
|
QCheckBox *recorderEnable;
|
||||||
QLineEdit *totalMemUsageLbl;
|
QLineEdit *numSnapsLbl;
|
||||||
QPushButton *applyButton;
|
QLineEdit *snapMemSizeLbl;
|
||||||
QPushButton *closeButton;
|
QLineEdit *totalMemUsageLbl;
|
||||||
QComboBox *cmprLvlCbox;
|
QLineEdit *saveTimeLbl;
|
||||||
|
QPushButton *applyButton;
|
||||||
|
QPushButton *closeButton;
|
||||||
|
QComboBox *cmprLvlCbox;
|
||||||
|
QComboBox *pauseOnLoadCbox;
|
||||||
|
QGroupBox *snapTimeGroup;
|
||||||
|
QGroupBox *snapFramesGroup;
|
||||||
|
QRadioButton *snapFrameSelBtn;
|
||||||
|
QRadioButton *snapTimeSelBtn;
|
||||||
|
QLineEdit *recStatusLbl;
|
||||||
|
QLineEdit *recBufSizeLbl;
|
||||||
|
QPushButton *startStopButton;
|
||||||
|
QProgressBar *bufUsage;
|
||||||
|
QTimer *updateTimer;
|
||||||
|
|
||||||
|
double saveTimeMs;
|
||||||
|
bool snapUseTime;
|
||||||
|
|
||||||
|
bool dataSavedCheck(void);
|
||||||
void recalcMemoryUsage(void);
|
void recalcMemoryUsage(void);
|
||||||
|
void updateStartStopBuffon(void);
|
||||||
|
void updateRecorderStatusLabel(void);
|
||||||
|
void updateBufferSizeStatus(void);
|
||||||
|
void updateStatusDisplay(void);
|
||||||
|
void packConfig( StateRecorderConfigData &config );
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void closeWindow(void);
|
void closeWindow(void);
|
||||||
private slots:
|
private slots:
|
||||||
void applyChanges(void);
|
void applyChanges(void);
|
||||||
|
void updatePeriodic(void);
|
||||||
|
void startStopClicked(void);
|
||||||
|
void snapTimeModeClicked(void);
|
||||||
|
void snapFrameModeClicked(void);
|
||||||
void spinBoxValueChanged(int newValue);
|
void spinBoxValueChanged(int newValue);
|
||||||
void enableChanged(int);
|
void enableChanged(int);
|
||||||
|
void compressionLevelChanged(int newValue);
|
||||||
|
void pauseOnLoadChanged(int index);
|
||||||
};
|
};
|
||||||
|
|
|
@ -116,7 +116,6 @@ void tasWindowSetFocus(bool val)
|
||||||
{
|
{
|
||||||
tasWin->activateWindow();
|
tasWin->activateWindow();
|
||||||
tasWin->raise();
|
tasWin->raise();
|
||||||
tasWin->setFocus();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// this getter contains formula to decide whether to record or replay movie
|
// this getter contains formula to decide whether to record or replay movie
|
||||||
|
@ -2917,7 +2916,6 @@ void TasEditorWindow::openFindNoteWindow(void)
|
||||||
{
|
{
|
||||||
findWin->activateWindow();
|
findWin->activateWindow();
|
||||||
findWin->raise();
|
findWin->raise();
|
||||||
findWin->setFocus();
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
|
@ -57,6 +57,7 @@
|
||||||
|
|
||||||
#include "common/os_utils.h"
|
#include "common/os_utils.h"
|
||||||
|
|
||||||
|
#include "Qt/ConsoleDebugger.h"
|
||||||
#include "Qt/ConsoleWindow.h"
|
#include "Qt/ConsoleWindow.h"
|
||||||
#include "Qt/ConsoleUtilities.h"
|
#include "Qt/ConsoleUtilities.h"
|
||||||
#include "Qt/TraceLogger.h"
|
#include "Qt/TraceLogger.h"
|
||||||
|
@ -1211,7 +1212,6 @@ void openTraceLoggerWindow(QWidget *parent)
|
||||||
{
|
{
|
||||||
traceLogWindow->activateWindow();
|
traceLogWindow->activateWindow();
|
||||||
traceLogWindow->raise();
|
traceLogWindow->raise();
|
||||||
traceLogWindow->setFocus();
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
//printf("Open Trace Logger Window\n");
|
//printf("Open Trace Logger Window\n");
|
||||||
|
@ -2188,7 +2188,7 @@ void QTraceLogView::openBpEditWindow(int editIdx, watchpointinfo *wp, traceRecor
|
||||||
numWPs++;
|
numWPs++;
|
||||||
}
|
}
|
||||||
|
|
||||||
updateAllDebuggerWindows();
|
updateAllDebuggerWindows(QAsmView::UPDATE_NO_SCROLL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2233,7 +2233,7 @@ void QTraceLogView::openDebugSymbolEditWindow(int addr, int bank)
|
||||||
|
|
||||||
if (ret == QDialog::Accepted)
|
if (ret == QDialog::Accepted)
|
||||||
{
|
{
|
||||||
updateAllDebuggerWindows();
|
updateAllDebuggerWindows(QAsmView::UPDATE_NO_SCROLL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
|
|
|
@ -756,9 +756,13 @@ InitConfig()
|
||||||
|
|
||||||
config->addOption("SDL.StateRecorderEnable", false);
|
config->addOption("SDL.StateRecorderEnable", false);
|
||||||
config->addOption("SDL.StateRecorderHistoryDurationMin", 15);
|
config->addOption("SDL.StateRecorderHistoryDurationMin", 15);
|
||||||
|
config->addOption("SDL.StateRecorderTimingMode", 0);
|
||||||
|
config->addOption("SDL.StateRecorderFramesBetweenSnaps", 60);
|
||||||
config->addOption("SDL.StateRecorderTimeBetweenSnapsMin", 0);
|
config->addOption("SDL.StateRecorderTimeBetweenSnapsMin", 0);
|
||||||
config->addOption("SDL.StateRecorderTimeBetweenSnapsSec", 3);
|
config->addOption("SDL.StateRecorderTimeBetweenSnapsSec", 3);
|
||||||
config->addOption("SDL.StateRecorderCompressionLevel", 0);
|
config->addOption("SDL.StateRecorderCompressionLevel", 0);
|
||||||
|
config->addOption("SDL.StateRecorderPauseOnLoad", 1);
|
||||||
|
config->addOption("SDL.StateRecorderPauseDuration", 3);
|
||||||
|
|
||||||
//TODO implement this
|
//TODO implement this
|
||||||
config->addOption("periodicsaves", "SDL.PeriodicSaves", 0);
|
config->addOption("periodicsaves", "SDL.PeriodicSaves", 0);
|
||||||
|
|
|
@ -976,22 +976,36 @@ int fceuWrapperInit( int argc, char *argv[] )
|
||||||
// Initialize the State Recorder
|
// Initialize the State Recorder
|
||||||
{
|
{
|
||||||
bool srEnable = false;
|
bool srEnable = false;
|
||||||
|
bool srUseTimeMode = false;
|
||||||
int srHistDurMin = 15;
|
int srHistDurMin = 15;
|
||||||
|
int srFramesBtwSnaps = 60;
|
||||||
int srTimeBtwSnapsMin = 0;
|
int srTimeBtwSnapsMin = 0;
|
||||||
int srTimeBtwSnapsSec = 3;
|
int srTimeBtwSnapsSec = 3;
|
||||||
int srCompressionLevel = 0;
|
int srCompressionLevel = 0;
|
||||||
|
int pauseOnLoadTime = 3;
|
||||||
|
int pauseOnLoad = StateRecorderConfigData::TEMPORARY_PAUSE;
|
||||||
|
|
||||||
g_config->getOption("SDL.StateRecorderEnable", &srEnable);
|
g_config->getOption("SDL.StateRecorderEnable", &srEnable);
|
||||||
|
g_config->getOption("SDL.StateRecorderTimingMode", &srUseTimeMode);
|
||||||
g_config->getOption("SDL.StateRecorderHistoryDurationMin", &srHistDurMin);
|
g_config->getOption("SDL.StateRecorderHistoryDurationMin", &srHistDurMin);
|
||||||
|
g_config->getOption("SDL.StateRecorderFramesBetweenSnaps", &srFramesBtwSnaps);
|
||||||
g_config->getOption("SDL.StateRecorderTimeBetweenSnapsMin", &srTimeBtwSnapsMin);
|
g_config->getOption("SDL.StateRecorderTimeBetweenSnapsMin", &srTimeBtwSnapsMin);
|
||||||
g_config->getOption("SDL.StateRecorderTimeBetweenSnapsSec", &srTimeBtwSnapsSec);
|
g_config->getOption("SDL.StateRecorderTimeBetweenSnapsSec", &srTimeBtwSnapsSec);
|
||||||
g_config->getOption("SDL.StateRecorderCompressionLevel", &srCompressionLevel);
|
g_config->getOption("SDL.StateRecorderCompressionLevel", &srCompressionLevel);
|
||||||
|
g_config->getOption("SDL.StateRecorderPauseOnLoad", &pauseOnLoad);
|
||||||
|
g_config->getOption("SDL.StateRecorderPauseDuration", &pauseOnLoadTime);
|
||||||
|
|
||||||
StateRecorderConfigData srConfig;
|
StateRecorderConfigData srConfig;
|
||||||
|
|
||||||
srConfig.historyDurationMinutes = srHistDurMin;
|
srConfig.historyDurationMinutes = srHistDurMin;
|
||||||
|
srConfig.timingMode = srUseTimeMode ?
|
||||||
|
StateRecorderConfigData::TIME : StateRecorderConfigData::FRAMES;
|
||||||
srConfig.timeBetweenSnapsMinutes = static_cast<float>( srTimeBtwSnapsMin ) +
|
srConfig.timeBetweenSnapsMinutes = static_cast<float>( srTimeBtwSnapsMin ) +
|
||||||
( static_cast<float>( srTimeBtwSnapsSec ) / 60.0f );
|
( static_cast<float>( srTimeBtwSnapsSec ) / 60.0f );
|
||||||
|
srConfig.framesBetweenSnaps = srFramesBtwSnaps;
|
||||||
srConfig.compressionLevel = srCompressionLevel;
|
srConfig.compressionLevel = srCompressionLevel;
|
||||||
|
srConfig.loadPauseTimeSeconds = pauseOnLoadTime;
|
||||||
|
srConfig.pauseOnLoad = static_cast<StateRecorderConfigData::PauseType>(pauseOnLoad);
|
||||||
|
|
||||||
FCEU_StateRecorderSetEnabled( srEnable );
|
FCEU_StateRecorderSetEnabled( srEnable );
|
||||||
FCEU_StateRecorderSetConfigData( srConfig );
|
FCEU_StateRecorderSetConfigData( srConfig );
|
||||||
|
@ -1469,20 +1483,19 @@ int fceuWrapperUpdate( void )
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
ArchiveScanRecord FCEUD_ScanArchive(std::string fname)
|
static int minizip_ScanArchive( const char *filepath, ArchiveScanRecord &rec)
|
||||||
{
|
{
|
||||||
int idx=0, ret;
|
int idx=0, ret;
|
||||||
unzFile zf;
|
unzFile zf;
|
||||||
unz_file_info fi;
|
unz_file_info fi;
|
||||||
char filename[512];
|
char filename[512];
|
||||||
ArchiveScanRecord rec;
|
|
||||||
|
zf = unzOpen( filepath );
|
||||||
zf = unzOpen( fname.c_str() );
|
|
||||||
|
|
||||||
if ( zf == NULL )
|
if ( zf == NULL )
|
||||||
{
|
{
|
||||||
//printf("Error: Failed to open Zip File: '%s'\n", fname.c_str() );
|
//printf("Error: Failed to open Zip File: '%s'\n", fname.c_str() );
|
||||||
return rec;
|
return -1;
|
||||||
}
|
}
|
||||||
rec.type = 0;
|
rec.type = 0;
|
||||||
|
|
||||||
|
@ -1512,18 +1525,313 @@ ArchiveScanRecord FCEUD_ScanArchive(std::string fname)
|
||||||
|
|
||||||
unzClose( zf );
|
unzClose( zf );
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef _USE_LIBARCHIVE
|
||||||
|
#include <archive.h>
|
||||||
|
#include <archive_entry.h>
|
||||||
|
|
||||||
|
static int libarchive_ScanArchive( const char *filepath, ArchiveScanRecord &rec)
|
||||||
|
{
|
||||||
|
int r, idx=0;
|
||||||
|
struct archive *a;
|
||||||
|
struct archive_entry *entry;
|
||||||
|
|
||||||
|
a = archive_read_new();
|
||||||
|
|
||||||
|
if (a == nullptr)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialize decoders
|
||||||
|
r = archive_read_support_filter_all(a);
|
||||||
|
if (r)
|
||||||
|
{
|
||||||
|
archive_read_free(a);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialize formats
|
||||||
|
r = archive_read_support_format_all(a);
|
||||||
|
if (r)
|
||||||
|
{
|
||||||
|
archive_read_free(a);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
r = archive_read_open_filename(a, filepath, 10240);
|
||||||
|
|
||||||
|
if (r)
|
||||||
|
{
|
||||||
|
archive_read_free(a);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
rec.type = 1;
|
||||||
|
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
r = archive_read_next_header(a, &entry);
|
||||||
|
if (r == ARCHIVE_EOF)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else if (r != ARCHIVE_OK)
|
||||||
|
{
|
||||||
|
printf("archive_read_next_header() %s\n", archive_error_string(a));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
const char *filename = archive_entry_pathname(entry);
|
||||||
|
|
||||||
|
FCEUARCHIVEFILEINFO_ITEM item;
|
||||||
|
item.name.assign( filename );
|
||||||
|
item.size = archive_entry_size(entry);
|
||||||
|
item.index = idx; idx++;
|
||||||
|
|
||||||
|
rec.files.push_back( item );
|
||||||
|
}
|
||||||
|
rec.numFilesInArchive = idx;
|
||||||
|
|
||||||
|
archive_read_free(a);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
ArchiveScanRecord FCEUD_ScanArchive(std::string fname)
|
||||||
|
{
|
||||||
|
int ret = -1;
|
||||||
|
ArchiveScanRecord rec;
|
||||||
|
|
||||||
|
#ifdef _USE_LIBARCHIVE
|
||||||
|
ret = libarchive_ScanArchive( fname.c_str(), rec );
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (ret == -1)
|
||||||
|
{
|
||||||
|
minizip_ScanArchive( fname.c_str(), rec );
|
||||||
|
}
|
||||||
return rec;
|
return rec;
|
||||||
}
|
}
|
||||||
|
|
||||||
FCEUFILE* FCEUD_OpenArchive(ArchiveScanRecord& asr, std::string& fname, std::string* innerFilename, int* userCancel)
|
static FCEUFILE* minizip_OpenArchive(ArchiveScanRecord& asr, std::string &fname, std::string *searchFile, int innerIndex )
|
||||||
{
|
{
|
||||||
int ret;
|
int ret, idx=0;
|
||||||
FCEUFILE* fp = 0;
|
FCEUFILE* fp = nullptr;
|
||||||
|
void *tmpMem = nullptr;
|
||||||
unzFile zf;
|
unzFile zf;
|
||||||
unz_file_info fi;
|
unz_file_info fi;
|
||||||
char filename[512];
|
char filename[512];
|
||||||
char foundFile = 0;
|
bool foundFile = false;
|
||||||
void *tmpMem = NULL;
|
|
||||||
|
zf = unzOpen( fname.c_str() );
|
||||||
|
|
||||||
|
if ( zf == NULL )
|
||||||
|
{
|
||||||
|
//printf("Error: Failed to open Zip File: '%s'\n", fname.c_str() );
|
||||||
|
return fp;
|
||||||
|
}
|
||||||
|
|
||||||
|
//printf("Searching for %s in %s \n", searchFile.c_str(), fname.c_str() );
|
||||||
|
|
||||||
|
ret = unzGoToFirstFile( zf );
|
||||||
|
|
||||||
|
//printf("unzGoToFirstFile: %i \n", ret );
|
||||||
|
|
||||||
|
while ( ret == 0 )
|
||||||
|
{
|
||||||
|
unzGetCurrentFileInfo( zf, &fi, filename, sizeof(filename), NULL, 0, NULL, 0 );
|
||||||
|
|
||||||
|
//printf("Filename: %u '%s' \n", fi.uncompressed_size, filename );
|
||||||
|
|
||||||
|
if (searchFile)
|
||||||
|
{
|
||||||
|
if ( strcmp( searchFile->c_str(), filename ) == 0 )
|
||||||
|
{
|
||||||
|
//printf("Found Filename: %u '%s' \n", fi.uncompressed_size, filename );
|
||||||
|
foundFile = true; break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if ((innerIndex != -1) && (idx == innerIndex))
|
||||||
|
{
|
||||||
|
foundFile = true; break;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = unzGoToNextFile( zf );
|
||||||
|
|
||||||
|
//printf("unzGoToNextFile: %i \n", ret );
|
||||||
|
idx++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( !foundFile )
|
||||||
|
{
|
||||||
|
unzClose( zf );
|
||||||
|
return fp;
|
||||||
|
}
|
||||||
|
|
||||||
|
tmpMem = ::malloc( fi.uncompressed_size );
|
||||||
|
|
||||||
|
if ( tmpMem == NULL )
|
||||||
|
{
|
||||||
|
unzClose( zf );
|
||||||
|
return fp;
|
||||||
|
}
|
||||||
|
//printf("Loading via minizip\n");
|
||||||
|
|
||||||
|
EMUFILE_MEMORY* ms = new EMUFILE_MEMORY(fi.uncompressed_size);
|
||||||
|
|
||||||
|
unzOpenCurrentFile( zf );
|
||||||
|
unzReadCurrentFile( zf, tmpMem, fi.uncompressed_size );
|
||||||
|
unzCloseCurrentFile( zf );
|
||||||
|
|
||||||
|
ms->fwrite( tmpMem, fi.uncompressed_size );
|
||||||
|
|
||||||
|
free( tmpMem );
|
||||||
|
|
||||||
|
//if we extracted the file correctly
|
||||||
|
fp = new FCEUFILE();
|
||||||
|
fp->archiveFilename = fname;
|
||||||
|
fp->filename = filename;
|
||||||
|
fp->fullFilename = fp->archiveFilename + "|" + fp->filename;
|
||||||
|
fp->archiveIndex = idx;
|
||||||
|
fp->mode = FCEUFILE::READ;
|
||||||
|
fp->size = fi.uncompressed_size;
|
||||||
|
fp->stream = ms;
|
||||||
|
fp->archiveCount = (int)asr.numFilesInArchive;
|
||||||
|
ms->fseek(0,SEEK_SET); //rewind so that the rom analyzer sees a freshly opened file
|
||||||
|
|
||||||
|
unzClose( zf );
|
||||||
|
|
||||||
|
return fp;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef _USE_LIBARCHIVE
|
||||||
|
static FCEUFILE* libarchive_OpenArchive( ArchiveScanRecord& asr, std::string& fname, std::string *searchFile, int innerIndex)
|
||||||
|
{
|
||||||
|
int r, idx=0;
|
||||||
|
struct archive *a;
|
||||||
|
struct archive_entry *entry;
|
||||||
|
const char *filename = nullptr;
|
||||||
|
bool foundFile = false;
|
||||||
|
int fileSize = 0;
|
||||||
|
FCEUFILE* fp = nullptr;
|
||||||
|
|
||||||
|
a = archive_read_new();
|
||||||
|
|
||||||
|
if (a == nullptr)
|
||||||
|
{
|
||||||
|
archive_read_free(a);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialize decoders
|
||||||
|
r = archive_read_support_filter_all(a);
|
||||||
|
if (r)
|
||||||
|
{
|
||||||
|
archive_read_free(a);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialize formats
|
||||||
|
r = archive_read_support_format_all(a);
|
||||||
|
if (r)
|
||||||
|
{
|
||||||
|
archive_read_free(a);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
r = archive_read_open_filename(a, fname.c_str(), 10240);
|
||||||
|
|
||||||
|
if (r)
|
||||||
|
{
|
||||||
|
archive_read_free(a);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
r = archive_read_next_header(a, &entry);
|
||||||
|
if (r == ARCHIVE_EOF)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else if (r != ARCHIVE_OK)
|
||||||
|
{
|
||||||
|
printf("archive_read_next_header() %s\n", archive_error_string(a));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
filename = archive_entry_pathname(entry);
|
||||||
|
fileSize = archive_entry_size(entry);
|
||||||
|
|
||||||
|
if (searchFile)
|
||||||
|
{
|
||||||
|
if (strcmp( filename, searchFile->c_str() ) == 0)
|
||||||
|
{
|
||||||
|
foundFile = true; break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if ((innerIndex != -1) && (idx == innerIndex))
|
||||||
|
{
|
||||||
|
foundFile = true; break;
|
||||||
|
}
|
||||||
|
idx++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (foundFile && (fileSize > 0))
|
||||||
|
{
|
||||||
|
const void *buff;
|
||||||
|
size_t size, totalSize = 0;
|
||||||
|
#if ARCHIVE_VERSION_NUMBER >= 3000000
|
||||||
|
int64_t offset;
|
||||||
|
#else
|
||||||
|
off_t offset;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//printf("Loading via libarchive\n");
|
||||||
|
|
||||||
|
EMUFILE_MEMORY* ms = new EMUFILE_MEMORY(fileSize);
|
||||||
|
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
r = archive_read_data_block(a, &buff, &size, &offset);
|
||||||
|
|
||||||
|
if (r == ARCHIVE_EOF)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (r != ARCHIVE_OK)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
//printf("Read: %p Size:%zu Offset:%llu\n", buff, size, (long long int)offset);
|
||||||
|
ms->fwrite( buff, size );
|
||||||
|
totalSize += size;
|
||||||
|
}
|
||||||
|
|
||||||
|
//if we extracted the file correctly
|
||||||
|
fp = new FCEUFILE();
|
||||||
|
fp->archiveFilename = fname;
|
||||||
|
fp->filename = filename;
|
||||||
|
fp->fullFilename = fp->archiveFilename + "|" + fp->filename;
|
||||||
|
fp->archiveIndex = idx;
|
||||||
|
fp->mode = FCEUFILE::READ;
|
||||||
|
fp->size = totalSize;
|
||||||
|
fp->stream = ms;
|
||||||
|
fp->archiveCount = (int)asr.numFilesInArchive;
|
||||||
|
ms->fseek(0,SEEK_SET); //rewind so that the rom analyzer sees a freshly opened file
|
||||||
|
}
|
||||||
|
|
||||||
|
archive_read_free(a);
|
||||||
|
|
||||||
|
return fp;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
FCEUFILE* FCEUD_OpenArchive(ArchiveScanRecord& asr, std::string& fname, std::string* innerFilename, int* userCancel)
|
||||||
|
{
|
||||||
|
FCEUFILE* fp = nullptr;
|
||||||
std::string searchFile;
|
std::string searchFile;
|
||||||
|
|
||||||
if ( innerFilename != NULL )
|
if ( innerFilename != NULL )
|
||||||
|
@ -1573,75 +1881,14 @@ FCEUFILE* FCEUD_OpenArchive(ArchiveScanRecord& asr, std::string& fname, std::str
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
zf = unzOpen( fname.c_str() );
|
#ifdef _USE_LIBARCHIVE
|
||||||
|
fp = libarchive_OpenArchive(asr, fname, &searchFile, -1 );
|
||||||
|
#endif
|
||||||
|
|
||||||
if ( zf == NULL )
|
if (fp == nullptr)
|
||||||
{
|
{
|
||||||
//printf("Error: Failed to open Zip File: '%s'\n", fname.c_str() );
|
fp = minizip_OpenArchive(asr, fname, &searchFile, -1 );
|
||||||
return fp;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//printf("Searching for %s in %s \n", searchFile.c_str(), fname.c_str() );
|
|
||||||
|
|
||||||
ret = unzGoToFirstFile( zf );
|
|
||||||
|
|
||||||
//printf("unzGoToFirstFile: %i \n", ret );
|
|
||||||
|
|
||||||
while ( ret == 0 )
|
|
||||||
{
|
|
||||||
unzGetCurrentFileInfo( zf, &fi, filename, sizeof(filename), NULL, 0, NULL, 0 );
|
|
||||||
|
|
||||||
//printf("Filename: %u '%s' \n", fi.uncompressed_size, filename );
|
|
||||||
|
|
||||||
if ( strcmp( searchFile.c_str(), filename ) == 0 )
|
|
||||||
{
|
|
||||||
//printf("Found Filename: %u '%s' \n", fi.uncompressed_size, filename );
|
|
||||||
foundFile = 1; break;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = unzGoToNextFile( zf );
|
|
||||||
|
|
||||||
//printf("unzGoToNextFile: %i \n", ret );
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( !foundFile )
|
|
||||||
{
|
|
||||||
unzClose( zf );
|
|
||||||
return fp;
|
|
||||||
}
|
|
||||||
|
|
||||||
tmpMem = ::malloc( fi.uncompressed_size );
|
|
||||||
|
|
||||||
if ( tmpMem == NULL )
|
|
||||||
{
|
|
||||||
unzClose( zf );
|
|
||||||
return fp;
|
|
||||||
}
|
|
||||||
|
|
||||||
EMUFILE_MEMORY* ms = new EMUFILE_MEMORY(fi.uncompressed_size);
|
|
||||||
|
|
||||||
unzOpenCurrentFile( zf );
|
|
||||||
unzReadCurrentFile( zf, tmpMem, fi.uncompressed_size );
|
|
||||||
unzCloseCurrentFile( zf );
|
|
||||||
|
|
||||||
ms->fwrite( tmpMem, fi.uncompressed_size );
|
|
||||||
|
|
||||||
free( tmpMem );
|
|
||||||
|
|
||||||
//if we extracted the file correctly
|
|
||||||
fp = new FCEUFILE();
|
|
||||||
fp->archiveFilename = fname;
|
|
||||||
fp->filename = searchFile;
|
|
||||||
fp->fullFilename = fp->archiveFilename + "|" + fp->filename;
|
|
||||||
fp->archiveIndex = ret;
|
|
||||||
fp->mode = FCEUFILE::READ;
|
|
||||||
fp->size = fi.uncompressed_size;
|
|
||||||
fp->stream = ms;
|
|
||||||
fp->archiveCount = (int)asr.numFilesInArchive;
|
|
||||||
ms->fseek(0,SEEK_SET); //rewind so that the rom analyzer sees a freshly opened file
|
|
||||||
|
|
||||||
unzClose( zf );
|
|
||||||
|
|
||||||
return fp;
|
return fp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1654,82 +1901,16 @@ FCEUFILE* FCEUD_OpenArchive(ArchiveScanRecord& asr, std::string& fname, std::str
|
||||||
|
|
||||||
FCEUFILE* FCEUD_OpenArchiveIndex(ArchiveScanRecord& asr, std::string &fname, int innerIndex, int* userCancel)
|
FCEUFILE* FCEUD_OpenArchiveIndex(ArchiveScanRecord& asr, std::string &fname, int innerIndex, int* userCancel)
|
||||||
{
|
{
|
||||||
int ret, idx=0;
|
FCEUFILE* fp = nullptr;
|
||||||
FCEUFILE* fp = 0;
|
|
||||||
unzFile zf;
|
|
||||||
unz_file_info fi;
|
|
||||||
char filename[512];
|
|
||||||
char foundFile = 0;
|
|
||||||
void *tmpMem = NULL;
|
|
||||||
|
|
||||||
zf = unzOpen( fname.c_str() );
|
#ifdef _USE_LIBARCHIVE
|
||||||
|
fp = libarchive_OpenArchive( asr, fname, nullptr, innerIndex );
|
||||||
if ( zf == NULL )
|
#endif
|
||||||
|
if (fp == nullptr)
|
||||||
{
|
{
|
||||||
//printf("Error: Failed to open Zip File: '%s'\n", fname.c_str() );
|
fp = minizip_OpenArchive(asr, fname, nullptr, innerIndex);
|
||||||
return fp;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = unzGoToFirstFile( zf );
|
|
||||||
|
|
||||||
//printf("unzGoToFirstFile: %i \n", ret );
|
|
||||||
|
|
||||||
while ( ret == 0 )
|
|
||||||
{
|
|
||||||
unzGetCurrentFileInfo( zf, &fi, filename, sizeof(filename), NULL, 0, NULL, 0 );
|
|
||||||
|
|
||||||
//printf("Filename: %u '%s' \n", fi.uncompressed_size, filename );
|
|
||||||
|
|
||||||
if ( idx == innerIndex )
|
|
||||||
{
|
|
||||||
//printf("Found Filename: %u '%s' \n", fi.uncompressed_size, filename );
|
|
||||||
foundFile = 1; break;
|
|
||||||
}
|
|
||||||
idx++;
|
|
||||||
|
|
||||||
ret = unzGoToNextFile( zf );
|
|
||||||
|
|
||||||
//printf("unzGoToNextFile: %i \n", ret );
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( !foundFile )
|
|
||||||
{
|
|
||||||
unzClose( zf );
|
|
||||||
return fp;
|
|
||||||
}
|
|
||||||
|
|
||||||
tmpMem = ::malloc( fi.uncompressed_size );
|
|
||||||
|
|
||||||
if ( tmpMem == NULL )
|
|
||||||
{
|
|
||||||
unzClose( zf );
|
|
||||||
return fp;
|
|
||||||
}
|
|
||||||
|
|
||||||
EMUFILE_MEMORY* ms = new EMUFILE_MEMORY(fi.uncompressed_size);
|
|
||||||
|
|
||||||
unzOpenCurrentFile( zf );
|
|
||||||
unzReadCurrentFile( zf, tmpMem, fi.uncompressed_size );
|
|
||||||
unzCloseCurrentFile( zf );
|
|
||||||
|
|
||||||
ms->fwrite( tmpMem, fi.uncompressed_size );
|
|
||||||
|
|
||||||
free( tmpMem );
|
|
||||||
|
|
||||||
//if we extracted the file correctly
|
|
||||||
fp = new FCEUFILE();
|
|
||||||
fp->archiveFilename = fname;
|
|
||||||
fp->filename = filename;
|
|
||||||
fp->fullFilename = fp->archiveFilename + "|" + fp->filename;
|
|
||||||
fp->archiveIndex = ret;
|
|
||||||
fp->mode = FCEUFILE::READ;
|
|
||||||
fp->size = fi.uncompressed_size;
|
|
||||||
fp->stream = ms;
|
|
||||||
fp->archiveCount = (int)asr.numFilesInArchive;
|
|
||||||
ms->fseek(0,SEEK_SET); //rewind so that the rom analyzer sees a freshly opened file
|
|
||||||
|
|
||||||
unzClose( zf );
|
|
||||||
|
|
||||||
return fp;
|
return fp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -92,7 +92,6 @@ int openPPUViewWindow( QWidget *parent )
|
||||||
{
|
{
|
||||||
ppuViewWindow->activateWindow();
|
ppuViewWindow->activateWindow();
|
||||||
ppuViewWindow->raise();
|
ppuViewWindow->raise();
|
||||||
ppuViewWindow->setFocus();
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
initPPUViewer();
|
initPPUViewer();
|
||||||
|
@ -110,7 +109,6 @@ int openOAMViewWindow( QWidget *parent )
|
||||||
{
|
{
|
||||||
spriteViewWindow->activateWindow();
|
spriteViewWindow->activateWindow();
|
||||||
spriteViewWindow->raise();
|
spriteViewWindow->raise();
|
||||||
spriteViewWindow->setFocus();
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
initPPUViewer();
|
initPPUViewer();
|
||||||
|
@ -637,8 +635,8 @@ QPoint ppuPatternView_t::convPixToTile( QPoint p )
|
||||||
w = pattern->w;
|
w = pattern->w;
|
||||||
h = pattern->h;
|
h = pattern->h;
|
||||||
|
|
||||||
i = x / (w*8);
|
i = w == 0 ? 0 : x / (w*8);
|
||||||
j = y / (h*8);
|
j = h == 0 ? 0 : y / (h*8);
|
||||||
|
|
||||||
if ( PPUView_sprite16Mode[ patternIndex ] )
|
if ( PPUView_sprite16Mode[ patternIndex ] )
|
||||||
{
|
{
|
||||||
|
@ -3338,8 +3336,8 @@ QPoint oamPatternView_t::convPixToTile( QPoint p )
|
||||||
w = oamPattern.w;
|
w = oamPattern.w;
|
||||||
h = oamPattern.h;
|
h = oamPattern.h;
|
||||||
|
|
||||||
i = x / (w*8);
|
i = w == 0 ? 0 : x / (w*8);
|
||||||
j = y / (h*16);
|
j = h == 0 ? 0 : y / (h*16);
|
||||||
|
|
||||||
//printf("(x,y) = (%i,%i) w=%i h=%i $%X%X \n", x, y, w, h, jj, ii );
|
//printf("(x,y) = (%i,%i) w=%i h=%i $%X%X \n", x, y, w, h, jj, ii );
|
||||||
|
|
||||||
|
|
|
@ -1235,7 +1235,7 @@ void DeleteBreak(int sel)
|
||||||
if(sel<0) return;
|
if(sel<0) return;
|
||||||
if(sel>=numWPs) return;
|
if(sel>=numWPs) return;
|
||||||
if (watchpoint[sel].cond)
|
if (watchpoint[sel].cond)
|
||||||
freeTree(watchpoint[sel].cond);
|
delete watchpoint[sel].cond;
|
||||||
if (watchpoint[sel].condText)
|
if (watchpoint[sel].condText)
|
||||||
free(watchpoint[sel].condText);
|
free(watchpoint[sel].condText);
|
||||||
if (watchpoint[sel].desc)
|
if (watchpoint[sel].desc)
|
||||||
|
|
46
src/fceu.cpp
46
src/fceu.cpp
|
@ -116,6 +116,7 @@ bool movieSubtitles = true; //Toggle for displaying movie subtitles
|
||||||
bool DebuggerWasUpdated = false; //To prevent the debugger from updating things without being updated.
|
bool DebuggerWasUpdated = false; //To prevent the debugger from updating things without being updated.
|
||||||
bool AutoResumePlay = false;
|
bool AutoResumePlay = false;
|
||||||
char romNameWhenClosingEmulator[2048] = {0};
|
char romNameWhenClosingEmulator[2048] = {0};
|
||||||
|
static unsigned int pauseTimer = 0;
|
||||||
|
|
||||||
|
|
||||||
FCEUGI::FCEUGI()
|
FCEUGI::FCEUGI()
|
||||||
|
@ -764,6 +765,22 @@ void FCEUI_Emulate(uint8 **pXBuf, int32 **SoundBuf, int32 *SoundBufSize, int ski
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (EmulationPaused & EMULATIONPAUSED_TIMER)
|
||||||
|
{
|
||||||
|
if (pauseTimer > 0)
|
||||||
|
{
|
||||||
|
pauseTimer--;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
EmulationPaused &= ~EMULATIONPAUSED_TIMER;
|
||||||
|
}
|
||||||
|
if (EmulationPaused & EMULATIONPAUSED_PAUSED)
|
||||||
|
{
|
||||||
|
EmulationPaused &= ~EMULATIONPAUSED_TIMER;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (EmulationPaused & EMULATIONPAUSED_FA)
|
if (EmulationPaused & EMULATIONPAUSED_FA)
|
||||||
{
|
{
|
||||||
// the user is holding Frame Advance key
|
// the user is holding Frame Advance key
|
||||||
|
@ -787,7 +804,7 @@ void FCEUI_Emulate(uint8 **pXBuf, int32 **SoundBuf, int32 *SoundBufSize, int ski
|
||||||
RefreshThrottleFPS();
|
RefreshThrottleFPS();
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
if (EmulationPaused & EMULATIONPAUSED_PAUSED)
|
if (EmulationPaused & (EMULATIONPAUSED_PAUSED | EMULATIONPAUSED_TIMER) )
|
||||||
{
|
{
|
||||||
// emulator is paused
|
// emulator is paused
|
||||||
memcpy(XBuf, XBackBuf, 256*256);
|
memcpy(XBuf, XBackBuf, 256*256);
|
||||||
|
@ -1263,6 +1280,33 @@ void FCEUI_FrameAdvance(void) {
|
||||||
frameAdvanceRequested = true;
|
frameAdvanceRequested = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void FCEUI_PauseForDuration(int secs)
|
||||||
|
{
|
||||||
|
int framesPerSec;
|
||||||
|
|
||||||
|
// If already paused, do nothing
|
||||||
|
if (EmulationPaused & EMULATIONPAUSED_PAUSED)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (PAL || dendy)
|
||||||
|
{
|
||||||
|
framesPerSec = 50;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
framesPerSec = 60;
|
||||||
|
}
|
||||||
|
pauseTimer = framesPerSec * secs;
|
||||||
|
EmulationPaused |= EMULATIONPAUSED_TIMER;
|
||||||
|
}
|
||||||
|
|
||||||
|
int FCEUI_PauseFramesRemaining(void)
|
||||||
|
{
|
||||||
|
return (EmulationPaused & EMULATIONPAUSED_TIMER) ? pauseTimer : 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int AutosaveCounter = 0;
|
static int AutosaveCounter = 0;
|
||||||
|
|
||||||
void UpdateAutosave(void) {
|
void UpdateAutosave(void) {
|
||||||
|
|
|
@ -181,8 +181,9 @@ extern uint8 vsdip;
|
||||||
|
|
||||||
#define ARRAY_SIZE(a) (sizeof(a)/sizeof(a[0]))
|
#define ARRAY_SIZE(a) (sizeof(a)/sizeof(a[0]))
|
||||||
|
|
||||||
#define EMULATIONPAUSED_PAUSED 1
|
#define EMULATIONPAUSED_PAUSED 0x01
|
||||||
#define EMULATIONPAUSED_FA 2
|
#define EMULATIONPAUSED_TIMER 0x02
|
||||||
|
#define EMULATIONPAUSED_FA 0x04
|
||||||
|
|
||||||
#define FRAMEADVANCE_DELAY_DEFAULT 10
|
#define FRAMEADVANCE_DELAY_DEFAULT 10
|
||||||
#define NES_HEADER_SIZE 16
|
#define NES_HEADER_SIZE 16
|
||||||
|
|
157
src/state.cpp
157
src/state.cpp
|
@ -84,9 +84,9 @@ bool backupSavestates = true;
|
||||||
bool compressSavestates = true; //By default FCEUX compresses savestates when a movie is inactive.
|
bool compressSavestates = true; //By default FCEUX compresses savestates when a movie is inactive.
|
||||||
|
|
||||||
// a temp memory stream. We'll be dumping some data here and then compress
|
// a temp memory stream. We'll be dumping some data here and then compress
|
||||||
EMUFILE_MEMORY memory_savestate;
|
static EMUFILE_MEMORY memory_savestate;
|
||||||
// temporary buffer for compressed data of a savestate
|
// temporary buffer for compressed data of a savestate
|
||||||
std::vector<uint8> compressed_buf;
|
static std::vector<uint8> compressed_buf;
|
||||||
|
|
||||||
#define SFMDATA_SIZE (128)
|
#define SFMDATA_SIZE (128)
|
||||||
static SFORMAT SFMDATA[SFMDATA_SIZE];
|
static SFORMAT SFMDATA[SFMDATA_SIZE];
|
||||||
|
@ -1218,6 +1218,10 @@ class StateRecorder
|
||||||
|
|
||||||
void loadConfig( StateRecorderConfigData &config )
|
void loadConfig( StateRecorderConfigData &config )
|
||||||
{
|
{
|
||||||
|
if (config.framesBetweenSnaps < 1)
|
||||||
|
{
|
||||||
|
config.framesBetweenSnaps = 1;
|
||||||
|
}
|
||||||
if (config.timeBetweenSnapsMinutes < 0.0)
|
if (config.timeBetweenSnapsMinutes < 0.0)
|
||||||
{
|
{
|
||||||
config.timeBetweenSnapsMinutes = 3.0f / 60.0f;
|
config.timeBetweenSnapsMinutes = 3.0f / 60.0f;
|
||||||
|
@ -1226,28 +1230,46 @@ class StateRecorder
|
||||||
{
|
{
|
||||||
config.historyDurationMinutes = config.timeBetweenSnapsMinutes;
|
config.historyDurationMinutes = config.timeBetweenSnapsMinutes;
|
||||||
}
|
}
|
||||||
const double fhistMin = config.historyDurationMinutes;
|
|
||||||
const double fsnapMin = config.timeBetweenSnapsMinutes;
|
|
||||||
const double fnumSnaps = fhistMin / fsnapMin;
|
|
||||||
|
|
||||||
ringBufSize = static_cast<int>( fnumSnaps + 0.5f );
|
if (config.timingMode)
|
||||||
|
{
|
||||||
|
const double fhistMin = config.historyDurationMinutes;
|
||||||
|
const double fsnapMin = config.timeBetweenSnapsMinutes;
|
||||||
|
const double fnumSnaps = fhistMin / fsnapMin;
|
||||||
|
|
||||||
int32_t fps = FCEUI_GetDesiredFPS(); // Do >> 24 to get in Hz
|
ringBufSize = static_cast<int>( fnumSnaps + 0.5f );
|
||||||
|
|
||||||
double hz = ( ((double)fps) / 16777216.0 );
|
int32_t fps = FCEUI_GetDesiredFPS(); // Do >> 24 to get in Hz
|
||||||
|
|
||||||
double framesPerSnapf = hz * fsnapMin * 60.0;
|
double hz = ( ((double)fps) / 16777216.0 );
|
||||||
|
|
||||||
framesPerSnap = static_cast<unsigned int>( framesPerSnapf + 0.50 );
|
double framesPerSnapf = hz * fsnapMin * 60.0;
|
||||||
|
|
||||||
|
framesPerSnap = static_cast<unsigned int>( framesPerSnapf + 0.50 );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
const double fhistMin = config.historyDurationMinutes;
|
||||||
|
int32_t fps = FCEUI_GetDesiredFPS(); // Do >> 24 to get in Hz
|
||||||
|
double hz = ( ((double)fps) / 16777216.0 );
|
||||||
|
|
||||||
|
const double fsnapMin = static_cast<double>(config.framesBetweenSnaps) / (hz * 60.0);
|
||||||
|
const double fnumSnaps = fhistMin / fsnapMin;
|
||||||
|
|
||||||
|
ringBufSize = static_cast<int>( fnumSnaps + 0.5f );
|
||||||
|
framesPerSnap = config.framesBetweenSnaps;
|
||||||
|
}
|
||||||
|
|
||||||
printf("ringBufSize:%i framesPerSnap:%i\n", ringBufSize, framesPerSnap );
|
printf("ringBufSize:%i framesPerSnap:%i\n", ringBufSize, framesPerSnap );
|
||||||
|
|
||||||
compressionLevel = stateRecorderConfig.compressionLevel;
|
compressionLevel = config.compressionLevel;
|
||||||
|
loadPauseTime = config.loadPauseTimeSeconds;
|
||||||
|
pauseOnLoad = config.pauseOnLoad;
|
||||||
}
|
}
|
||||||
|
|
||||||
void update(void)
|
void update(void)
|
||||||
{
|
{
|
||||||
bool isPaused = FCEUI_EmulationPaused() ? true : false;
|
bool isPaused = EmulationPaused ? true : false;
|
||||||
|
|
||||||
unsigned int curFrame = static_cast<unsigned int>(currFrameCounter);
|
unsigned int curFrame = static_cast<unsigned int>(currFrameCounter);
|
||||||
|
|
||||||
|
@ -1311,6 +1333,8 @@ class StateRecorder
|
||||||
|
|
||||||
EMUFILE_MEMORY *em = ringBuf[ snapIdx ];
|
EMUFILE_MEMORY *em = ringBuf[ snapIdx ];
|
||||||
|
|
||||||
|
em->fseek(SEEK_SET, 0);
|
||||||
|
|
||||||
FCEUSS_LoadFP( em, SSLOADPARAM_NOBACKUP );
|
FCEUSS_LoadFP( em, SSLOADPARAM_NOBACKUP );
|
||||||
|
|
||||||
frameCounter = lastLoadFrame = static_cast<unsigned int>(currFrameCounter);
|
frameCounter = lastLoadFrame = static_cast<unsigned int>(currFrameCounter);
|
||||||
|
@ -1318,9 +1342,55 @@ class StateRecorder
|
||||||
lastState = snapIdx;
|
lastState = snapIdx;
|
||||||
loadIndexReset = true;
|
loadIndexReset = true;
|
||||||
|
|
||||||
|
if (pauseOnLoad == StateRecorderConfigData::TEMPORARY_PAUSE)
|
||||||
|
{
|
||||||
|
if (loadPauseTime > 0)
|
||||||
|
{ // Temporary pause after loading new state for user to have time to process
|
||||||
|
FCEUI_PauseForDuration(loadPauseTime);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (pauseOnLoad == StateRecorderConfigData::FULL_PAUSE)
|
||||||
|
{
|
||||||
|
FCEUI_SetEmulationPaused( EMULATIONPAUSED_PAUSED );
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int loadPrevState(void)
|
||||||
|
{
|
||||||
|
int snapIdx = lastState;
|
||||||
|
|
||||||
|
if ( lastState == ringHead )
|
||||||
|
{ // No States to Load
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if ( lastState != ringStart )
|
||||||
|
{
|
||||||
|
if ( (lastLoadFrame+30) > frameCounter)
|
||||||
|
{
|
||||||
|
snapIdx--;
|
||||||
|
|
||||||
|
if (snapIdx < 0)
|
||||||
|
{
|
||||||
|
snapIdx += ringBufSize;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return loadStateByIndex( snapIdx );
|
||||||
|
}
|
||||||
|
|
||||||
|
int loadNextState(void)
|
||||||
|
{
|
||||||
|
int snapIdx = lastState;
|
||||||
|
int nextIdx = (lastState + 1) % ringBufSize;
|
||||||
|
|
||||||
|
if ( nextIdx != ringHead )
|
||||||
|
{
|
||||||
|
snapIdx = nextIdx;
|
||||||
|
}
|
||||||
|
return loadStateByIndex( snapIdx );
|
||||||
|
}
|
||||||
|
|
||||||
int getHeadIndex(void)
|
int getHeadIndex(void)
|
||||||
{
|
{
|
||||||
return ringHead;
|
return ringHead;
|
||||||
|
@ -1347,6 +1417,10 @@ class StateRecorder
|
||||||
return ringBuf.size() * ringBuf[0]->size();
|
return ringBuf.size() * ringBuf[0]->size();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
size_t ringBufferSize(void)
|
||||||
|
{
|
||||||
|
return ringBuf.size();
|
||||||
|
}
|
||||||
static bool enabled;
|
static bool enabled;
|
||||||
static int lastState;
|
static int lastState;
|
||||||
private:
|
private:
|
||||||
|
@ -1362,6 +1436,8 @@ class StateRecorder
|
||||||
int ringStart;
|
int ringStart;
|
||||||
int ringBufSize;
|
int ringBufSize;
|
||||||
int compressionLevel;
|
int compressionLevel;
|
||||||
|
int loadPauseTime;
|
||||||
|
StateRecorderConfigData::PauseType pauseOnLoad;
|
||||||
unsigned int frameCounter;
|
unsigned int frameCounter;
|
||||||
unsigned int framesPerSnap;
|
unsigned int framesPerSnap;
|
||||||
unsigned int lastLoadFrame;
|
unsigned int lastLoadFrame;
|
||||||
|
@ -1415,13 +1491,37 @@ bool FCEU_StateRecorderRunning(void)
|
||||||
return stateRecorder != nullptr;
|
return stateRecorder != nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
int FCEU_StateRecorderLoadState(int snapIndex)
|
int FCEU_StateRecorderGetMaxSnaps(void)
|
||||||
{
|
{
|
||||||
|
int size = 0;
|
||||||
|
|
||||||
if (stateRecorder != nullptr)
|
if (stateRecorder != nullptr)
|
||||||
{
|
{
|
||||||
stateRecorder->loadStateByIndex(snapIndex);
|
size = stateRecorder->ringBufferSize();
|
||||||
}
|
}
|
||||||
return 0;
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
int FCEU_StateRecorderGetNumSnapsSaved(void)
|
||||||
|
{
|
||||||
|
int n = 0;
|
||||||
|
|
||||||
|
if (stateRecorder != nullptr)
|
||||||
|
{
|
||||||
|
n = stateRecorder->numSnapsSaved();
|
||||||
|
}
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
int FCEU_StateRecorderLoadState(int snapIndex)
|
||||||
|
{
|
||||||
|
int ret = -1;
|
||||||
|
|
||||||
|
if (stateRecorder != nullptr)
|
||||||
|
{
|
||||||
|
ret = stateRecorder->loadStateByIndex(snapIndex);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
int FCEU_StateRecorderGetStateIndex(void)
|
int FCEU_StateRecorderGetStateIndex(void)
|
||||||
|
@ -1429,6 +1529,28 @@ int FCEU_StateRecorderGetStateIndex(void)
|
||||||
return StateRecorder::lastState;
|
return StateRecorder::lastState;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int FCEU_StateRecorderLoadPrevState(void)
|
||||||
|
{
|
||||||
|
int ret = -1;
|
||||||
|
|
||||||
|
if (stateRecorder != nullptr)
|
||||||
|
{
|
||||||
|
ret = stateRecorder->loadPrevState();
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int FCEU_StateRecorderLoadNextState(void)
|
||||||
|
{
|
||||||
|
int ret = -1;
|
||||||
|
|
||||||
|
if (stateRecorder != nullptr)
|
||||||
|
{
|
||||||
|
ret = stateRecorder->loadNextState();
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
const StateRecorderConfigData& FCEU_StateRecorderGetConfigData(void)
|
const StateRecorderConfigData& FCEU_StateRecorderGetConfigData(void)
|
||||||
{
|
{
|
||||||
return stateRecorderConfig;
|
return stateRecorderConfig;
|
||||||
|
@ -1436,5 +1558,10 @@ const StateRecorderConfigData& FCEU_StateRecorderGetConfigData(void)
|
||||||
int FCEU_StateRecorderSetConfigData(const StateRecorderConfigData &newConfig)
|
int FCEU_StateRecorderSetConfigData(const StateRecorderConfigData &newConfig)
|
||||||
{
|
{
|
||||||
stateRecorderConfig = newConfig;
|
stateRecorderConfig = newConfig;
|
||||||
|
|
||||||
|
if (stateRecorder != nullptr)
|
||||||
|
{
|
||||||
|
stateRecorder->loadConfig( stateRecorderConfig );
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
29
src/state.h
29
src/state.h
|
@ -17,6 +17,7 @@
|
||||||
* along with this program; if not, write to the Free Software
|
* along with this program; if not, write to the Free Software
|
||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
|
#pragma once
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
enum ENUM_SSLOADPARAMS
|
enum ENUM_SSLOADPARAMS
|
||||||
|
@ -83,13 +84,37 @@ struct StateRecorderConfigData
|
||||||
{
|
{
|
||||||
float historyDurationMinutes;
|
float historyDurationMinutes;
|
||||||
float timeBetweenSnapsMinutes;
|
float timeBetweenSnapsMinutes;
|
||||||
|
int framesBetweenSnaps;
|
||||||
int compressionLevel;
|
int compressionLevel;
|
||||||
|
int loadPauseTimeSeconds;
|
||||||
|
|
||||||
|
enum TimingType
|
||||||
|
{
|
||||||
|
FRAMES = 0,
|
||||||
|
TIME,
|
||||||
|
} timingMode;
|
||||||
|
|
||||||
|
enum PauseType
|
||||||
|
{
|
||||||
|
NO_PAUSE = 0,
|
||||||
|
TEMPORARY_PAUSE,
|
||||||
|
FULL_PAUSE,
|
||||||
|
} pauseOnLoad;
|
||||||
|
|
||||||
StateRecorderConfigData(void)
|
StateRecorderConfigData(void)
|
||||||
{
|
{
|
||||||
|
framesBetweenSnaps = 60;
|
||||||
historyDurationMinutes = 15.0f;
|
historyDurationMinutes = 15.0f;
|
||||||
timeBetweenSnapsMinutes = 3.0f / 60.0f;
|
timeBetweenSnapsMinutes = 3.0f / 60.0f;
|
||||||
compressionLevel = 0;
|
compressionLevel = 0;
|
||||||
|
loadPauseTimeSeconds = 3;
|
||||||
|
pauseOnLoad = TEMPORARY_PAUSE;
|
||||||
|
timingMode = FRAMES;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool compare( const StateRecorderConfigData &other )
|
||||||
|
{
|
||||||
|
return memcmp( this, &other, sizeof(StateRecorderConfigData) ) == 0;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -99,7 +124,11 @@ int FCEU_StateRecorderUpdate(void);
|
||||||
bool FCEU_StateRecorderRunning(void);
|
bool FCEU_StateRecorderRunning(void);
|
||||||
bool FCEU_StateRecorderIsEnabled(void);
|
bool FCEU_StateRecorderIsEnabled(void);
|
||||||
void FCEU_StateRecorderSetEnabled(bool enabled);
|
void FCEU_StateRecorderSetEnabled(bool enabled);
|
||||||
|
int FCEU_StateRecorderGetMaxSnaps(void);
|
||||||
|
int FCEU_StateRecorderGetNumSnapsSaved(void);
|
||||||
int FCEU_StateRecorderGetStateIndex(void);
|
int FCEU_StateRecorderGetStateIndex(void);
|
||||||
int FCEU_StateRecorderLoadState(int snapIndex);
|
int FCEU_StateRecorderLoadState(int snapIndex);
|
||||||
|
int FCEU_StateRecorderLoadPrevState(void);
|
||||||
|
int FCEU_StateRecorderLoadNextState(void);
|
||||||
int FCEU_StateRecorderSetConfigData(const StateRecorderConfigData &newConfig);
|
int FCEU_StateRecorderSetConfigData(const StateRecorderConfigData &newConfig);
|
||||||
const StateRecorderConfigData& FCEU_StateRecorderGetConfigData(void);
|
const StateRecorderConfigData& FCEU_StateRecorderGetConfigData(void);
|
||||||
|
|
|
@ -87,6 +87,8 @@ std::string AsSnapshotName =""; //adelikat:this will set the snapshot name whe
|
||||||
void FCEUI_SetSnapshotAsName(std::string name) { AsSnapshotName = name; }
|
void FCEUI_SetSnapshotAsName(std::string name) { AsSnapshotName = name; }
|
||||||
std::string FCEUI_GetSnapshotAsName() { return AsSnapshotName; }
|
std::string FCEUI_GetSnapshotAsName() { return AsSnapshotName; }
|
||||||
|
|
||||||
|
static void FCEU_DrawPauseCountDown(uint8 *XBuf);
|
||||||
|
|
||||||
void FCEU_KillVirtualVideo(void)
|
void FCEU_KillVirtualVideo(void)
|
||||||
{
|
{
|
||||||
if ( XBuf )
|
if ( XBuf )
|
||||||
|
@ -254,6 +256,7 @@ void FCEU_PutImage(void)
|
||||||
FCEU_DrawLagCounter(XBuf);
|
FCEU_DrawLagCounter(XBuf);
|
||||||
FCEU_DrawNTSCControlBars(XBuf);
|
FCEU_DrawNTSCControlBars(XBuf);
|
||||||
FCEU_DrawRecordingStatus(XBuf);
|
FCEU_DrawRecordingStatus(XBuf);
|
||||||
|
FCEU_DrawPauseCountDown(XBuf);
|
||||||
ShowFPS();
|
ShowFPS();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -771,3 +774,35 @@ void ShowFPS(void)
|
||||||
|
|
||||||
DrawTextTrans(XBuf + ((256 - ClipSidesOffset) - 40) + (FSettings.FirstSLine + 4) * 256, 256, (uint8*)fpsmsg, 0xA0);
|
DrawTextTrans(XBuf + ((256 - ClipSidesOffset) - 40) + (FSettings.FirstSLine + 4) * 256, 256, (uint8*)fpsmsg, 0xA0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool showPauseCountDown = true;
|
||||||
|
|
||||||
|
static void FCEU_DrawPauseCountDown(uint8 *XBuf)
|
||||||
|
{
|
||||||
|
if (EmulationPaused & EMULATIONPAUSED_TIMER)
|
||||||
|
{
|
||||||
|
int pauseFramesLeft = FCEUI_PauseFramesRemaining();
|
||||||
|
|
||||||
|
if (showPauseCountDown && (pauseFramesLeft > 0) )
|
||||||
|
{
|
||||||
|
char text[32];
|
||||||
|
int framesPerSec;
|
||||||
|
|
||||||
|
if (PAL || dendy)
|
||||||
|
{
|
||||||
|
framesPerSec = 50;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
framesPerSec = 60;
|
||||||
|
}
|
||||||
|
|
||||||
|
sprintf(text, "Unpausing in %d...", (pauseFramesLeft / framesPerSec) + 1);
|
||||||
|
|
||||||
|
if (text[0])
|
||||||
|
{
|
||||||
|
DrawTextTrans(XBuf + ClipSidesOffset + (FSettings.FirstSLine) * 256, 256, (uint8*)text, 0xA0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue