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
|
||||
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
|
||||
#sudo apt-get install libgtk2.0-dev
|
||||
|
||||
|
|
|
@ -70,6 +70,12 @@ echo 'Install Dependency minizip'
|
|||
echo '****************************************'
|
||||
brew install minizip
|
||||
|
||||
echo '****************************************'
|
||||
echo 'Install Optional Dependency libarchive'
|
||||
echo '****************************************'
|
||||
brew install libarchive
|
||||
LIBARCHIVE_PATH=`brew --prefix libarchive`;
|
||||
|
||||
echo '****************************************'
|
||||
echo 'Install Optional Dependency x264'
|
||||
echo '****************************************'
|
||||
|
@ -87,7 +93,7 @@ brew install ffmpeg
|
|||
|
||||
#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;
|
||||
|
||||
|
|
|
@ -24,28 +24,33 @@ mkdir bin
|
|||
|
||||
set SDL_VERSION=2.24.1
|
||||
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/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
|
||||
|
||||
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" libarchive-v%LIBARCHIVE_VERSION%-amd64.zip
|
||||
|
||||
rename SDL2-%SDL_VERSION% SDL2
|
||||
move ffmpeg-%FFMPEG_VERSION%-full_build-shared\ffmpeg-%FFMPEG_VERSION%-full_build-shared ffmpeg
|
||||
rmdir ffmpeg-%FFMPEG_VERSION%-full_build-shared
|
||||
del ffmpeg-%FFMPEG_VERSION%-full_build-shared.zip
|
||||
move libarchive-v%LIBARCHIVE_VERSION%-amd64\libarchive libarchive
|
||||
|
||||
set SDL_INSTALL_PREFIX=%CD%
|
||||
set FFMPEG_INSTALL_PREFIX=%CD%
|
||||
set LIBARCHIVE_INSTALL_PREFIX=%CD%
|
||||
set PUBLIC_RELEASE=0
|
||||
IF DEFINED FCEU_RELEASE_VERSION (set PUBLIC_RELEASE=1)
|
||||
|
||||
REM cmake -h
|
||||
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
|
||||
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 %PROJECT_ROOT%\src\auxlib.lua bin\.
|
||||
REM 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\lua51.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 %LIBARCHIVE_INSTALL_PREFIX%\libarchive\bin\archive.dll bin\.
|
||||
copy %FFMPEG_INSTALL_PREFIX%\ffmpeg\bin\*.dll bin\.
|
||||
|
||||
windeployqt --no-compiler-runtime bin\qfceux.exe
|
||||
|
|
|
@ -41,12 +41,15 @@ if(WIN32)
|
|||
add_definitions( -DMSVC -D_CRT_SECURE_NO_WARNINGS )
|
||||
add_definitions( -D__SDL__ -D__QT_DRIVER__ -DQT_DEPRECATED_WARNINGS )
|
||||
add_definitions( -DFCEUDEF_DEBUGGER )
|
||||
add_definitions( -D_USE_LIBARCHIVE )
|
||||
add_definitions( /wd4267 /wd4244 )
|
||||
#add_definitions( /wd4018 ) # Integer comparison sign mismatch warnings
|
||||
include_directories( ${SDL_INSTALL_PREFIX}/SDL2/include )
|
||||
include_directories( ${LIBARCHIVE_INSTALL_PREFIX}/libarchive/include )
|
||||
include_directories( ${CMAKE_CURRENT_SOURCE_DIR}/drivers/win/zlib )
|
||||
set( OPENGL_LDFLAGS OpenGL::GL )
|
||||
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(APP_ICON_RESOURCES_WINDOWS ${CMAKE_SOURCE_DIR}/icons/fceux.rc )
|
||||
|
||||
|
@ -110,6 +113,13 @@ else(WIN32)
|
|||
add_definitions( -D_SYSTEM_MINIZIP ${MINIZIP_CFLAGS} )
|
||||
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)
|
||||
|
||||
if ( ${X264_FOUND} )
|
||||
|
@ -643,7 +653,7 @@ target_link_libraries( ${APP_NAME} ${ASAN_LDFLAGS}
|
|||
${${Qt}OpenGLWidgets_LIBRARIES}
|
||||
${OPENGL_LDFLAGS}
|
||||
${SDL2_LDFLAGS}
|
||||
${MINIZIP_LDFLAGS} ${ZLIB_LIBRARIES}
|
||||
${MINIZIP_LDFLAGS} ${ZLIB_LIBRARIES} ${LIBARCHIVE_LDFLAGS}
|
||||
${LUA_LDFLAGS} ${X264_LDFLAGS} ${X265_LDFLAGS} ${LIBAV_LDFLAGS}
|
||||
${SYS_LIBS}
|
||||
)
|
||||
|
|
|
@ -27,6 +27,7 @@ static void (*WSync)(void);
|
|||
static readfunc defread;
|
||||
static uint8 *WRAM = NULL;
|
||||
static uint32 WRAMSIZE=0;
|
||||
static uint8 hasBattery = 0;
|
||||
|
||||
static DECLFW(LatchWrite) {
|
||||
latche = A;
|
||||
|
@ -358,20 +359,17 @@ void Mapper217_Init(CartInfo *info) {
|
|||
}
|
||||
|
||||
//------------------ Map 227 ---------------------------
|
||||
|
||||
static void M227Sync(void) {
|
||||
uint32 S = latche & 1;
|
||||
uint32 p = ((latche >> 2) & 0x1F) + ((latche & 0x100) >> 3);
|
||||
uint32 L = (latche >> 9) & 1;
|
||||
|
||||
// ok, according to nesdev wiki (refrenced to the nesdev dumping thread) there is a CHR write protection bit7.
|
||||
// however, this bit clearly determined a specific PRG layout for some game but does not meant to have additional
|
||||
// functionality. as I see from the menu code, it disables the chr writing before run an actual game.
|
||||
// this fix here makes happy both waixing rpgs and multigame menus at once. can't veryfy it on a hardware
|
||||
// but if I find some i'll definitly do this.
|
||||
|
||||
if ((latche & 0xF000) == 0xF000)
|
||||
SetupCartCHRMapping(0, CHRptr[0], 0x2000, 0);
|
||||
// Only Waixing appear to have battery flag enabled, while multicarts don't.
|
||||
// Multicarts needs CHR-RAM protect in NROM modes, so only apply CHR-RAM protect
|
||||
// on non battery-enabled carts.
|
||||
if (!hasBattery && (latche & 0x80) == 0x80)
|
||||
/* CHR-RAM write protect hack, needed for some multicarts */
|
||||
SetupCartCHRMapping(0, CHRptr[0], 0x2000, 0);
|
||||
else
|
||||
SetupCartCHRMapping(0, CHRptr[0], 0x2000, 1);
|
||||
|
||||
|
@ -409,6 +407,7 @@ static void M227Sync(void) {
|
|||
|
||||
void Mapper227_Init(CartInfo *info) {
|
||||
Latch_Init(info, M227Sync, NULL, 0x0000, 0x8000, 0xFFFF, 1);
|
||||
hasBattery = info->battery;
|
||||
}
|
||||
|
||||
//------------------ Map 229 ---------------------------
|
||||
|
|
|
@ -52,17 +52,17 @@
|
|||
#include <cctype>
|
||||
|
||||
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
|
||||
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');
|
||||
}
|
||||
|
||||
void scan(const char** str)
|
||||
static void scan(const char** str)
|
||||
{
|
||||
do
|
||||
{
|
||||
|
@ -71,40 +71,37 @@ void scan(const char** str)
|
|||
} 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 ')'
|
||||
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* t1;
|
||||
Condition* mid;
|
||||
int op;
|
||||
|
||||
if (t == nullptr)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
while ((op = operators(str)))
|
||||
{
|
||||
scan(str);
|
||||
|
||||
t1 = nextPart(str);
|
||||
|
||||
if (t1 == 0)
|
||||
if (t1 == nullptr)
|
||||
{
|
||||
if(t)
|
||||
freeTree(t);
|
||||
delete t;
|
||||
return 0;
|
||||
}
|
||||
|
||||
mid = (Condition*)FCEU_dmalloc(sizeof(Condition));
|
||||
if (!mid)
|
||||
return NULL;
|
||||
memset(mid, 0, sizeof(Condition));
|
||||
mid = new Condition();
|
||||
if (mid == nullptr)
|
||||
{
|
||||
delete t;
|
||||
delete t1;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
mid->lhs = t;
|
||||
mid->rhs = t1;
|
||||
|
@ -117,7 +114,7 @@ Condition* InfixOperator(const char** str, Condition(*nextPart(const char**)), i
|
|||
}
|
||||
|
||||
// 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)
|
||||
{
|
||||
|
@ -131,43 +128,43 @@ int TwoCharOperator(const char** str, char c1, char c2, int op)
|
|||
}
|
||||
|
||||
// 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';
|
||||
}
|
||||
|
||||
// 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';
|
||||
}
|
||||
|
||||
// Determines if a character is for PC bank
|
||||
int isPCBank(char c)
|
||||
static int isPCBank(char c)
|
||||
{
|
||||
return c == 'K';
|
||||
}
|
||||
|
||||
// Determines if a character is for Data bank
|
||||
int isDataBank(char c)
|
||||
static int isDataBank(char c)
|
||||
{
|
||||
return c == 'T';
|
||||
}
|
||||
|
||||
// Determines if a character is for value read
|
||||
int isValueRead(char c)
|
||||
static int isValueRead(char c)
|
||||
{
|
||||
return c == 'R';
|
||||
}
|
||||
|
||||
// Determines if a character is for value write
|
||||
int isValueWrite(char c)
|
||||
static int isValueWrite(char c)
|
||||
{
|
||||
return c == 'W';
|
||||
}
|
||||
|
||||
// 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];
|
||||
|
||||
|
@ -185,10 +182,10 @@ int getNumber(unsigned int* number, const char** str)
|
|||
return 1;
|
||||
}
|
||||
|
||||
Condition* Connect(const char** str);
|
||||
static Condition* Connect(const char** str);
|
||||
|
||||
// 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)
|
||||
{
|
||||
|
@ -216,7 +213,7 @@ Condition* Parentheses(const char** str, Condition* c, char openPar, char closeP
|
|||
* Check for primitives
|
||||
* 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 */
|
||||
{
|
||||
|
@ -394,24 +391,22 @@ Condition* Primitive(const char** str, Condition* c)
|
|||
}
|
||||
|
||||
/* Handle * and / operators */
|
||||
Condition* Term(const char** str)
|
||||
static Condition* Term(const char** str)
|
||||
{
|
||||
Condition* t;
|
||||
Condition* t1;
|
||||
Condition* mid;
|
||||
|
||||
t = (Condition*)FCEU_dmalloc(sizeof(Condition));
|
||||
t = new Condition();
|
||||
|
||||
if (!t)
|
||||
if (t == nullptr)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memset(t, 0, sizeof(Condition));
|
||||
|
||||
if (!Primitive(str, t))
|
||||
{
|
||||
freeTree(t);
|
||||
delete t;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -421,22 +416,25 @@ Condition* Term(const char** str)
|
|||
|
||||
scan(str);
|
||||
|
||||
if (!(t1 = (Condition*)FCEU_dmalloc(sizeof(Condition))))
|
||||
return NULL;
|
||||
|
||||
memset(t1, 0, sizeof(Condition));
|
||||
if ((t1 = new Condition()) == nullptr)
|
||||
{
|
||||
delete t;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!Primitive(str, t1))
|
||||
{
|
||||
freeTree(t);
|
||||
freeTree(t1);
|
||||
delete t;
|
||||
delete t1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(mid = (Condition*)FCEU_dmalloc(sizeof(Condition))))
|
||||
return NULL;
|
||||
|
||||
memset(mid, 0, sizeof(Condition));
|
||||
if ((mid = new Condition()) == nullptr)
|
||||
{
|
||||
delete t;
|
||||
delete t1;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
mid->lhs = t;
|
||||
mid->rhs = t1;
|
||||
|
@ -449,7 +447,7 @@ Condition* Term(const char** str)
|
|||
}
|
||||
|
||||
/* Check for + and - operators */
|
||||
int SumOperators(const char** str)
|
||||
static int SumOperators(const char** str)
|
||||
{
|
||||
switch (next)
|
||||
{
|
||||
|
@ -460,13 +458,13 @@ int SumOperators(const char** str)
|
|||
}
|
||||
|
||||
/* Handle + and - operators */
|
||||
Condition* Sum(const char** str)
|
||||
static Condition* Sum(const char** str)
|
||||
{
|
||||
return InfixOperator(str, Term, SumOperators);
|
||||
}
|
||||
|
||||
/* Check for <=, =>, ==, !=, > and < operators */
|
||||
int CompareOperators(const char** str)
|
||||
static int CompareOperators(const char** str)
|
||||
{
|
||||
int val = TwoCharOperator(str, '=', '=', OP_EQ);
|
||||
if (val) return val;
|
||||
|
@ -490,13 +488,13 @@ int CompareOperators(const char** str)
|
|||
}
|
||||
|
||||
/* Handle <=, =>, ==, !=, > and < operators */
|
||||
Condition* Compare(const char** str)
|
||||
static Condition* Compare(const char** str)
|
||||
{
|
||||
return InfixOperator(str, Sum, CompareOperators);
|
||||
}
|
||||
|
||||
/* Check for || or && operators */
|
||||
int ConnectOperators(const char** str)
|
||||
static int ConnectOperators(const char** str)
|
||||
{
|
||||
int val = TwoCharOperator(str, '|', '|', OP_OR);
|
||||
if(val) return val;
|
||||
|
@ -508,7 +506,7 @@ int ConnectOperators(const char** str)
|
|||
}
|
||||
|
||||
/* Handle || and && operators */
|
||||
Condition* Connect(const char** str)
|
||||
static Condition* Connect(const char** str)
|
||||
{
|
||||
return InfixOperator(str, Compare, ConnectOperators);
|
||||
}
|
||||
|
@ -521,6 +519,10 @@ Condition* generateCondition(const char* str)
|
|||
scan(&str);
|
||||
c = Connect(&str);
|
||||
|
||||
if (!c || next != 0) return 0;
|
||||
if (!c || next != 0)
|
||||
{
|
||||
if (c) delete c;
|
||||
return 0;
|
||||
}
|
||||
else return c;
|
||||
}
|
||||
|
|
|
@ -61,9 +61,28 @@ struct Condition
|
|||
|
||||
unsigned int type2;
|
||||
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);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -19,10 +19,15 @@ unsigned int debuggerPageSize = 14;
|
|||
int vblankScanLines = 0; //Used to calculate scanlines 240-261 (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;
|
||||
|
||||
if (conversionOk)
|
||||
{
|
||||
*conversionOk = false;
|
||||
}
|
||||
|
||||
if (sscanf(offsetBuffer,"%7X",(unsigned int *)&offset) == EOF)
|
||||
{
|
||||
return -1;
|
||||
|
@ -30,14 +35,26 @@ int offsetStringToInt(unsigned int type, const char* offsetBuffer)
|
|||
|
||||
if (type & BT_P)
|
||||
{
|
||||
if (conversionOk)
|
||||
{
|
||||
*conversionOk = (offset >= 0) && (offset < 0x4000);
|
||||
}
|
||||
return offset & 0x3FFF;
|
||||
}
|
||||
else if (type & BT_S)
|
||||
{
|
||||
if (conversionOk)
|
||||
{
|
||||
*conversionOk = (offset >= 0) && (offset < 0x100);
|
||||
}
|
||||
return offset & 0x00FF;
|
||||
}
|
||||
else if (type & BT_R)
|
||||
{
|
||||
if (conversionOk)
|
||||
{
|
||||
*conversionOk = (offset >= 0);
|
||||
}
|
||||
return offset;
|
||||
}
|
||||
else // BT_C
|
||||
|
@ -46,6 +63,10 @@ int offsetStringToInt(unsigned int type, const char* offsetBuffer)
|
|||
|
||||
if (sym)
|
||||
{
|
||||
if (conversionOk)
|
||||
{
|
||||
*conversionOk = true;
|
||||
}
|
||||
return sym->offset() & 0xFFFF;
|
||||
}
|
||||
|
||||
|
@ -56,21 +77,26 @@ int offsetStringToInt(unsigned int type, const char* offsetBuffer)
|
|||
type = GameInfo->type;
|
||||
}
|
||||
if (type == GIT_NSF) { //NSF Breakpoint keywords
|
||||
if (strcmp(offsetBuffer,"LOAD") == 0) return (NSFHeader.LoadAddressLow | (NSFHeader.LoadAddressHigh<<8));
|
||||
if (strcmp(offsetBuffer,"INIT") == 0) return (NSFHeader.InitAddressLow | (NSFHeader.InitAddressHigh<<8));
|
||||
if (strcmp(offsetBuffer,"PLAY") == 0) return (NSFHeader.PlayAddressLow | (NSFHeader.PlayAddressHigh<<8));
|
||||
if (strcmp(offsetBuffer,"LOAD") == 0) offset = (NSFHeader.LoadAddressLow | (NSFHeader.LoadAddressHigh<<8));
|
||||
else if (strcmp(offsetBuffer,"INIT") == 0) offset = (NSFHeader.InitAddressLow | (NSFHeader.InitAddressHigh<<8));
|
||||
else if (strcmp(offsetBuffer,"PLAY") == 0) offset = (NSFHeader.PlayAddressLow | (NSFHeader.PlayAddressHigh<<8));
|
||||
}
|
||||
else if (type == GIT_FDS) { //FDS Breakpoint keywords
|
||||
if (strcmp(offsetBuffer,"NMI1") == 0) return (GetMem(0xDFF6) | (GetMem(0xDFF7)<<8));
|
||||
if (strcmp(offsetBuffer,"NMI2") == 0) return (GetMem(0xDFF8) | (GetMem(0xDFF9)<<8));
|
||||
if (strcmp(offsetBuffer,"NMI3") == 0) return (GetMem(0xDFFA) | (GetMem(0xDFFB)<<8));
|
||||
if (strcmp(offsetBuffer,"RST") == 0) return (GetMem(0xDFFC) | (GetMem(0xDFFD)<<8));
|
||||
if ((strcmp(offsetBuffer,"IRQ") == 0) || (strcmp(offsetBuffer,"BRK") == 0)) return (GetMem(0xDFFE) | (GetMem(0xDFFF)<<8));
|
||||
if (strcmp(offsetBuffer,"NMI1") == 0) offset = (GetMem(0xDFF6) | (GetMem(0xDFF7)<<8));
|
||||
else if (strcmp(offsetBuffer,"NMI2") == 0) offset = (GetMem(0xDFF8) | (GetMem(0xDFF9)<<8));
|
||||
else if (strcmp(offsetBuffer,"NMI3") == 0) offset = (GetMem(0xDFFA) | (GetMem(0xDFFB)<<8));
|
||||
else if (strcmp(offsetBuffer,"RST") == 0) offset = (GetMem(0xDFFC) | (GetMem(0xDFFD)<<8));
|
||||
else if ((strcmp(offsetBuffer,"IRQ") == 0) || (strcmp(offsetBuffer,"BRK") == 0)) offset = (GetMem(0xDFFE) | (GetMem(0xDFFF)<<8));
|
||||
}
|
||||
else { //NES Breakpoint keywords
|
||||
if ((strcmp(offsetBuffer,"NMI") == 0) || (strcmp(offsetBuffer,"VBL") == 0)) return (GetMem(0xFFFA) | (GetMem(0xFFFB)<<8));
|
||||
if (strcmp(offsetBuffer,"RST") == 0) return (GetMem(0xFFFC) | (GetMem(0xFFFD)<<8));
|
||||
if ((strcmp(offsetBuffer,"IRQ") == 0) || (strcmp(offsetBuffer,"BRK") == 0)) return (GetMem(0xFFFE) | (GetMem(0xFFFF)<<8));
|
||||
if ((strcmp(offsetBuffer,"NMI") == 0) || (strcmp(offsetBuffer,"VBL") == 0)) offset = (GetMem(0xFFFA) | (GetMem(0xFFFB)<<8));
|
||||
else if (strcmp(offsetBuffer,"RST") == 0) offset = (GetMem(0xFFFC) | (GetMem(0xFFFD)<<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.
|
||||
if (watchpoint[num].cond)
|
||||
{
|
||||
freeTree(watchpoint[num].cond);
|
||||
delete watchpoint[num].cond;
|
||||
free(watchpoint[num].condText);
|
||||
watchpoint[num].cond = 0;
|
||||
watchpoint[num].condText = 0;
|
||||
|
@ -153,8 +179,8 @@ int checkCondition(const char* condition, int num)
|
|||
{
|
||||
watchpoint[num].cond = c;
|
||||
watchpoint[num].condText = (char*)malloc(strlen(condition) + 1);
|
||||
if (!watchpoint[num].condText)
|
||||
return 0;
|
||||
if (!watchpoint[num].condText)
|
||||
return 0;
|
||||
strcpy(watchpoint[num].condText, condition);
|
||||
}
|
||||
else
|
||||
|
@ -169,7 +195,7 @@ int checkCondition(const char* condition, int num)
|
|||
// Remove the old breakpoint condition
|
||||
if (watchpoint[num].cond)
|
||||
{
|
||||
freeTree(watchpoint[num].cond);
|
||||
delete watchpoint[num].cond;
|
||||
free(watchpoint[num].condText);
|
||||
watchpoint[num].cond = 0;
|
||||
watchpoint[num].condText = 0;
|
||||
|
|
|
@ -172,7 +172,7 @@ DebuggerState &FCEUI_Debugger();
|
|||
//#define WRITE_BREAKPOINT 16
|
||||
//#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);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -346,7 +346,7 @@ void FCEU_DrawRecordingStatus(uint8* XBuf)
|
|||
hasPlayRecIcon = true;
|
||||
}
|
||||
|
||||
if(FCEUI_EmulationPaused())
|
||||
if( EmulationPaused & (EMULATIONPAUSED_PAUSED | EMULATIONPAUSED_TIMER) )
|
||||
drawstatus(XBuf-ClipSidesOffset,3,28,hasPlayRecIcon?-16:0);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -273,6 +273,8 @@ void FCEUI_ClearEmulationFrameStepped();
|
|||
void FCEUI_SetEmulationPaused(int val);
|
||||
///toggles the paused bit (bit0) for EmulationPaused. caused FCEUD_DebugUpdate() to fire if the emulation pauses
|
||||
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)
|
||||
bool FCEUD_ShouldDrawInputAids();
|
||||
|
|
|
@ -30,9 +30,14 @@
|
|||
#endif
|
||||
|
||||
#ifdef _USE_X264
|
||||
#include <cstdint>
|
||||
#include "x264.h"
|
||||
#endif
|
||||
|
||||
#ifdef _USE_LIBARCHIVE
|
||||
#include <archive.h>
|
||||
#endif
|
||||
|
||||
#ifdef _USE_LIBAV
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
|
@ -201,6 +206,23 @@ AboutWindow::AboutWindow(QWidget *parent)
|
|||
sprintf( stmp, " Compiled with zlib %s\n", ZLIB_VERSION );
|
||||
credits->insertPlainText( stmp );
|
||||
#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
|
||||
sprintf( stmp, " Compiled with %s\n", LUA_RELEASE );
|
||||
|
|
|
@ -54,7 +54,6 @@ void openCheatDialog(QWidget *parent)
|
|||
{
|
||||
win->activateWindow();
|
||||
win->raise();
|
||||
win->setFocus();
|
||||
return;
|
||||
}
|
||||
win = new GuiCheatsDialog_t(parent);
|
||||
|
@ -705,14 +704,10 @@ int GuiCheatsDialog_t::activeCheatListCB(const char *name, uint32 a, uint8 v, in
|
|||
|
||||
if (item == NULL)
|
||||
{
|
||||
item = new QTreeWidgetItem();
|
||||
|
||||
actvCheatList->addTopLevelItem(item);
|
||||
item = new QTreeWidgetItem(actvCheatList);
|
||||
}
|
||||
|
||||
//item->setFlags( Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsEditable | Qt::ItemIsUserCheckable );
|
||||
item->setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsUserCheckable | Qt::ItemNeverHasChildren);
|
||||
|
||||
item->setCheckState(0, s ? Qt::Checked : Qt::Unchecked);
|
||||
|
||||
item->setText(0, tr(codeStr));
|
||||
|
@ -738,8 +733,6 @@ void GuiCheatsDialog_t::showActiveCheatList(bool redraw)
|
|||
|
||||
enaCheats->setChecked(!globalCheatDisabled);
|
||||
|
||||
actvCheatRedraw = redraw;
|
||||
|
||||
if (redraw)
|
||||
{
|
||||
actvCheatList->clear();
|
||||
|
@ -747,6 +740,8 @@ void GuiCheatsDialog_t::showActiveCheatList(bool redraw)
|
|||
actvCheatIdx = 0;
|
||||
|
||||
FCEUI_ListCheats(::activeCheatListCB, (void *)this);
|
||||
|
||||
actvCheatList->viewport()->update();
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
void GuiCheatsDialog_t::openCheatFile(void)
|
||||
|
|
|
@ -72,7 +72,6 @@ protected:
|
|||
|
||||
int fontCharWidth;
|
||||
int actvCheatIdx;
|
||||
bool actvCheatRedraw;
|
||||
bool pauseWhileActive;
|
||||
bool wasPausedByCheats;
|
||||
|
||||
|
|
|
@ -63,7 +63,6 @@ int openCDLWindow( QWidget *parent )
|
|||
{
|
||||
cdlWin->activateWindow();
|
||||
cdlWin->raise();
|
||||
cdlWin->setFocus();
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -172,7 +172,7 @@ ConsoleDebugger::ConsoleDebugger(QWidget *parent)
|
|||
|
||||
loadDisplayViews();
|
||||
|
||||
windowUpdateReq = true;
|
||||
windowUpdateReq = QAsmView::UPDATE_ALL;
|
||||
|
||||
dbgWin = this;
|
||||
|
||||
|
@ -373,7 +373,7 @@ void ConsoleDebugger::ld65ImportDebug(void)
|
|||
|
||||
debugSymbolTable.ld65LoadDebugFile( filename.toStdString().c_str() );
|
||||
|
||||
queueUpdate();
|
||||
queueUpdate(QAsmView::UPDATE_ALL);
|
||||
|
||||
return;
|
||||
}
|
||||
|
@ -1834,28 +1834,26 @@ void ConsoleDebugger::selBmAddrChanged(const QString &txt)
|
|||
//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;
|
||||
QDialog dialog(this);
|
||||
editIdx = editIndex;
|
||||
wp = wpIn;
|
||||
|
||||
QHBoxLayout *hbox;
|
||||
QVBoxLayout *mainLayout, *vbox;
|
||||
QLabel *lbl;
|
||||
QLineEdit *addr1, *addr2, *cond, *name;
|
||||
QCheckBox *forbidChkBox, *rbp, *wbp, *xbp, *ebp;
|
||||
QGridLayout *grid;
|
||||
QFrame *frame;
|
||||
QGroupBox *gbox;
|
||||
QPushButton *okButton, *cancelButton;
|
||||
QRadioButton *cpu_radio, *ppu_radio, *oam_radio, *rom_radio;
|
||||
|
||||
if ( editIdx >= 0 )
|
||||
{
|
||||
dialog.setWindowTitle( tr("Edit Breakpoint") );
|
||||
setWindowTitle( tr("Edit Breakpoint") );
|
||||
}
|
||||
else
|
||||
{
|
||||
dialog.setWindowTitle( tr("Add Breakpoint") );
|
||||
setWindowTitle( tr("Add Breakpoint") );
|
||||
}
|
||||
|
||||
hbox = new QHBoxLayout();
|
||||
|
@ -1874,6 +1872,9 @@ void ConsoleDebugger::openBpEditWindow( int editIdx, watchpointinfo *wp, bool fo
|
|||
hbox->addWidget( lbl );
|
||||
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") );
|
||||
hbox->addWidget( forbidChkBox );
|
||||
|
||||
|
@ -1906,6 +1907,11 @@ void ConsoleDebugger::openBpEditWindow( int editIdx, watchpointinfo *wp, bool fo
|
|||
rom_radio = new QRadioButton( tr("ROM") );
|
||||
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 );
|
||||
hbox->addWidget( cpu_radio );
|
||||
hbox->addWidget( ppu_radio );
|
||||
|
@ -1917,6 +1923,9 @@ void ConsoleDebugger::openBpEditWindow( int editIdx, watchpointinfo *wp, bool fo
|
|||
mainLayout->addLayout( grid );
|
||||
lbl = new QLabel( tr("Condition") );
|
||||
cond = new QLineEdit();
|
||||
condValid = true;
|
||||
|
||||
connect( cond, SIGNAL(textChanged(const QString &)), this, SLOT(conditionTextChanged(const QString &)));
|
||||
|
||||
grid->addWidget( lbl, 0, 0 );
|
||||
grid->addWidget( cond, 0, 1 );
|
||||
|
@ -1928,15 +1937,17 @@ void ConsoleDebugger::openBpEditWindow( int editIdx, watchpointinfo *wp, bool fo
|
|||
grid->addWidget( name, 1, 1 );
|
||||
|
||||
hbox = new QHBoxLayout();
|
||||
msgLbl = new QLabel();
|
||||
okButton = new QPushButton( tr("OK") );
|
||||
cancelButton = new QPushButton( tr("Cancel") );
|
||||
|
||||
mainLayout->addLayout( hbox );
|
||||
hbox->addWidget( cancelButton );
|
||||
hbox->addWidget( okButton );
|
||||
hbox->addWidget( msgLbl, 5 );
|
||||
hbox->addWidget( cancelButton, 1 );
|
||||
hbox->addWidget( okButton, 1 );
|
||||
|
||||
connect( okButton, SIGNAL(clicked(void)), &dialog, SLOT(accept(void)) );
|
||||
connect( cancelButton, SIGNAL(clicked(void)), &dialog, SLOT(reject(void)) );
|
||||
connect( okButton, SIGNAL(clicked(void)), this, SLOT(accept(void)) );
|
||||
connect( cancelButton, SIGNAL(clicked(void)), this, SLOT(reject(void)) );
|
||||
|
||||
okButton->setIcon( style()->standardIcon( QStyle::SP_DialogOkButton ) );
|
||||
cancelButton->setIcon( style()->standardIcon( QStyle::SP_DialogCancelButton ) );
|
||||
|
@ -2036,99 +2047,270 @@ void ConsoleDebugger::openBpEditWindow( int editIdx, watchpointinfo *wp, bool fo
|
|||
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 )
|
||||
{
|
||||
dialog->loadBreakpoint();
|
||||
dialog->deleteLater();
|
||||
ret = QDialog::Accepted;
|
||||
}
|
||||
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;
|
||||
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 );
|
||||
}
|
||||
}
|
||||
bpListUpdate( false );
|
||||
}
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
|
@ -2439,7 +2621,7 @@ static void DeleteBreak(int sel)
|
|||
|
||||
if (watchpoint[sel].cond)
|
||||
{
|
||||
freeTree(watchpoint[sel].cond);
|
||||
delete watchpoint[sel].cond;
|
||||
}
|
||||
if (watchpoint[sel].condText)
|
||||
{
|
||||
|
@ -2488,7 +2670,7 @@ void debuggerClearAllBreakpoints(void)
|
|||
{
|
||||
if (watchpoint[i].cond)
|
||||
{
|
||||
freeTree(watchpoint[i].cond);
|
||||
delete watchpoint[i].cond;
|
||||
}
|
||||
if (watchpoint[i].condText)
|
||||
{
|
||||
|
@ -2499,7 +2681,7 @@ void debuggerClearAllBreakpoints(void)
|
|||
free(watchpoint[i].desc);
|
||||
}
|
||||
|
||||
watchpoint[i].address = 0;
|
||||
watchpoint[i].address = 0;
|
||||
watchpoint[i].endaddress = 0;
|
||||
watchpoint[i].flags = 0;
|
||||
watchpoint[i].cond = 0;
|
||||
|
@ -2898,7 +3080,7 @@ void ConsoleDebugger::debugStepBackCB(void)
|
|||
{
|
||||
FCEU_WRAPPER_LOCK();
|
||||
FCEUD_TraceLoggerBackUpInstruction();
|
||||
updateWindowData();
|
||||
updateWindowData(QAsmView::UPDATE_ALL);
|
||||
hexEditorUpdateMemoryValues(true);
|
||||
hexEditorRequestUpdateAll();
|
||||
lastBpIdx = BREAK_TYPE_STEP;
|
||||
|
@ -3093,8 +3275,7 @@ void ConsoleDebugger::seekPCCB (void)
|
|||
setRegsFromEntry();
|
||||
//updateAllDebugWindows();
|
||||
}
|
||||
windowUpdateReq = true;
|
||||
//asmView->scrollToPC();
|
||||
windowUpdateReq = QAsmView::UPDATE_ALL;
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
void ConsoleDebugger::openChangePcDialog(void)
|
||||
|
@ -3148,7 +3329,7 @@ void ConsoleDebugger::openChangePcDialog(void)
|
|||
{
|
||||
X.PC = sbox->value();
|
||||
|
||||
windowUpdateReq = true;
|
||||
windowUpdateReq = QAsmView::UPDATE_ALL;
|
||||
}
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
|
@ -4142,20 +4323,25 @@ void ConsoleDebugger::updateRegisterView(void)
|
|||
ppuScrollY->setText( tr(stmp) );
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
void ConsoleDebugger::updateWindowData(void)
|
||||
void ConsoleDebugger::updateWindowData(enum QAsmView::UpdateType type)
|
||||
{
|
||||
asmView->updateAssemblyView();
|
||||
|
||||
asmView->scrollToPC();
|
||||
if (type == QAsmView::UPDATE_ALL)
|
||||
{
|
||||
asmView->updateAssemblyView();
|
||||
asmView->scrollToPC();
|
||||
updateRegisterView();
|
||||
} else if (type == QAsmView::UPDATE_NO_SCROLL)
|
||||
{
|
||||
asmView->updateAssemblyView();
|
||||
updateRegisterView();
|
||||
}
|
||||
|
||||
updateRegisterView();
|
||||
|
||||
windowUpdateReq = false;
|
||||
windowUpdateReq = QAsmView::UPDATE_NONE;
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
void ConsoleDebugger::queueUpdate(void)
|
||||
void ConsoleDebugger::queueUpdate(enum QAsmView::UpdateType type)
|
||||
{
|
||||
windowUpdateReq = true;
|
||||
windowUpdateReq = type;
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
void ConsoleDebugger::updatePeriodic(void)
|
||||
|
@ -4173,10 +4359,10 @@ void ConsoleDebugger::updatePeriodic(void)
|
|||
bpNotifyReq = false;
|
||||
}
|
||||
|
||||
if ( windowUpdateReq )
|
||||
if ( windowUpdateReq != QAsmView::UPDATE_NONE )
|
||||
{
|
||||
FCEU_WRAPPER_LOCK();
|
||||
updateWindowData();
|
||||
updateWindowData(windowUpdateReq);
|
||||
FCEU_WRAPPER_UNLOCK();
|
||||
}
|
||||
asmView->update();
|
||||
|
@ -4346,7 +4532,7 @@ void ConsoleDebugger::breakPointNotify( int bpNum )
|
|||
}
|
||||
}
|
||||
|
||||
windowUpdateReq = true;
|
||||
windowUpdateReq = QAsmView::UPDATE_ALL;
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
void ConsoleDebugger::hbarChanged(int value)
|
||||
|
@ -4461,7 +4647,6 @@ void debuggerWindowSetFocus(bool val)
|
|||
{
|
||||
dbgWin->activateWindow();
|
||||
dbgWin->raise();
|
||||
dbgWin->setFocus();
|
||||
}
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
|
@ -4470,11 +4655,11 @@ bool debuggerWaitingAtBreakpoint(void)
|
|||
return waitingAtBp;
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
void updateAllDebuggerWindows( void )
|
||||
void updateAllDebuggerWindows( enum QAsmView::UpdateType type )
|
||||
{
|
||||
if ( dbgWin )
|
||||
{
|
||||
dbgWin->queueUpdate();
|
||||
dbgWin->queueUpdate(type);
|
||||
}
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
|
|
|
@ -167,6 +167,8 @@ class QAsmView : public QWidget
|
|||
|
||||
QFont getFont(void){ return font; };
|
||||
|
||||
enum UpdateType { UPDATE_NONE, UPDATE_ALL, UPDATE_NO_SCROLL };
|
||||
|
||||
protected:
|
||||
bool event(QEvent *event) override;
|
||||
void paintEvent(QPaintEvent *event) override;
|
||||
|
@ -420,6 +422,51 @@ class DebugBreakOnDialog : public QDialog
|
|||
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
|
||||
{
|
||||
Q_OBJECT
|
||||
|
@ -428,7 +475,7 @@ class ConsoleDebugger : public QDialog
|
|||
ConsoleDebugger(QWidget *parent = 0);
|
||||
~ConsoleDebugger(void);
|
||||
|
||||
void updateWindowData(void);
|
||||
void updateWindowData(enum QAsmView::UpdateType type);
|
||||
void updateRegisterView(void);
|
||||
void updateTabVisibility(void);
|
||||
void breakPointNotify(int bpNum);
|
||||
|
@ -437,7 +484,7 @@ class ConsoleDebugger : public QDialog
|
|||
void setBookmarkSelectedAddress( int addr );
|
||||
int getBookmarkSelectedAddress(void){ return selBmAddrVal; };
|
||||
void edit_BM_name( int addr );
|
||||
void queueUpdate(void);
|
||||
void queueUpdate(enum QAsmView::UpdateType type);
|
||||
|
||||
QLabel *asmLineSelLbl;
|
||||
|
||||
|
@ -530,7 +577,8 @@ class ConsoleDebugger : public QDialog
|
|||
ColorMenuItem *pcColorAct;
|
||||
|
||||
int selBmAddrVal;
|
||||
bool windowUpdateReq;
|
||||
enum QAsmView::UpdateType windowUpdateReq;
|
||||
|
||||
bool startedTraceLogger;
|
||||
|
||||
private:
|
||||
|
@ -625,6 +673,6 @@ void saveGameDebugBreakpoints( bool force = false );
|
|||
void loadGameDebugBreakpoints(void);
|
||||
void debuggerClearAllBreakpoints(void);
|
||||
void debuggerClearAllBookmarks(void);
|
||||
void updateAllDebuggerWindows(void);
|
||||
void updateAllDebuggerWindows(enum QAsmView::UpdateType type);
|
||||
|
||||
extern debuggerBookmarkManager_t dbgBmMgr;
|
||||
|
|
|
@ -2388,7 +2388,7 @@ void consoleWin_t::openROMFile(void)
|
|||
QDir d;
|
||||
|
||||
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)",
|
||||
"NSF files (*.nsf *.NSF)",
|
||||
"UNF files (*.unf *.UNF *.unif *.UNIF)",
|
||||
|
@ -2758,14 +2758,14 @@ void consoleWin_t::loadState9(void){ loadState(9); }
|
|||
void consoleWin_t::loadPrevState(void)
|
||||
{
|
||||
FCEU_WRAPPER_LOCK();
|
||||
FCEU_StateRecorderLoadState( FCEU_StateRecorderGetStateIndex()-1 );
|
||||
FCEU_StateRecorderLoadPrevState();
|
||||
FCEU_WRAPPER_UNLOCK();
|
||||
}
|
||||
|
||||
void consoleWin_t::loadNextState(void)
|
||||
{
|
||||
FCEU_WRAPPER_LOCK();
|
||||
FCEU_StateRecorderLoadState( FCEU_StateRecorderGetStateIndex()-1 );
|
||||
FCEU_StateRecorderLoadNextState();
|
||||
FCEU_WRAPPER_UNLOCK();
|
||||
}
|
||||
|
||||
|
|
|
@ -126,7 +126,6 @@ int openFamilyKeyboardDialog(QWidget *parent)
|
|||
{
|
||||
fkbWin->activateWindow();
|
||||
fkbWin->raise();
|
||||
fkbWin->setFocus();
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -42,6 +42,7 @@
|
|||
#include "Qt/config.h"
|
||||
#include "Qt/keyscan.h"
|
||||
#include "Qt/fceuWrapper.h"
|
||||
#include "Qt/CheatsConf.h"
|
||||
#include "Qt/HexEditor.h"
|
||||
#include "Qt/GameGenie.h"
|
||||
|
||||
|
@ -278,6 +279,7 @@ void GameGenieDialog_t::addCheatClicked(void)
|
|||
|
||||
FCEU_WRAPPER_LOCK();
|
||||
FCEUI_AddCheat( name.c_str(), a, v, c, 1 );
|
||||
updateCheatDialog();
|
||||
FCEU_WRAPPER_UNLOCK();
|
||||
|
||||
}
|
||||
|
|
|
@ -399,7 +399,7 @@ static int writeMem( int mode, unsigned int addr, int value )
|
|||
{
|
||||
if (debuggerWindowIsOpen())
|
||||
{
|
||||
updateAllDebuggerWindows();
|
||||
updateAllDebuggerWindows(QAsmView::UPDATE_NO_SCROLL);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1853,7 +1853,7 @@ void HexEditorDialog_t::openDebugSymbolEditWindow( int addr )
|
|||
|
||||
if ( ret == QDialog::Accepted )
|
||||
{
|
||||
updateAllDebuggerWindows();
|
||||
updateAllDebuggerWindows(QAsmView::UPDATE_NO_SCROLL);
|
||||
}
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
|
@ -2777,7 +2777,13 @@ void QHexEdit::keyPressEvent(QKeyEvent *event)
|
|||
event->accept();
|
||||
}
|
||||
else
|
||||
{
|
||||
{ // Use the input text to modify the values in the editor area.
|
||||
|
||||
if (event->text().isEmpty())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
int key;
|
||||
if ( cursorPosX >= 32 )
|
||||
{ // Edit Area is ASCII
|
||||
|
@ -2830,6 +2836,7 @@ void QHexEdit::keyPressEvent(QKeyEvent *event)
|
|||
}
|
||||
else
|
||||
{ // Edit Area is Hex
|
||||
|
||||
key = int(event->text()[0].toUpper().toLatin1());
|
||||
|
||||
if ( ::isxdigit( key ) )
|
||||
|
@ -4222,7 +4229,6 @@ int hexEditorOpenFromDebugger( int mode, int addr )
|
|||
{
|
||||
win->activateWindow();
|
||||
win->raise();
|
||||
win->setFocus();
|
||||
}
|
||||
|
||||
win->editor->setMode( mode );
|
||||
|
|
|
@ -108,7 +108,6 @@ int openNameTableViewWindow( QWidget *parent )
|
|||
{
|
||||
nameTableViewWindow->activateWindow();
|
||||
nameTableViewWindow->raise();
|
||||
nameTableViewWindow->setFocus();
|
||||
return -1;
|
||||
}
|
||||
initNameTableViewer();
|
||||
|
|
|
@ -27,22 +27,25 @@
|
|||
#include <QCloseEvent>
|
||||
#include <QGridLayout>
|
||||
#include <QSettings>
|
||||
#include <QMessageBox>
|
||||
|
||||
#include "Qt/throttle.h"
|
||||
#include "Qt/fceuWrapper.h"
|
||||
#include "Qt/StateRecorderConf.h"
|
||||
|
||||
#include "../../fceu.h"
|
||||
#include "../../state.h"
|
||||
#include "../../driver.h"
|
||||
#include "../../emufile.h"
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
StateRecorderDialog_t::StateRecorderDialog_t(QWidget *parent)
|
||||
: QDialog(parent)
|
||||
{
|
||||
QVBoxLayout *mainLayout;
|
||||
QVBoxLayout *mainLayout, *vbox1;
|
||||
QHBoxLayout *hbox, *hbox1;
|
||||
QGroupBox *frame, *frame1;
|
||||
QGridLayout *grid, *memStatsGrid;
|
||||
QGridLayout *grid, *memStatsGrid, *sysStatusGrid;
|
||||
QSettings settings;
|
||||
int opt;
|
||||
|
||||
|
@ -52,14 +55,19 @@ StateRecorderDialog_t::StateRecorderDialog_t(QWidget *parent)
|
|||
grid = new QGridLayout();
|
||||
|
||||
recorderEnable = new QCheckBox(tr("Auto Start Recorder at ROM Load"));
|
||||
snapFrames = new QSpinBox();
|
||||
snapMinutes = new QSpinBox();
|
||||
snapSeconds = new QSpinBox();
|
||||
historyDuration = new QSpinBox();
|
||||
snapFrameSelBtn = new QRadioButton( tr("By Frames") );
|
||||
snapTimeSelBtn = new QRadioButton( tr("By Time") );
|
||||
|
||||
recorderEnable->setChecked( FCEU_StateRecorderIsEnabled() );
|
||||
|
||||
connect( recorderEnable, SIGNAL(stateChanged(int)), this, SLOT(enableChanged(int)) );
|
||||
|
||||
snapFrames->setMinimum(1);
|
||||
snapFrames->setMaximum(10000);
|
||||
snapSeconds->setMinimum(0);
|
||||
snapSeconds->setMaximum(60);
|
||||
snapMinutes->setMinimum(0);
|
||||
|
@ -67,6 +75,10 @@ StateRecorderDialog_t::StateRecorderDialog_t(QWidget *parent)
|
|||
historyDuration->setMinimum(1);
|
||||
historyDuration->setMaximum(180);
|
||||
|
||||
opt = 10;
|
||||
g_config->getOption("SDL.StateRecorderFramesBetweenSnaps", &opt);
|
||||
snapFrames->setValue(opt);
|
||||
|
||||
opt = 15;
|
||||
g_config->getOption("SDL.StateRecorderHistoryDurationMin", &opt );
|
||||
historyDuration->setValue(opt);
|
||||
|
@ -79,6 +91,14 @@ StateRecorderDialog_t::StateRecorderDialog_t(QWidget *parent)
|
|||
g_config->getOption("SDL.StateRecorderTimeBetweenSnapsSec", &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( snapMinutes, 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);
|
||||
cmprLvlCbox->setCurrentIndex(opt);
|
||||
|
||||
connect( cmprLvlCbox, SIGNAL(currentIndexChanged(int)), this, SLOT(compressionLevelChanged(int)) );
|
||||
|
||||
hbox->addWidget(cmprLvlCbox);
|
||||
|
||||
frame->setLayout(hbox);
|
||||
grid->addWidget( frame, 1, 1 );
|
||||
|
||||
frame1 = new QGroupBox(tr("Time Between Snapshots:"));
|
||||
frame1 = new QGroupBox(tr("Snapshot Timing Setting:"));
|
||||
hbox1 = new QHBoxLayout();
|
||||
frame1->setLayout(hbox1);
|
||||
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();
|
||||
hbox = new QHBoxLayout();
|
||||
|
||||
|
@ -141,16 +183,53 @@ StateRecorderDialog_t::StateRecorderDialog_t(QWidget *parent)
|
|||
|
||||
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:") );
|
||||
memStatsGrid = new QGridLayout();
|
||||
|
||||
numSnapsLbl = new QLineEdit();
|
||||
snapMemSizeLbl = new QLineEdit();
|
||||
totalMemUsageLbl = new QLineEdit();
|
||||
saveTimeLbl = new QLineEdit();
|
||||
|
||||
numSnapsLbl->setReadOnly(true);
|
||||
snapMemSizeLbl->setReadOnly(true);
|
||||
totalMemUsageLbl->setReadOnly(true);
|
||||
saveTimeLbl->setReadOnly(true);
|
||||
|
||||
grid->addWidget(frame, 1, 3, 2, 2);
|
||||
frame->setLayout(memStatsGrid);
|
||||
|
@ -163,8 +242,71 @@ StateRecorderDialog_t::StateRecorderDialog_t(QWidget *parent)
|
|||
memStatsGrid->addWidget( new QLabel( tr("Total Size:") ), 2, 0 );
|
||||
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);
|
||||
|
||||
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();
|
||||
mainLayout->addLayout(hbox);
|
||||
|
||||
|
@ -186,6 +328,14 @@ StateRecorderDialog_t::StateRecorderDialog_t(QWidget *parent)
|
|||
restoreGeometry(settings.value("stateRecorderWindow/geometry").toByteArray());
|
||||
|
||||
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)
|
||||
|
@ -197,44 +347,206 @@ void StateRecorderDialog_t::closeEvent(QCloseEvent *event)
|
|||
{
|
||||
QSettings settings;
|
||||
settings.setValue("stateRecorderWindow/geometry", saveGeometry());
|
||||
done(0);
|
||||
deleteLater();
|
||||
event->accept();
|
||||
|
||||
if (dataSavedCheck())
|
||||
{
|
||||
done(0);
|
||||
deleteLater();
|
||||
event->accept();
|
||||
}
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
void StateRecorderDialog_t::closeWindow(void)
|
||||
{
|
||||
QSettings settings;
|
||||
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)
|
||||
{
|
||||
StateRecorderConfigData config;
|
||||
|
||||
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();
|
||||
packConfig( config );
|
||||
|
||||
FCEU_WRAPPER_LOCK();
|
||||
FCEU_StateRecorderSetEnabled( recorderEnable->isChecked() );
|
||||
FCEU_StateRecorderSetConfigData( config );
|
||||
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();
|
||||
|
||||
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.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->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)
|
||||
{
|
||||
bool ena = val ? true : false;
|
||||
|
@ -252,13 +564,39 @@ void StateRecorderDialog_t::spinBoxValueChanged(int newValue)
|
|||
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)
|
||||
{
|
||||
char stmp[64];
|
||||
|
||||
float fsnapMin = 1.0;
|
||||
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 );
|
||||
}
|
||||
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 fsnapSize = 10.0f * 1024.0f;
|
||||
|
@ -272,16 +610,32 @@ void StateRecorderDialog_t::recalcMemoryUsage(void)
|
|||
|
||||
numSnapsLbl->setText( tr(stmp) );
|
||||
|
||||
saveTimeMs = 0.0;
|
||||
|
||||
if (GameInfo)
|
||||
{
|
||||
constexpr int numIterations = 10;
|
||||
double ts_start, ts_end;
|
||||
|
||||
FCEU_WRAPPER_LOCK();
|
||||
|
||||
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();
|
||||
}
|
||||
|
@ -313,5 +667,8 @@ void StateRecorderDialog_t::recalcMemoryUsage(void)
|
|||
}
|
||||
|
||||
totalMemUsageLbl->setText( tr(stmp) );
|
||||
|
||||
sprintf( stmp, "%.02f ms", saveTimeMs);
|
||||
saveTimeLbl->setText( tr(stmp) );
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
|
|
|
@ -12,10 +12,15 @@
|
|||
#include <QSpinBox>
|
||||
#include <QComboBox>
|
||||
#include <QPushButton>
|
||||
#include <QRadioButton>
|
||||
#include <QProgressBar>
|
||||
#include <QLineEdit>
|
||||
#include <QLabel>
|
||||
#include <QFrame>
|
||||
#include <QGroupBox>
|
||||
#include <QTimer>
|
||||
|
||||
struct StateRecorderConfigData;
|
||||
|
||||
class StateRecorderDialog_t : public QDialog
|
||||
{
|
||||
|
@ -28,23 +33,51 @@ public:
|
|||
protected:
|
||||
void closeEvent(QCloseEvent *event);
|
||||
|
||||
QSpinBox *snapMinutes;
|
||||
QSpinBox *snapSeconds;
|
||||
QSpinBox *historyDuration;
|
||||
QCheckBox *recorderEnable;
|
||||
QLineEdit *numSnapsLbl;
|
||||
QLineEdit *snapMemSizeLbl;
|
||||
QLineEdit *totalMemUsageLbl;
|
||||
QPushButton *applyButton;
|
||||
QPushButton *closeButton;
|
||||
QComboBox *cmprLvlCbox;
|
||||
QSpinBox *snapMinutes;
|
||||
QSpinBox *snapSeconds;
|
||||
QSpinBox *snapFrames;
|
||||
QSpinBox *historyDuration;
|
||||
QSpinBox *pauseDuration;
|
||||
QCheckBox *recorderEnable;
|
||||
QLineEdit *numSnapsLbl;
|
||||
QLineEdit *snapMemSizeLbl;
|
||||
QLineEdit *totalMemUsageLbl;
|
||||
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 updateStartStopBuffon(void);
|
||||
void updateRecorderStatusLabel(void);
|
||||
void updateBufferSizeStatus(void);
|
||||
void updateStatusDisplay(void);
|
||||
void packConfig( StateRecorderConfigData &config );
|
||||
|
||||
public slots:
|
||||
void closeWindow(void);
|
||||
private slots:
|
||||
void applyChanges(void);
|
||||
void updatePeriodic(void);
|
||||
void startStopClicked(void);
|
||||
void snapTimeModeClicked(void);
|
||||
void snapFrameModeClicked(void);
|
||||
void spinBoxValueChanged(int newValue);
|
||||
void enableChanged(int);
|
||||
void compressionLevelChanged(int newValue);
|
||||
void pauseOnLoadChanged(int index);
|
||||
};
|
||||
|
|
|
@ -116,7 +116,6 @@ void tasWindowSetFocus(bool val)
|
|||
{
|
||||
tasWin->activateWindow();
|
||||
tasWin->raise();
|
||||
tasWin->setFocus();
|
||||
}
|
||||
}
|
||||
// this getter contains formula to decide whether to record or replay movie
|
||||
|
@ -2917,7 +2916,6 @@ void TasEditorWindow::openFindNoteWindow(void)
|
|||
{
|
||||
findWin->activateWindow();
|
||||
findWin->raise();
|
||||
findWin->setFocus();
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -57,6 +57,7 @@
|
|||
|
||||
#include "common/os_utils.h"
|
||||
|
||||
#include "Qt/ConsoleDebugger.h"
|
||||
#include "Qt/ConsoleWindow.h"
|
||||
#include "Qt/ConsoleUtilities.h"
|
||||
#include "Qt/TraceLogger.h"
|
||||
|
@ -1211,7 +1212,6 @@ void openTraceLoggerWindow(QWidget *parent)
|
|||
{
|
||||
traceLogWindow->activateWindow();
|
||||
traceLogWindow->raise();
|
||||
traceLogWindow->setFocus();
|
||||
return;
|
||||
}
|
||||
//printf("Open Trace Logger Window\n");
|
||||
|
@ -2188,7 +2188,7 @@ void QTraceLogView::openBpEditWindow(int editIdx, watchpointinfo *wp, traceRecor
|
|||
numWPs++;
|
||||
}
|
||||
|
||||
updateAllDebuggerWindows();
|
||||
updateAllDebuggerWindows(QAsmView::UPDATE_NO_SCROLL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2233,7 +2233,7 @@ void QTraceLogView::openDebugSymbolEditWindow(int addr, int bank)
|
|||
|
||||
if (ret == QDialog::Accepted)
|
||||
{
|
||||
updateAllDebuggerWindows();
|
||||
updateAllDebuggerWindows(QAsmView::UPDATE_NO_SCROLL);
|
||||
}
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
|
|
|
@ -756,9 +756,13 @@ InitConfig()
|
|||
|
||||
config->addOption("SDL.StateRecorderEnable", false);
|
||||
config->addOption("SDL.StateRecorderHistoryDurationMin", 15);
|
||||
config->addOption("SDL.StateRecorderTimingMode", 0);
|
||||
config->addOption("SDL.StateRecorderFramesBetweenSnaps", 60);
|
||||
config->addOption("SDL.StateRecorderTimeBetweenSnapsMin", 0);
|
||||
config->addOption("SDL.StateRecorderTimeBetweenSnapsSec", 3);
|
||||
config->addOption("SDL.StateRecorderCompressionLevel", 0);
|
||||
config->addOption("SDL.StateRecorderPauseOnLoad", 1);
|
||||
config->addOption("SDL.StateRecorderPauseDuration", 3);
|
||||
|
||||
//TODO implement this
|
||||
config->addOption("periodicsaves", "SDL.PeriodicSaves", 0);
|
||||
|
|
|
@ -976,22 +976,36 @@ int fceuWrapperInit( int argc, char *argv[] )
|
|||
// Initialize the State Recorder
|
||||
{
|
||||
bool srEnable = false;
|
||||
bool srUseTimeMode = false;
|
||||
int srHistDurMin = 15;
|
||||
int srFramesBtwSnaps = 60;
|
||||
int srTimeBtwSnapsMin = 0;
|
||||
int srTimeBtwSnapsSec = 3;
|
||||
int srCompressionLevel = 0;
|
||||
int pauseOnLoadTime = 3;
|
||||
int pauseOnLoad = StateRecorderConfigData::TEMPORARY_PAUSE;
|
||||
|
||||
g_config->getOption("SDL.StateRecorderEnable", &srEnable);
|
||||
g_config->getOption("SDL.StateRecorderTimingMode", &srUseTimeMode);
|
||||
g_config->getOption("SDL.StateRecorderHistoryDurationMin", &srHistDurMin);
|
||||
g_config->getOption("SDL.StateRecorderFramesBetweenSnaps", &srFramesBtwSnaps);
|
||||
g_config->getOption("SDL.StateRecorderTimeBetweenSnapsMin", &srTimeBtwSnapsMin);
|
||||
g_config->getOption("SDL.StateRecorderTimeBetweenSnapsSec", &srTimeBtwSnapsSec);
|
||||
g_config->getOption("SDL.StateRecorderCompressionLevel", &srCompressionLevel);
|
||||
g_config->getOption("SDL.StateRecorderPauseOnLoad", &pauseOnLoad);
|
||||
g_config->getOption("SDL.StateRecorderPauseDuration", &pauseOnLoadTime);
|
||||
|
||||
StateRecorderConfigData srConfig;
|
||||
|
||||
srConfig.historyDurationMinutes = srHistDurMin;
|
||||
srConfig.timingMode = srUseTimeMode ?
|
||||
StateRecorderConfigData::TIME : StateRecorderConfigData::FRAMES;
|
||||
srConfig.timeBetweenSnapsMinutes = static_cast<float>( srTimeBtwSnapsMin ) +
|
||||
( static_cast<float>( srTimeBtwSnapsSec ) / 60.0f );
|
||||
srConfig.framesBetweenSnaps = srFramesBtwSnaps;
|
||||
srConfig.compressionLevel = srCompressionLevel;
|
||||
srConfig.loadPauseTimeSeconds = pauseOnLoadTime;
|
||||
srConfig.pauseOnLoad = static_cast<StateRecorderConfigData::PauseType>(pauseOnLoad);
|
||||
|
||||
FCEU_StateRecorderSetEnabled( srEnable );
|
||||
FCEU_StateRecorderSetConfigData( srConfig );
|
||||
|
@ -1469,20 +1483,19 @@ int fceuWrapperUpdate( void )
|
|||
return 0;
|
||||
}
|
||||
|
||||
ArchiveScanRecord FCEUD_ScanArchive(std::string fname)
|
||||
static int minizip_ScanArchive( const char *filepath, ArchiveScanRecord &rec)
|
||||
{
|
||||
int idx=0, ret;
|
||||
unzFile zf;
|
||||
unz_file_info fi;
|
||||
char filename[512];
|
||||
ArchiveScanRecord rec;
|
||||
|
||||
zf = unzOpen( fname.c_str() );
|
||||
|
||||
zf = unzOpen( filepath );
|
||||
|
||||
if ( zf == NULL )
|
||||
{
|
||||
//printf("Error: Failed to open Zip File: '%s'\n", fname.c_str() );
|
||||
return rec;
|
||||
return -1;
|
||||
}
|
||||
rec.type = 0;
|
||||
|
||||
|
@ -1512,18 +1525,313 @@ ArchiveScanRecord FCEUD_ScanArchive(std::string fname)
|
|||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
FCEUFILE* fp = 0;
|
||||
int ret, idx=0;
|
||||
FCEUFILE* fp = nullptr;
|
||||
void *tmpMem = nullptr;
|
||||
unzFile zf;
|
||||
unz_file_info fi;
|
||||
char filename[512];
|
||||
char foundFile = 0;
|
||||
void *tmpMem = NULL;
|
||||
bool foundFile = false;
|
||||
|
||||
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;
|
||||
|
||||
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() );
|
||||
return fp;
|
||||
fp = minizip_OpenArchive(asr, fname, &searchFile, -1 );
|
||||
}
|
||||
|
||||
//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;
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
{
|
||||
int ret, idx=0;
|
||||
FCEUFILE* fp = 0;
|
||||
unzFile zf;
|
||||
unz_file_info fi;
|
||||
char filename[512];
|
||||
char foundFile = 0;
|
||||
void *tmpMem = NULL;
|
||||
FCEUFILE* fp = nullptr;
|
||||
|
||||
zf = unzOpen( fname.c_str() );
|
||||
|
||||
if ( zf == NULL )
|
||||
#ifdef _USE_LIBARCHIVE
|
||||
fp = libarchive_OpenArchive( asr, fname, nullptr, innerIndex );
|
||||
#endif
|
||||
if (fp == nullptr)
|
||||
{
|
||||
//printf("Error: Failed to open Zip File: '%s'\n", fname.c_str() );
|
||||
return fp;
|
||||
fp = minizip_OpenArchive(asr, fname, nullptr, innerIndex);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -92,7 +92,6 @@ int openPPUViewWindow( QWidget *parent )
|
|||
{
|
||||
ppuViewWindow->activateWindow();
|
||||
ppuViewWindow->raise();
|
||||
ppuViewWindow->setFocus();
|
||||
return -1;
|
||||
}
|
||||
initPPUViewer();
|
||||
|
@ -110,7 +109,6 @@ int openOAMViewWindow( QWidget *parent )
|
|||
{
|
||||
spriteViewWindow->activateWindow();
|
||||
spriteViewWindow->raise();
|
||||
spriteViewWindow->setFocus();
|
||||
return -1;
|
||||
}
|
||||
initPPUViewer();
|
||||
|
@ -637,8 +635,8 @@ QPoint ppuPatternView_t::convPixToTile( QPoint p )
|
|||
w = pattern->w;
|
||||
h = pattern->h;
|
||||
|
||||
i = x / (w*8);
|
||||
j = y / (h*8);
|
||||
i = w == 0 ? 0 : x / (w*8);
|
||||
j = h == 0 ? 0 : y / (h*8);
|
||||
|
||||
if ( PPUView_sprite16Mode[ patternIndex ] )
|
||||
{
|
||||
|
@ -3338,8 +3336,8 @@ QPoint oamPatternView_t::convPixToTile( QPoint p )
|
|||
w = oamPattern.w;
|
||||
h = oamPattern.h;
|
||||
|
||||
i = x / (w*8);
|
||||
j = y / (h*16);
|
||||
i = w == 0 ? 0 : x / (w*8);
|
||||
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 );
|
||||
|
||||
|
|
|
@ -1235,7 +1235,7 @@ void DeleteBreak(int sel)
|
|||
if(sel<0) return;
|
||||
if(sel>=numWPs) return;
|
||||
if (watchpoint[sel].cond)
|
||||
freeTree(watchpoint[sel].cond);
|
||||
delete watchpoint[sel].cond;
|
||||
if (watchpoint[sel].condText)
|
||||
free(watchpoint[sel].condText);
|
||||
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 AutoResumePlay = false;
|
||||
char romNameWhenClosingEmulator[2048] = {0};
|
||||
static unsigned int pauseTimer = 0;
|
||||
|
||||
|
||||
FCEUGI::FCEUGI()
|
||||
|
@ -764,6 +765,22 @@ void FCEUI_Emulate(uint8 **pXBuf, int32 **SoundBuf, int32 *SoundBufSize, int ski
|
|||
#endif
|
||||
}
|
||||
|
||||
if (EmulationPaused & EMULATIONPAUSED_TIMER)
|
||||
{
|
||||
if (pauseTimer > 0)
|
||||
{
|
||||
pauseTimer--;
|
||||
}
|
||||
else
|
||||
{
|
||||
EmulationPaused &= ~EMULATIONPAUSED_TIMER;
|
||||
}
|
||||
if (EmulationPaused & EMULATIONPAUSED_PAUSED)
|
||||
{
|
||||
EmulationPaused &= ~EMULATIONPAUSED_TIMER;
|
||||
}
|
||||
}
|
||||
|
||||
if (EmulationPaused & EMULATIONPAUSED_FA)
|
||||
{
|
||||
// the user is holding Frame Advance key
|
||||
|
@ -787,7 +804,7 @@ void FCEUI_Emulate(uint8 **pXBuf, int32 **SoundBuf, int32 *SoundBufSize, int ski
|
|||
RefreshThrottleFPS();
|
||||
}
|
||||
#endif
|
||||
if (EmulationPaused & EMULATIONPAUSED_PAUSED)
|
||||
if (EmulationPaused & (EMULATIONPAUSED_PAUSED | EMULATIONPAUSED_TIMER) )
|
||||
{
|
||||
// emulator is paused
|
||||
memcpy(XBuf, XBackBuf, 256*256);
|
||||
|
@ -1263,6 +1280,33 @@ void FCEUI_FrameAdvance(void) {
|
|||
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;
|
||||
|
||||
void UpdateAutosave(void) {
|
||||
|
|
|
@ -181,8 +181,9 @@ extern uint8 vsdip;
|
|||
|
||||
#define ARRAY_SIZE(a) (sizeof(a)/sizeof(a[0]))
|
||||
|
||||
#define EMULATIONPAUSED_PAUSED 1
|
||||
#define EMULATIONPAUSED_FA 2
|
||||
#define EMULATIONPAUSED_PAUSED 0x01
|
||||
#define EMULATIONPAUSED_TIMER 0x02
|
||||
#define EMULATIONPAUSED_FA 0x04
|
||||
|
||||
#define FRAMEADVANCE_DELAY_DEFAULT 10
|
||||
#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.
|
||||
|
||||
// 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
|
||||
std::vector<uint8> compressed_buf;
|
||||
static std::vector<uint8> compressed_buf;
|
||||
|
||||
#define SFMDATA_SIZE (128)
|
||||
static SFORMAT SFMDATA[SFMDATA_SIZE];
|
||||
|
@ -1218,6 +1218,10 @@ class StateRecorder
|
|||
|
||||
void loadConfig( StateRecorderConfigData &config )
|
||||
{
|
||||
if (config.framesBetweenSnaps < 1)
|
||||
{
|
||||
config.framesBetweenSnaps = 1;
|
||||
}
|
||||
if (config.timeBetweenSnapsMinutes < 0.0)
|
||||
{
|
||||
config.timeBetweenSnapsMinutes = 3.0f / 60.0f;
|
||||
|
@ -1226,28 +1230,46 @@ class StateRecorder
|
|||
{
|
||||
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 );
|
||||
|
||||
compressionLevel = stateRecorderConfig.compressionLevel;
|
||||
compressionLevel = config.compressionLevel;
|
||||
loadPauseTime = config.loadPauseTimeSeconds;
|
||||
pauseOnLoad = config.pauseOnLoad;
|
||||
}
|
||||
|
||||
void update(void)
|
||||
{
|
||||
bool isPaused = FCEUI_EmulationPaused() ? true : false;
|
||||
bool isPaused = EmulationPaused ? true : false;
|
||||
|
||||
unsigned int curFrame = static_cast<unsigned int>(currFrameCounter);
|
||||
|
||||
|
@ -1311,6 +1333,8 @@ class StateRecorder
|
|||
|
||||
EMUFILE_MEMORY *em = ringBuf[ snapIdx ];
|
||||
|
||||
em->fseek(SEEK_SET, 0);
|
||||
|
||||
FCEUSS_LoadFP( em, SSLOADPARAM_NOBACKUP );
|
||||
|
||||
frameCounter = lastLoadFrame = static_cast<unsigned int>(currFrameCounter);
|
||||
|
@ -1318,9 +1342,55 @@ class StateRecorder
|
|||
lastState = snapIdx;
|
||||
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;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
return ringHead;
|
||||
|
@ -1347,6 +1417,10 @@ class StateRecorder
|
|||
return ringBuf.size() * ringBuf[0]->size();
|
||||
}
|
||||
|
||||
size_t ringBufferSize(void)
|
||||
{
|
||||
return ringBuf.size();
|
||||
}
|
||||
static bool enabled;
|
||||
static int lastState;
|
||||
private:
|
||||
|
@ -1362,6 +1436,8 @@ class StateRecorder
|
|||
int ringStart;
|
||||
int ringBufSize;
|
||||
int compressionLevel;
|
||||
int loadPauseTime;
|
||||
StateRecorderConfigData::PauseType pauseOnLoad;
|
||||
unsigned int frameCounter;
|
||||
unsigned int framesPerSnap;
|
||||
unsigned int lastLoadFrame;
|
||||
|
@ -1415,13 +1491,37 @@ bool FCEU_StateRecorderRunning(void)
|
|||
return stateRecorder != nullptr;
|
||||
}
|
||||
|
||||
int FCEU_StateRecorderLoadState(int snapIndex)
|
||||
int FCEU_StateRecorderGetMaxSnaps(void)
|
||||
{
|
||||
int size = 0;
|
||||
|
||||
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)
|
||||
|
@ -1429,6 +1529,28 @@ int FCEU_StateRecorderGetStateIndex(void)
|
|||
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)
|
||||
{
|
||||
return stateRecorderConfig;
|
||||
|
@ -1436,5 +1558,10 @@ const StateRecorderConfigData& FCEU_StateRecorderGetConfigData(void)
|
|||
int FCEU_StateRecorderSetConfigData(const StateRecorderConfigData &newConfig)
|
||||
{
|
||||
stateRecorderConfig = newConfig;
|
||||
|
||||
if (stateRecorder != nullptr)
|
||||
{
|
||||
stateRecorder->loadConfig( stateRecorderConfig );
|
||||
}
|
||||
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
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
#pragma once
|
||||
#include <string>
|
||||
|
||||
enum ENUM_SSLOADPARAMS
|
||||
|
@ -83,13 +84,37 @@ struct StateRecorderConfigData
|
|||
{
|
||||
float historyDurationMinutes;
|
||||
float timeBetweenSnapsMinutes;
|
||||
int framesBetweenSnaps;
|
||||
int compressionLevel;
|
||||
int loadPauseTimeSeconds;
|
||||
|
||||
enum TimingType
|
||||
{
|
||||
FRAMES = 0,
|
||||
TIME,
|
||||
} timingMode;
|
||||
|
||||
enum PauseType
|
||||
{
|
||||
NO_PAUSE = 0,
|
||||
TEMPORARY_PAUSE,
|
||||
FULL_PAUSE,
|
||||
} pauseOnLoad;
|
||||
|
||||
StateRecorderConfigData(void)
|
||||
{
|
||||
framesBetweenSnaps = 60;
|
||||
historyDurationMinutes = 15.0f;
|
||||
timeBetweenSnapsMinutes = 3.0f / 60.0f;
|
||||
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_StateRecorderIsEnabled(void);
|
||||
void FCEU_StateRecorderSetEnabled(bool enabled);
|
||||
int FCEU_StateRecorderGetMaxSnaps(void);
|
||||
int FCEU_StateRecorderGetNumSnapsSaved(void);
|
||||
int FCEU_StateRecorderGetStateIndex(void);
|
||||
int FCEU_StateRecorderLoadState(int snapIndex);
|
||||
int FCEU_StateRecorderLoadPrevState(void);
|
||||
int FCEU_StateRecorderLoadNextState(void);
|
||||
int FCEU_StateRecorderSetConfigData(const StateRecorderConfigData &newConfig);
|
||||
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; }
|
||||
std::string FCEUI_GetSnapshotAsName() { return AsSnapshotName; }
|
||||
|
||||
static void FCEU_DrawPauseCountDown(uint8 *XBuf);
|
||||
|
||||
void FCEU_KillVirtualVideo(void)
|
||||
{
|
||||
if ( XBuf )
|
||||
|
@ -254,6 +256,7 @@ void FCEU_PutImage(void)
|
|||
FCEU_DrawLagCounter(XBuf);
|
||||
FCEU_DrawNTSCControlBars(XBuf);
|
||||
FCEU_DrawRecordingStatus(XBuf);
|
||||
FCEU_DrawPauseCountDown(XBuf);
|
||||
ShowFPS();
|
||||
}
|
||||
|
||||
|
@ -771,3 +774,35 @@ void ShowFPS(void)
|
|||
|
||||
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