mirror of https://github.com/mgba-emu/mgba.git
Merge branch 'master' into medusa
This commit is contained in:
commit
ddbdb62473
1
CHANGES
1
CHANGES
|
@ -97,6 +97,7 @@ Other fixes:
|
|||
- Core: Fix the runloop resuming after a game has crashed (fixes mgba.io/i/2451)
|
||||
- Core: Fix crash if library can't be opened
|
||||
- Debugger: Fix crash with extremely long CLI strings
|
||||
- Debugger: Fix multiple conditional watchpoints at the same address
|
||||
- FFmpeg: Fix crash when encoding audio with some containers
|
||||
- FFmpeg: Fix GIF recording (fixes mgba.io/i/2393)
|
||||
- GB: Fix temporary saves
|
||||
|
|
|
@ -21,14 +21,11 @@ if(NOT LIBMGBA_ONLY)
|
|||
set(BINARY_NAME ${BINARY_NAME} CACHE INTERNAL "Name of output binaries")
|
||||
endif()
|
||||
|
||||
set(CMAKE_C_STANDARD 99)
|
||||
set(CMAKE_C_STANDARD 11)
|
||||
if(NOT MSVC)
|
||||
set(CMAKE_C_STANDARD_REQUIRED ON)
|
||||
set(CMAKE_C_EXTENSIONS OFF)
|
||||
if(SWITCH OR 3DS)
|
||||
set(CMAKE_C_STANDARD 11)
|
||||
set(CMAKE_C_EXTENSIONS ON)
|
||||
elseif(CMAKE_C_COMPILER_ID STREQUAL "GNU" AND CMAKE_C_COMPILER_VERSION VERSION_LESS "4.3")
|
||||
if(SWITCH OR 3DS OR (CMAKE_C_COMPILER_ID STREQUAL "GNU" AND CMAKE_C_COMPILER_VERSION VERSION_LESS "4.3"))
|
||||
set(CMAKE_C_EXTENSIONS ON)
|
||||
endif()
|
||||
set(WARNING_FLAGS "-Wall -Wextra -Wno-missing-field-initializers")
|
||||
|
@ -39,8 +36,8 @@ if(NOT MSVC)
|
|||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${WARNING_FLAGS} -Werror=implicit-function-declaration")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${WARNING_FLAGS}")
|
||||
else()
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -D_CRT_SECURE_NO_WARNINGS /wd4003 /wd4244 /wd4146 /wd4267")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -D_CRT_SECURE_NO_WARNINGS /wd4003 /wd4244 /wd4146 /wd4267")
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -D_CRT_SECURE_NO_WARNINGS /wd4003 /wd4244 /wd4146 /wd4267 /Zc:preprocessor-")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -D_CRT_SECURE_NO_WARNINGS /wd4003 /wd4244 /wd4146 /wd4267 /Zc:preprocessor-")
|
||||
endif()
|
||||
|
||||
if(NOT LIBMGBA_ONLY)
|
||||
|
|
|
@ -136,7 +136,7 @@ DS default controls are slightly different:
|
|||
Compiling
|
||||
---------
|
||||
|
||||
Compiling requires using CMake 3.1 or newer. GCC and Clang are both known to work to compile medusa, but Visual Studio 2013 and older are known not to work. Support for Visual Studio 2015 and newer is coming soon.
|
||||
Compiling requires using CMake 3.1 or newer. GCC, Clang and Visual Studio 2019 known to work to compile medusa.
|
||||
|
||||
#### Docker building
|
||||
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
|
||||
CXX_GUARD_START
|
||||
|
||||
#include <assert.h>
|
||||
#include <ctype.h>
|
||||
#include <fcntl.h>
|
||||
#include <inttypes.h>
|
||||
|
|
|
@ -24,7 +24,6 @@ typedef THREAD_ENTRY (*ThreadEntry)(void*);
|
|||
typedef pthread_t Thread;
|
||||
typedef pthread_mutex_t Mutex;
|
||||
typedef pthread_cond_t Condition;
|
||||
typedef pthread_key_t ThreadLocal;
|
||||
|
||||
static inline int MutexInit(Mutex* mutex) {
|
||||
return pthread_mutex_init(mutex, 0);
|
||||
|
@ -104,6 +103,9 @@ static inline int ThreadSetName(const char* name) {
|
|||
#endif
|
||||
}
|
||||
|
||||
#if (__STDC_VERSION__ < 201112L) || (__STDC_NO_THREADS__ == 1)
|
||||
typedef pthread_key_t ThreadLocal;
|
||||
|
||||
static inline void ThreadLocalInitKey(ThreadLocal* key) {
|
||||
pthread_key_create(key, 0);
|
||||
}
|
||||
|
@ -115,6 +117,7 @@ static inline void ThreadLocalSetKey(ThreadLocal key, void* value) {
|
|||
static inline void* ThreadLocalGetValue(ThreadLocal key) {
|
||||
return pthread_getspecific(key);
|
||||
}
|
||||
#endif
|
||||
|
||||
CXX_GUARD_END
|
||||
|
||||
|
|
|
@ -17,7 +17,6 @@ typedef struct {
|
|||
} Condition;
|
||||
#define THREAD_ENTRY int
|
||||
typedef THREAD_ENTRY (*ThreadEntry)(void*);
|
||||
typedef int ThreadLocal;
|
||||
|
||||
static inline int MutexInit(Mutex* mutex) {
|
||||
Mutex id = sceKernelCreateMutex("mutex", 0, 0, 0);
|
||||
|
@ -145,6 +144,9 @@ static inline int ThreadSetName(const char* name) {
|
|||
return -1;
|
||||
}
|
||||
|
||||
#if (__STDC_VERSION__ < 201112L) || (__STDC_NO_THREADS__ == 1)
|
||||
typedef int ThreadLocal;
|
||||
|
||||
static inline void ThreadLocalInitKey(ThreadLocal* key) {
|
||||
static int base = 0x90;
|
||||
*key = __atomic_fetch_add(&base, 1, __ATOMIC_SEQ_CST);
|
||||
|
@ -160,3 +162,4 @@ static inline void* ThreadLocalGetValue(ThreadLocal key) {
|
|||
return *tls;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
|
|
@ -16,7 +16,6 @@ typedef THREAD_ENTRY ThreadEntry(LPVOID);
|
|||
typedef HANDLE Thread;
|
||||
typedef CRITICAL_SECTION Mutex;
|
||||
typedef CONDITION_VARIABLE Condition;
|
||||
typedef DWORD ThreadLocal;
|
||||
|
||||
static inline int MutexInit(Mutex* mutex) {
|
||||
InitializeCriticalSection(mutex);
|
||||
|
@ -89,6 +88,9 @@ static inline int ThreadSetName(const char* name) {
|
|||
return -1;
|
||||
}
|
||||
|
||||
#if (__STDC_VERSION__ < 201112L) || (__STDC_NO_THREADS__ == 1)
|
||||
typedef DWORD ThreadLocal;
|
||||
|
||||
static inline void ThreadLocalInitKey(ThreadLocal* key) {
|
||||
*key = TlsAlloc();
|
||||
}
|
||||
|
@ -100,5 +102,6 @@ static inline void ThreadLocalSetKey(ThreadLocal key, void* value) {
|
|||
static inline void* ThreadLocalGetValue(ThreadLocal key) {
|
||||
return TlsGetValue(key);
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
|
@ -39,6 +39,10 @@ typedef SOCKET Socket;
|
|||
typedef int Socket;
|
||||
#endif
|
||||
|
||||
#if !defined(__3DS__) && !defined(GEKKO)
|
||||
#define HAS_IPV6
|
||||
#endif
|
||||
|
||||
enum IP {
|
||||
IPV4,
|
||||
IPV6
|
||||
|
@ -152,12 +156,36 @@ static inline int SocketClose(Socket socket) {
|
|||
#endif
|
||||
}
|
||||
|
||||
static inline Socket SocketOpenTCP(int port, const struct Address* bindAddress) {
|
||||
#ifdef GEKKO
|
||||
Socket sock = net_socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
|
||||
static inline void SocketCloseQuiet(Socket socket) {
|
||||
int savedErrno = SocketError();
|
||||
SocketClose(socket);
|
||||
#ifdef _WIN32
|
||||
WSASetLastError(savedErrno);
|
||||
#else
|
||||
Socket sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
|
||||
errno = savedErrno;
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline Socket SocketCreate(bool useIPv6, int protocol) {
|
||||
if (useIPv6) {
|
||||
#ifdef HAS_IPV6
|
||||
return socket(AF_INET6, SOCK_STREAM, protocol);
|
||||
#else
|
||||
errno = EAFNOSUPPORT;
|
||||
return INVALID_SOCKET;
|
||||
#endif
|
||||
} else {
|
||||
#ifdef GEKKO
|
||||
return net_socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
|
||||
#else
|
||||
return socket(AF_INET, SOCK_STREAM, protocol);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
static inline Socket SocketOpenTCP(int port, const struct Address* bindAddress) {
|
||||
bool useIPv6 = bindAddress && (bindAddress->version == IPV6);
|
||||
Socket sock = SocketCreate(useIPv6, IPPROTO_TCP);
|
||||
if (SOCKET_FAILED(sock)) {
|
||||
return sock;
|
||||
}
|
||||
|
@ -178,7 +206,7 @@ static inline Socket SocketOpenTCP(int port, const struct Address* bindAddress)
|
|||
#else
|
||||
err = bind(sock, (const struct sockaddr*) &bindInfo, sizeof(bindInfo));
|
||||
#endif
|
||||
} else if (bindAddress->version == IPV4) {
|
||||
} else if (!useIPv6) {
|
||||
struct sockaddr_in bindInfo;
|
||||
memset(&bindInfo, 0, sizeof(bindInfo));
|
||||
bindInfo.sin_family = AF_INET;
|
||||
|
@ -200,18 +228,15 @@ static inline Socket SocketOpenTCP(int port, const struct Address* bindAddress)
|
|||
#endif
|
||||
}
|
||||
if (err) {
|
||||
SocketClose(sock);
|
||||
SocketCloseQuiet(sock);
|
||||
return INVALID_SOCKET;
|
||||
}
|
||||
return sock;
|
||||
}
|
||||
|
||||
static inline Socket SocketConnectTCP(int port, const struct Address* destinationAddress) {
|
||||
#ifdef GEKKO
|
||||
Socket sock = net_socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
|
||||
#else
|
||||
Socket sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
|
||||
#endif
|
||||
bool useIPv6 = destinationAddress && (destinationAddress->version == IPV6);
|
||||
Socket sock = SocketCreate(useIPv6, IPPROTO_TCP);
|
||||
if (SOCKET_FAILED(sock)) {
|
||||
return sock;
|
||||
}
|
||||
|
@ -238,7 +263,7 @@ static inline Socket SocketConnectTCP(int port, const struct Address* destinatio
|
|||
#else
|
||||
err = connect(sock, (const struct sockaddr*) &bindInfo, sizeof(bindInfo));
|
||||
#endif
|
||||
#if !defined(__3DS__) && !defined(GEKKO)
|
||||
#ifdef HAS_IPV6
|
||||
} else {
|
||||
struct sockaddr_in6 bindInfo;
|
||||
memset(&bindInfo, 0, sizeof(bindInfo));
|
||||
|
@ -250,7 +275,7 @@ static inline Socket SocketConnectTCP(int port, const struct Address* destinatio
|
|||
}
|
||||
|
||||
if (err) {
|
||||
SocketClose(sock);
|
||||
SocketCloseQuiet(sock);
|
||||
return INVALID_SOCKET;
|
||||
}
|
||||
return sock;
|
||||
|
|
|
@ -11,12 +11,6 @@
|
|||
CXX_GUARD_START
|
||||
|
||||
#ifndef DISABLE_THREADING
|
||||
#if (__STDC_VERSION__ >= 201112L) && (__STDC_NO_THREADS__ != 1)
|
||||
#define ThreadLocal _Thread_local void*
|
||||
#define ThreadLocalInitKey(X)
|
||||
#define ThreadLocalSetKey(K, V) K = V
|
||||
#define ThreadLocalGetValue(K) K
|
||||
#endif
|
||||
#ifdef USE_PTHREADS
|
||||
#include <mgba-util/platform/posix/threading.h>
|
||||
#elif defined(_WIN32)
|
||||
|
@ -31,7 +25,15 @@ CXX_GUARD_START
|
|||
#define DISABLE_THREADING
|
||||
#endif
|
||||
#endif
|
||||
#ifdef DISABLE_THREADING
|
||||
|
||||
#ifndef DISABLE_THREADING
|
||||
#if (__STDC_VERSION__ >= 201112L) && (__STDC_NO_THREADS__ != 1)
|
||||
#define ThreadLocal _Thread_local void*
|
||||
#define ThreadLocalInitKey(X)
|
||||
#define ThreadLocalSetKey(K, V) K = V
|
||||
#define ThreadLocalGetValue(K) K
|
||||
#endif
|
||||
#else
|
||||
#ifdef __3DS__
|
||||
// ctrulib already has a type called Thread
|
||||
#include <3ds/thread.h>
|
||||
|
|
|
@ -164,12 +164,12 @@ mLOG_DECLARE_CATEGORY(GB_STATE);
|
|||
* | 0x00197: Reserved (leave zero)
|
||||
* 0x00198 - 0x0019F: Global cycle counter
|
||||
* 0x001A0 - 0x001A1: Program counter for last cartridge read
|
||||
* 0x001A2 - 0x00247: Reserved (leave zero)
|
||||
* 0x00248 - 0x0025F: Additional audio state
|
||||
* | 0x00248 - 0x0024B: Last sample timestamp
|
||||
* | 0x0024C: Current audio sample index
|
||||
* | 0x0024D - 0x0024F: Reserved (leave zero)
|
||||
* | 0x00250 - 0x0025F: Audio rendered samples
|
||||
* 0x001A2 - 0x001D7: Reserved (leave zero)
|
||||
* 0x001D8 - 0x0025F: Additional audio state
|
||||
* | 0x001D8 - 0x001DB: Last sample timestamp
|
||||
* | 0x001DC: Current audio sample index
|
||||
* | 0x001DD - 0x001DF: Reserved (leave zero)
|
||||
* | 0x001E0 - 0x0025F: Audio rendered samples
|
||||
* 0x00260 - 0x002FF: OAM
|
||||
* 0x00300 - 0x0037F: I/O memory
|
||||
* 0x00380 - 0x003FE: HRAM
|
||||
|
@ -442,7 +442,7 @@ struct GBSerializedState {
|
|||
int32_t lastSample;
|
||||
uint8_t sampleIndex;
|
||||
uint8_t reserved[3];
|
||||
struct mStereoSample currentSamples[32];
|
||||
struct mStereoSample currentSamples[GB_MAX_SAMPLES];
|
||||
} audio2;
|
||||
|
||||
uint8_t oam[GB_SIZE_OAM];
|
||||
|
@ -473,6 +473,8 @@ struct GBSerializedState {
|
|||
};
|
||||
#pragma pack(pop)
|
||||
|
||||
static_assert(sizeof(struct GBSerializedState) == 0x11800, "GB savestate struct sized wrong");
|
||||
|
||||
bool GBDeserialize(struct GB* gb, const struct GBSerializedState* state);
|
||||
void GBSerialize(struct GB* gb, struct GBSerializedState* state);
|
||||
|
||||
|
|
|
@ -402,7 +402,7 @@ struct GBASerializedState {
|
|||
int8_t chB[16];
|
||||
} samples;
|
||||
|
||||
struct mStereoSample currentSamples[16];
|
||||
struct mStereoSample currentSamples[GBA_MAX_SAMPLES];
|
||||
|
||||
uint32_t reserved[12];
|
||||
|
||||
|
@ -414,6 +414,8 @@ struct GBASerializedState {
|
|||
uint8_t wram[SIZE_WORKING_RAM];
|
||||
};
|
||||
|
||||
static_assert(sizeof(struct GBASerializedState) == 0x61000, "GBA savestate struct sized wrong");
|
||||
|
||||
struct VDir;
|
||||
|
||||
void GBASerialize(struct GBA* gba, struct GBASerializedState* state);
|
||||
|
|
|
@ -84,7 +84,9 @@ CXX_GUARD_START
|
|||
extern const struct mScriptType mSTStruct_ ## STRUCT; \
|
||||
extern const struct mScriptType mSTStructConst_ ## STRUCT; \
|
||||
extern const struct mScriptType mSTStructPtr_ ## STRUCT; \
|
||||
extern const struct mScriptType mSTStructPtrConst_ ## STRUCT;
|
||||
extern const struct mScriptType mSTStructPtrConst_ ## STRUCT; \
|
||||
extern const struct mScriptType mSTWrapper_ ## STRUCT; \
|
||||
extern const struct mScriptType mSTWrapperConst_ ## STRUCT;
|
||||
|
||||
#define mSCRIPT_DEFINE_STRUCT(STRUCT) \
|
||||
const struct mScriptType mSTStruct_ ## STRUCT; \
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
[shader]
|
||||
name=TV Mode
|
||||
author=Dominus Iniquitatis
|
||||
description=Scanlines along with a subtle blurring.
|
||||
passes=1
|
||||
|
||||
[pass.0]
|
||||
fragmentShader=tv.fs
|
||||
blend=1
|
||||
width=-2
|
||||
height=-2
|
||||
|
||||
[pass.0.uniform.lineBrightness]
|
||||
type=float
|
||||
readableName=Line brightness
|
||||
default=0.75
|
||||
min=0.0
|
||||
max=1.0
|
||||
|
||||
[pass.0.uniform.blurring]
|
||||
type=float
|
||||
readableName=Blurring
|
||||
default=1.0
|
||||
min=0.0
|
||||
max=1.0
|
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
TV Mode Shader
|
||||
|
||||
Copyright (C) 2022 Dominus Iniquitatis - zerosaiko@gmail.com
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
|
||||
uniform sampler2D tex;
|
||||
uniform vec2 texSize;
|
||||
varying vec2 texCoord;
|
||||
|
||||
uniform float lineBrightness;
|
||||
uniform float blurring;
|
||||
|
||||
void main()
|
||||
{
|
||||
vec4 c = texture2D(tex, texCoord);
|
||||
vec4 n = texture2D(tex, texCoord + vec2(1.0 / texSize.x * 0.5, 0.0));
|
||||
|
||||
vec4 color = mix(c, (c + n) / 2.0, blurring);
|
||||
color.a = c.a;
|
||||
|
||||
if (int(mod(texCoord.t * texSize.y * 2.0, 2.0)) == 0)
|
||||
{
|
||||
color.rgb *= lineBrightness;
|
||||
}
|
||||
|
||||
gl_FragColor = color;
|
||||
}
|
|
@ -102,7 +102,7 @@ static bool _checkWatchpoints(struct ARMDebugger* debugger, uint32_t address, st
|
|||
int32_t value;
|
||||
int segment;
|
||||
if (!mDebuggerEvaluateParseTree(debugger->d.p, watchpoint->condition, &value, &segment) || !(value || segment >= 0)) {
|
||||
return false;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -717,7 +717,7 @@ static void mScriptConsoleLog(struct mScriptConsole* console, struct mScriptStri
|
|||
if (console->logger) {
|
||||
mLogExplicit(console->logger, _mLOG_CAT_SCRIPT, mLOG_INFO, "%s", msg->buffer);
|
||||
} else {
|
||||
mLog(_mLOG_CAT_SCRIPT, mLOG_INFO, "%s", msg->buffer);
|
||||
mLog(_mLOG_CAT_SCRIPT, mLOG_INFO, "%s", msg->buffer);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -725,7 +725,7 @@ static void mScriptConsoleWarn(struct mScriptConsole* console, struct mScriptStr
|
|||
if (console->logger) {
|
||||
mLogExplicit(console->logger, _mLOG_CAT_SCRIPT, mLOG_WARN, "%s", msg->buffer);
|
||||
} else {
|
||||
mLog(_mLOG_CAT_SCRIPT, mLOG_WARN, "%s", msg->buffer);
|
||||
mLog(_mLOG_CAT_SCRIPT, mLOG_WARN, "%s", msg->buffer);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -733,7 +733,7 @@ static void mScriptConsoleError(struct mScriptConsole* console, struct mScriptSt
|
|||
if (console->logger) {
|
||||
mLogExplicit(console->logger, _mLOG_CAT_SCRIPT, mLOG_ERROR, "%s", msg->buffer);
|
||||
} else {
|
||||
mLog(_mLOG_CAT_SCRIPT, mLOG_WARN, "%s", msg->buffer);
|
||||
mLog(_mLOG_CAT_SCRIPT, mLOG_WARN, "%s", msg->buffer);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -818,7 +818,7 @@ mSCRIPT_DEFINE_STRUCT(mScriptTextBuffer)
|
|||
mSCRIPT_DEFINE_STRUCT_METHOD(mScriptTextBuffer, clear)
|
||||
mSCRIPT_DEFINE_DOCSTRING("Set the number of rows and columns")
|
||||
mSCRIPT_DEFINE_STRUCT_METHOD(mScriptTextBuffer, setSize)
|
||||
mSCRIPT_DEFINE_DOCSTRING("Set the posiiton of the cursor")
|
||||
mSCRIPT_DEFINE_DOCSTRING("Set the position of the cursor")
|
||||
mSCRIPT_DEFINE_STRUCT_METHOD(mScriptTextBuffer, moveCursor)
|
||||
mSCRIPT_DEFINE_DOCSTRING("Advance the cursor a number of columns")
|
||||
mSCRIPT_DEFINE_STRUCT_METHOD(mScriptTextBuffer, advance)
|
||||
|
|
|
@ -474,9 +474,8 @@ void GBAudioRun(struct GBAudio* audio, int32_t timestamp, int channels) {
|
|||
if (!audio->enable) {
|
||||
return;
|
||||
}
|
||||
if (audio->p && channels != 0xF && timestamp - audio->lastSample > SAMPLE_INTERVAL) {
|
||||
if (audio->p && channels != 0xF && timestamp - audio->lastSample > (int) (SAMPLE_INTERVAL * audio->timingFactor)) {
|
||||
GBAudioSample(audio, timestamp);
|
||||
return;
|
||||
}
|
||||
|
||||
if (audio->playingCh1 && (channels & 0x1)) {
|
||||
|
@ -747,10 +746,9 @@ void GBAudioSamplePSG(struct GBAudio* audio, int16_t* left, int16_t* right) {
|
|||
}
|
||||
|
||||
void GBAudioSample(struct GBAudio* audio, int32_t timestamp) {
|
||||
timestamp -= audio->lastSample;
|
||||
timestamp -= audio->sampleIndex * SAMPLE_INTERVAL;
|
||||
|
||||
int interval = SAMPLE_INTERVAL * audio->timingFactor;
|
||||
timestamp -= audio->lastSample;
|
||||
timestamp -= audio->sampleIndex * interval;
|
||||
|
||||
int sample;
|
||||
for (sample = audio->sampleIndex; timestamp >= interval && sample < GB_MAX_SAMPLES; ++sample, timestamp -= interval) {
|
||||
|
|
|
@ -627,7 +627,7 @@ static void GBVideoSoftwareRendererDrawRange(struct GBVideoRenderer* renderer, i
|
|||
if (startX == 0) {
|
||||
_cleanOAM(softwareRenderer, y);
|
||||
}
|
||||
if (GBRegisterLCDCIsObjEnable(softwareRenderer->lcdc) && !softwareRenderer->d.disableOBJ && (softwareRenderer->model != GB_MODEL_SCGB || softwareRenderer->sgbTransfer != 1)) {
|
||||
if (GBRegisterLCDCIsObjEnable(softwareRenderer->lcdc) && !softwareRenderer->d.disableOBJ) {
|
||||
int i;
|
||||
for (i = 0; i < softwareRenderer->objMax; ++i) {
|
||||
GBVideoSoftwareRendererDrawObj(softwareRenderer, &softwareRenderer->obj[i], startX, endX, y);
|
||||
|
@ -917,7 +917,7 @@ static void GBVideoSoftwareRendererDrawBackground(struct GBVideoSoftwareRenderer
|
|||
bgTile = ((int8_t*) maps)[topX + topY];
|
||||
}
|
||||
int p = highlight ? PAL_HIGHLIGHT_BG : PAL_BG;
|
||||
if (renderer->model >= GB_MODEL_CGB && (!(renderer->model & GB_MODEL_SGB) || renderer->sgbTransfer != 1)) {
|
||||
if (renderer->model >= GB_MODEL_CGB) {
|
||||
GBObjAttributes attrs = attr[topX + topY];
|
||||
p |= GBObjAttributesGetCGBPalette(attrs) * 4;
|
||||
if (GBObjAttributesIsPriority(attrs) && GBRegisterLCDCIsBgEnable(renderer->lcdc)) {
|
||||
|
@ -952,7 +952,7 @@ static void GBVideoSoftwareRendererDrawBackground(struct GBVideoSoftwareRenderer
|
|||
bgTile = ((int8_t*) maps)[topX + topY];
|
||||
}
|
||||
int p = highlight ? PAL_HIGHLIGHT_BG : PAL_BG;
|
||||
if (renderer->model >= GB_MODEL_CGB && (!(renderer->model & GB_MODEL_SGB) || renderer->sgbTransfer != 1)) {
|
||||
if (renderer->model >= GB_MODEL_CGB) {
|
||||
GBObjAttributes attrs = attr[topX + topY];
|
||||
p |= GBObjAttributesGetCGBPalette(attrs) * 4;
|
||||
if (GBObjAttributesIsPriority(attrs) && GBRegisterLCDCIsBgEnable(renderer->lcdc)) {
|
||||
|
|
|
@ -12,6 +12,9 @@
|
|||
#include <QMenu>
|
||||
|
||||
#include <mgba/feature/commandline.h>
|
||||
#ifdef M_CORE_GB
|
||||
#include <mgba/internal/gb/overrides.h>
|
||||
#endif
|
||||
|
||||
static const mOption s_frontendOptions[] = {
|
||||
{ "ecard", true, '\0' },
|
||||
|
@ -128,8 +131,10 @@ ConfigController::ConfigController(QObject* parent)
|
|||
m_opts.interframeBlending = false;
|
||||
mCoreConfigLoad(&m_config);
|
||||
mCoreConfigLoadDefaults(&m_config, &m_opts);
|
||||
#ifdef M_CORE_GB
|
||||
mCoreConfigSetDefaultIntValue(&m_config, "sgb.borders", 1);
|
||||
mCoreConfigSetDefaultIntValue(&m_config, "useCgbColors", 1);
|
||||
mCoreConfigSetDefaultIntValue(&m_config, "gb.colors", GB_COLORS_CGB);
|
||||
#endif
|
||||
mCoreConfigMap(&m_config, &m_opts);
|
||||
|
||||
mSubParserGraphicsInit(&m_subparsers[0], &m_graphicsOpts);
|
||||
|
|
|
@ -221,7 +221,7 @@ void DisplayGL::startDrawing(std::shared_ptr<CoreController> controller) {
|
|||
CoreController::Interrupter interrupter(controller);
|
||||
QMetaObject::invokeMethod(m_painter.get(), "start");
|
||||
if (!m_gl) {
|
||||
if (QGuiApplication::platformName() == "windows") {
|
||||
if (shouldDisableUpdates()) {
|
||||
setUpdatesEnabled(false);
|
||||
}
|
||||
} else {
|
||||
|
@ -309,7 +309,7 @@ void DisplayGL::unpauseDrawing() {
|
|||
if (m_hasStarted) {
|
||||
m_isDrawing = true;
|
||||
QMetaObject::invokeMethod(m_painter.get(), "unpause", Qt::BlockingQueuedConnection);
|
||||
if (!m_gl && QGuiApplication::platformName() == "windows") {
|
||||
if (!m_gl && shouldDisableUpdates()) {
|
||||
setUpdatesEnabled(false);
|
||||
}
|
||||
}
|
||||
|
@ -388,6 +388,16 @@ void DisplayGL::resizePainter() {
|
|||
}
|
||||
}
|
||||
|
||||
bool DisplayGL::shouldDisableUpdates() {
|
||||
if (QGuiApplication::platformName() == "windows") {
|
||||
return true;
|
||||
}
|
||||
if (QGuiApplication::platformName() == "xcb") {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void DisplayGL::setVideoProxy(std::shared_ptr<VideoProxy> proxy) {
|
||||
Display::setVideoProxy(proxy);
|
||||
if (proxy) {
|
||||
|
|
|
@ -112,6 +112,7 @@ protected:
|
|||
|
||||
private:
|
||||
void resizePainter();
|
||||
bool shouldDisableUpdates();
|
||||
|
||||
static QHash<QSurfaceFormat, bool> s_supports;
|
||||
|
||||
|
|
|
@ -165,10 +165,16 @@ Window::Window(CoreManager* manager, ConfigController* config, int playerId, QWi
|
|||
});
|
||||
#endif
|
||||
#if defined(M_CORE_GBA)
|
||||
resizeFrame(QSize(GBA_VIDEO_HORIZONTAL_PIXELS * i, GBA_VIDEO_VERTICAL_PIXELS * i));
|
||||
QSize minimumSize = QSize(GBA_VIDEO_HORIZONTAL_PIXELS, GBA_VIDEO_VERTICAL_PIXELS);
|
||||
#elif defined(M_CORE_GB)
|
||||
resizeFrame(QSize(GB_VIDEO_HORIZONTAL_PIXELS * i, GB_VIDEO_VERTICAL_PIXELS * i));
|
||||
QSize minimumSize = QSize(GB_VIDEO_HORIZONTAL_PIXELS, GB_VIDEO_VERTICAL_PIXELS);
|
||||
#endif
|
||||
setMinimumSize(minimumSize);
|
||||
if (i > 0) {
|
||||
m_initialSize = minimumSize * i;
|
||||
} else {
|
||||
m_initialSize = minimumSize * 2;
|
||||
}
|
||||
setLogo();
|
||||
|
||||
connect(this, &Window::shutdown, m_logView, &QWidget::hide);
|
||||
|
@ -232,7 +238,7 @@ void Window::argumentsPassed() {
|
|||
}
|
||||
#endif
|
||||
|
||||
if (m_config->graphicsOpts()->multiplier) {
|
||||
if (m_config->graphicsOpts()->multiplier > 0) {
|
||||
m_savedScale = m_config->graphicsOpts()->multiplier;
|
||||
|
||||
#if defined(M_CORE_GBA)
|
||||
|
@ -240,7 +246,7 @@ void Window::argumentsPassed() {
|
|||
#elif defined(M_CORE_GB)
|
||||
QSize size(GB_VIDEO_HORIZONTAL_PIXELS, GB_VIDEO_VERTICAL_PIXELS);
|
||||
#endif
|
||||
resizeFrame(size * m_savedScale);
|
||||
m_initialSize = size * m_savedScale;
|
||||
}
|
||||
|
||||
if (args->fname) {
|
||||
|
@ -263,9 +269,8 @@ void Window::resizeFrame(const QSize& size) {
|
|||
newSize.setHeight(geom.height());
|
||||
}
|
||||
}
|
||||
m_screenWidget->setSizeHint(newSize);
|
||||
newSize -= m_screenWidget->size();
|
||||
newSize += this->size();
|
||||
newSize -= centralWidget()->size();
|
||||
if (!isFullScreen()) {
|
||||
resize(newSize);
|
||||
}
|
||||
|
@ -295,7 +300,7 @@ void Window::loadConfig() {
|
|||
reloadConfig();
|
||||
|
||||
if (opts->width && opts->height) {
|
||||
resizeFrame(QSize(opts->width, opts->height));
|
||||
m_initialSize = QSize(opts->width, opts->height);
|
||||
}
|
||||
|
||||
if (opts->fullscreen) {
|
||||
|
@ -715,9 +720,10 @@ void Window::scriptingOpen() {
|
|||
#endif
|
||||
|
||||
void Window::resizeEvent(QResizeEvent*) {
|
||||
QSize newSize = centralWidget()->size();
|
||||
if (!isFullScreen()) {
|
||||
m_config->setOption("height", m_screenWidget->height());
|
||||
m_config->setOption("width", m_screenWidget->width());
|
||||
m_config->setOption("height", newSize.height());
|
||||
m_config->setOption("width", newSize.width());
|
||||
}
|
||||
|
||||
int factor = 0;
|
||||
|
@ -725,9 +731,9 @@ void Window::resizeEvent(QResizeEvent*) {
|
|||
if (m_controller) {
|
||||
size = m_controller->screenDimensions();
|
||||
}
|
||||
if (m_screenWidget->width() % size.width() == 0 && m_screenWidget->height() % size.height() == 0 &&
|
||||
m_screenWidget->width() / size.width() == m_screenWidget->height() / size.height()) {
|
||||
factor = m_screenWidget->width() / size.width();
|
||||
if (newSize.width() % size.width() == 0 && newSize.height() % size.height() == 0 &&
|
||||
newSize.width() / size.width() == newSize.height() / size.height()) {
|
||||
factor = newSize.width() / size.width();
|
||||
}
|
||||
m_savedScale = factor;
|
||||
for (QMap<int, Action*>::iterator iter = m_frameSizes.begin(); iter != m_frameSizes.end(); ++iter) {
|
||||
|
@ -754,7 +760,9 @@ void Window::showEvent(QShowEvent* event) {
|
|||
return;
|
||||
}
|
||||
m_wasOpened = true;
|
||||
resizeFrame(m_screenWidget->sizeHint());
|
||||
if (m_initialSize.isValid()) {
|
||||
resizeFrame(m_initialSize);
|
||||
}
|
||||
QVariant windowPos = m_config->getQtOption("windowPos", m_playerId > 0 ? QString("player%0").arg(m_playerId) : QString());
|
||||
bool maximized = m_config->getQtOption("maximized").toBool();
|
||||
QRect geom = windowHandle()->screen()->availableGeometry();
|
||||
|
@ -910,7 +918,7 @@ void Window::exitFullScreen() {
|
|||
if (!isFullScreen()) {
|
||||
return;
|
||||
}
|
||||
m_screenWidget->unsetCursor();
|
||||
centralWidget()->unsetCursor();
|
||||
menuBar()->show();
|
||||
showNormal();
|
||||
}
|
||||
|
@ -973,7 +981,7 @@ void Window::gameStarted() {
|
|||
}
|
||||
m_focusCheck.start();
|
||||
if (m_display->underMouse()) {
|
||||
m_screenWidget->setCursor(Qt::BlankCursor);
|
||||
centralWidget()->setCursor(Qt::BlankCursor);
|
||||
}
|
||||
|
||||
CoreController::Interrupter interrupter(m_controller);
|
||||
|
@ -1118,11 +1126,11 @@ void Window::reloadDisplayDriver() {
|
|||
|
||||
connect(m_display.get(), &QGBA::Display::hideCursor, [this]() {
|
||||
if (centralWidget() == m_display.get()) {
|
||||
m_screenWidget->setCursor(Qt::BlankCursor);
|
||||
centralWidget()->setCursor(Qt::BlankCursor);
|
||||
}
|
||||
});
|
||||
connect(m_display.get(), &QGBA::Display::showCursor, [this]() {
|
||||
m_screenWidget->unsetCursor();
|
||||
centralWidget()->unsetCursor();
|
||||
});
|
||||
|
||||
m_display->configure(m_config);
|
||||
|
@ -2207,7 +2215,7 @@ void Window::updateMute() {
|
|||
void Window::setLogo() {
|
||||
m_screenWidget->setPixmap(m_logo);
|
||||
m_screenWidget->setDimensions(m_logo.width(), m_logo.height());
|
||||
m_screenWidget->unsetCursor();
|
||||
centralWidget()->unsetCursor();
|
||||
}
|
||||
|
||||
WindowBackground::WindowBackground(QWidget* parent)
|
||||
|
|
|
@ -195,6 +195,7 @@ private:
|
|||
std::unique_ptr<AudioProcessor> m_audioProcessor;
|
||||
|
||||
std::unique_ptr<QGBA::Display> m_display;
|
||||
QSize m_initialSize;
|
||||
int m_savedScale;
|
||||
|
||||
// TODO: Move these to a new class
|
||||
|
|
|
@ -180,7 +180,7 @@ Tamaño de la descarga: %3</translation>
|
|||
<message>
|
||||
<location filename="../AudioDevice.cpp" line="62"/>
|
||||
<source>Writing data to read-only audio device</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Escribiendo datos a dispositivo de audio de sólo lectura</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
|
@ -188,7 +188,7 @@ Tamaño de la descarga: %3</translation>
|
|||
<message>
|
||||
<location filename="../AudioProcessorQt.cpp" line="43"/>
|
||||
<source>Can't start an audio processor without input</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Sin entrada no se puede iniciar un procesador de audio</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
|
@ -196,7 +196,7 @@ Tamaño de la descarga: %3</translation>
|
|||
<message>
|
||||
<location filename="../AudioProcessorSDL.cpp" line="34"/>
|
||||
<source>Can't start an audio processor without input</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Sin entrada no se puede iniciar un procesador de audio</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
|
@ -264,12 +264,12 @@ Tamaño de la descarga: %3</translation>
|
|||
<message>
|
||||
<location filename="../BattleChipView.cpp" line="117"/>
|
||||
<source>BattleChip data missing</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation type="unfinished">Faltan los datos de BattleChip</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../BattleChipView.cpp" line="118"/>
|
||||
<source>BattleChip data is missing. BattleChip Gates will still work, but some graphics will be missing. Would you like to download the data now?</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Faltan los datos de BattleChip. BattleChip Gates seguirán funcionando, pero faltarán algunos gráficos. ¿Quiere descargar los datos ahora?</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../BattleChipView.cpp" line="184"/>
|
||||
|
@ -358,7 +358,7 @@ Tamaño de la descarga: %3</translation>
|
|||
<message>
|
||||
<location filename="../CheatsView.cpp" line="187"/>
|
||||
<source>Some cheats could not be added. Please ensure they're formatted correctly and/or try other cheat types.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation type="unfinished">Algunos trucos no se pudieron añadir. Asegúrese de que están formateados correctamente y/o pruebe otros tipos de trucos.</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
|
@ -793,7 +793,7 @@ Tamaño de la descarga: %3</translation>
|
|||
<message>
|
||||
<location filename="../GameBoy.cpp" line="75"/>
|
||||
<source>ROM Only</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation type="unfinished">Sólo ROM</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../GameBoy.cpp" line="76"/>
|
||||
|
|
|
@ -758,37 +758,37 @@ Dimensione del download: %3</translation>
|
|||
<message>
|
||||
<location filename="../GameBoy.cpp" line="56"/>
|
||||
<source>Game Boy (DMG)</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Game Boy (DMG)</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../GameBoy.cpp" line="57"/>
|
||||
<source>Game Boy Pocket (MGB)</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Game Boy Pocket (MGB)</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../GameBoy.cpp" line="58"/>
|
||||
<source>Super Game Boy (SGB)</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Super Game Boy (SGB)</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../GameBoy.cpp" line="59"/>
|
||||
<source>Super Game Boy 2 (SGB)</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Super Game Boy 2 (SGB)</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../GameBoy.cpp" line="60"/>
|
||||
<source>Game Boy Color (CGB)</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Game Boy Color (CGB)</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../GameBoy.cpp" line="61"/>
|
||||
<source>Game Boy Advance (AGB)</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Game Boy Advance (AGB)</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../GameBoy.cpp" line="62"/>
|
||||
<source>Super Game Boy Color (SGB + CGB)</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Super Game Boy Color (SGB + CGB)</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../GameBoy.cpp" line="75"/>
|
||||
|
@ -4788,7 +4788,7 @@ Dimensione del download: %3</translation>
|
|||
<message>
|
||||
<location filename="../SettingsView.ui" line="555"/>
|
||||
<source>Load last state</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Carica l'ultimo stato</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../SettingsView.ui" line="565"/>
|
||||
|
@ -4798,7 +4798,7 @@ Dimensione del download: %3</translation>
|
|||
<message>
|
||||
<location filename="../SettingsView.ui" line="592"/>
|
||||
<source>Save entered cheats</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Salva i trucchi inseriti</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../SettingsView.ui" line="813"/>
|
||||
|
@ -4979,7 +4979,7 @@ Dimensione del download: %3</translation>
|
|||
<message>
|
||||
<location filename="../SettingsView.ui" line="582"/>
|
||||
<source>Periodically autosave state</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Salva periodicamente in automatico lo stato</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../SettingsView.ui" line="865"/>
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -4008,12 +4008,12 @@ Download size: %3</source>
|
|||
<message>
|
||||
<location filename="../PrinterView.cpp" line="59"/>
|
||||
<source>Save Printout</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>保存打印输出</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../PrinterView.cpp" line="59"/>
|
||||
<source>Portable Network Graphics (*.png)</source>
|
||||
<translation type="unfinished">便携式网络图形 (*.png)</translation>
|
||||
<translation>便携式网络图形 (*.png)</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
|
@ -4337,17 +4337,17 @@ Download size: %3</source>
|
|||
<message>
|
||||
<location filename="../scripting/ScriptingView.cpp" line="60"/>
|
||||
<source>Select script to load</source>
|
||||
<translation type="unfinished">选择要载入的脚本</translation>
|
||||
<translation>选择要载入的脚本</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../scripting/ScriptingView.cpp" line="85"/>
|
||||
<source>Lua scripts (*.lua)</source>
|
||||
<translation type="unfinished">Lua 脚本 (*.lua)</translation>
|
||||
<translation>Lua 脚本 (*.lua)</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../scripting/ScriptingView.cpp" line="87"/>
|
||||
<source>All files (*.*)</source>
|
||||
<translation type="unfinished">所有文件 (*.*)</translation>
|
||||
<translation>所有文件 (*.*)</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
|
@ -4796,22 +4796,22 @@ Download size: %3</source>
|
|||
<message>
|
||||
<location filename="../SettingsView.ui" line="548"/>
|
||||
<source>On loading a game:</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>在加载游戏时:</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../SettingsView.ui" line="555"/>
|
||||
<source>Load last state</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>加载最后的即时存档</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../SettingsView.ui" line="565"/>
|
||||
<source>Load cheats</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>加载作弊</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../SettingsView.ui" line="592"/>
|
||||
<source>Save entered cheats</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>保存已输入的作弊码</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../SettingsView.ui" line="813"/>
|
||||
|
@ -5641,12 +5641,12 @@ Download size: %3</source>
|
|||
<message>
|
||||
<location filename="../VideoView.ui" line="277"/>
|
||||
<source>H.264</source>
|
||||
<translation type="unfinished">H.264</translation>
|
||||
<translation>H.264</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../VideoView.ui" line="282"/>
|
||||
<source>H.264 (NVENC)</source>
|
||||
<translation type="unfinished">H.264 (NVENC)</translation>
|
||||
<translation>H.264 (NVENC)</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../VideoView.ui" line="455"/>
|
||||
|
@ -5656,7 +5656,7 @@ Download size: %3</source>
|
|||
<message>
|
||||
<location filename="../VideoView.ui" line="468"/>
|
||||
<source>CRF</source>
|
||||
<translation type="unfinished">CRF</translation>
|
||||
<translation>CRF</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../VideoView.ui" line="484"/>
|
||||
|
@ -6338,7 +6338,7 @@ Download size: %3</source>
|
|||
<message>
|
||||
<location filename="../Window.cpp" line="1665"/>
|
||||
<source>Game state views</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>游戏状态视图</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Window.cpp" line="1666"/>
|
||||
|
@ -6363,7 +6363,7 @@ Download size: %3</source>
|
|||
<message>
|
||||
<location filename="../Window.cpp" line="1671"/>
|
||||
<source>&Frame inspector...</source>
|
||||
<translation>框架检查器(&F)...</translation>
|
||||
<translation>帧检查器(&F)...</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Window.cpp" line="1687"/>
|
||||
|
|
|
@ -52,7 +52,7 @@ static bool _checkWatchpoints(struct SM83Debugger* debugger, uint16_t address, s
|
|||
int32_t value;
|
||||
int segment;
|
||||
if (!mDebuggerEvaluateParseTree(debugger->d.p, watchpoint->condition, &value, &segment) || !(value || segment >= 0)) {
|
||||
return false;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
uint8_t oldValue = debugger->originalMemory.load8(debugger->cpu, address);
|
||||
|
|
Loading…
Reference in New Issue