mirror of https://github.com/mgba-emu/mgba.git
Merge branch 'master' (early part) into medusa
This commit is contained in:
commit
5d0dafbbb1
3
CHANGES
3
CHANGES
|
@ -46,9 +46,12 @@ Features:
|
||||||
Emulation fixes:
|
Emulation fixes:
|
||||||
- GBA Memory: Make VRAM access stalls only apply to BG RAM
|
- GBA Memory: Make VRAM access stalls only apply to BG RAM
|
||||||
- GBA Video: Disable BG target 1 blending when OBJ blending (fixes mgba.io/i/2722)
|
- GBA Video: Disable BG target 1 blending when OBJ blending (fixes mgba.io/i/2722)
|
||||||
|
Other fixes:
|
||||||
|
- Qt: Fix crash when attempting to use OpenGL 2.1 to 3.1 (fixes mgba.io/i/2794)
|
||||||
Misc:
|
Misc:
|
||||||
- GB Serialize: Add missing savestate support for MBC6 and NT (newer)
|
- GB Serialize: Add missing savestate support for MBC6 and NT (newer)
|
||||||
- GBA: Improve detection of valid ELF ROMs
|
- GBA: Improve detection of valid ELF ROMs
|
||||||
|
- Qt: Include wayland QPA in AppImage (fixes mgba.io/i/2796)
|
||||||
|
|
||||||
0.10.1: (2023-01-10)
|
0.10.1: (2023-01-10)
|
||||||
Emulation fixes:
|
Emulation fixes:
|
||||||
|
|
|
@ -34,6 +34,16 @@ CXX_GUARD_START
|
||||||
size_t NAME ## Index(const struct NAME* vector, const TYPE* member); \
|
size_t NAME ## Index(const struct NAME* vector, const TYPE* member); \
|
||||||
void NAME ## Copy(struct NAME* dest, const struct NAME* src);
|
void NAME ## Copy(struct NAME* dest, const struct NAME* src);
|
||||||
|
|
||||||
|
#ifdef NDEBUG
|
||||||
|
#define VECTOR_BOUNDS_CHECK(NAME, V, L)
|
||||||
|
#else
|
||||||
|
#define VECTOR_BOUNDS_CHECK(NAME, V, L) \
|
||||||
|
if ((L) >= (V)->size) { \
|
||||||
|
fprintf(stderr, "Vector type %s invalid access of index %" PRIuPTR " into vector of size %" PRIuPTR "\n", #NAME, (L), (V)->size); \
|
||||||
|
abort(); \
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#define DEFINE_VECTOR(NAME, TYPE) \
|
#define DEFINE_VECTOR(NAME, TYPE) \
|
||||||
void NAME ## Init(struct NAME* vector, size_t capacity) { \
|
void NAME ## Init(struct NAME* vector, size_t capacity) { \
|
||||||
vector->size = 0; \
|
vector->size = 0; \
|
||||||
|
@ -50,9 +60,11 @@ CXX_GUARD_START
|
||||||
vector->size = 0; \
|
vector->size = 0; \
|
||||||
} \
|
} \
|
||||||
TYPE* NAME ## GetPointer(struct NAME* vector, size_t location) { \
|
TYPE* NAME ## GetPointer(struct NAME* vector, size_t location) { \
|
||||||
|
VECTOR_BOUNDS_CHECK(NAME, vector, location); \
|
||||||
return &vector->vector[location]; \
|
return &vector->vector[location]; \
|
||||||
} \
|
} \
|
||||||
TYPE const* NAME ## GetConstPointer(const struct NAME* vector, size_t location) { \
|
TYPE const* NAME ## GetConstPointer(const struct NAME* vector, size_t location) { \
|
||||||
|
VECTOR_BOUNDS_CHECK(NAME, vector, location); \
|
||||||
return &vector->vector[location]; \
|
return &vector->vector[location]; \
|
||||||
} \
|
} \
|
||||||
TYPE* NAME ## Append(struct NAME* vector) { \
|
TYPE* NAME ## Append(struct NAME* vector) { \
|
||||||
|
@ -78,10 +90,12 @@ CXX_GUARD_START
|
||||||
vector->vector = realloc(vector->vector, vector->capacity * sizeof(TYPE)); \
|
vector->vector = realloc(vector->vector, vector->capacity * sizeof(TYPE)); \
|
||||||
} \
|
} \
|
||||||
void NAME ## Shift(struct NAME* vector, size_t location, size_t difference) { \
|
void NAME ## Shift(struct NAME* vector, size_t location, size_t difference) { \
|
||||||
|
VECTOR_BOUNDS_CHECK(NAME, vector, location); \
|
||||||
memmove(&vector->vector[location], &vector->vector[location + difference], (vector->size - location - difference) * sizeof(TYPE)); \
|
memmove(&vector->vector[location], &vector->vector[location + difference], (vector->size - location - difference) * sizeof(TYPE)); \
|
||||||
vector->size -= difference; \
|
vector->size -= difference; \
|
||||||
} \
|
} \
|
||||||
void NAME ## Unshift(struct NAME* vector, size_t location, size_t difference) { \
|
void NAME ## Unshift(struct NAME* vector, size_t location, size_t difference) { \
|
||||||
|
VECTOR_BOUNDS_CHECK(NAME, vector, location); \
|
||||||
NAME ## Resize(vector, difference); \
|
NAME ## Resize(vector, difference); \
|
||||||
memmove(&vector->vector[location + difference], &vector->vector[location], (vector->size - location - difference) * sizeof(TYPE)); \
|
memmove(&vector->vector[location + difference], &vector->vector[location], (vector->size - location - difference) * sizeof(TYPE)); \
|
||||||
} \
|
} \
|
||||||
|
@ -97,8 +111,16 @@ CXX_GUARD_START
|
||||||
dest->size = src->size; \
|
dest->size = src->size; \
|
||||||
} \
|
} \
|
||||||
|
|
||||||
DECLARE_VECTOR(StringList, char*);
|
|
||||||
DECLARE_VECTOR(IntList, int);
|
DECLARE_VECTOR(IntList, int);
|
||||||
|
DECLARE_VECTOR(SInt8List, int8_t);
|
||||||
|
DECLARE_VECTOR(SInt16List, int16_t);
|
||||||
|
DECLARE_VECTOR(SInt32List, int32_t);
|
||||||
|
DECLARE_VECTOR(SIntPtrList, intptr_t);
|
||||||
|
DECLARE_VECTOR(UInt8List, uint8_t);
|
||||||
|
DECLARE_VECTOR(UInt16List, uint16_t);
|
||||||
|
DECLARE_VECTOR(UInt32List, uint32_t);
|
||||||
|
DECLARE_VECTOR(UIntPtrList, uintptr_t);
|
||||||
|
DECLARE_VECTOR(StringList, char*);
|
||||||
|
|
||||||
CXX_GUARD_END
|
CXX_GUARD_END
|
||||||
|
|
||||||
|
|
|
@ -89,6 +89,7 @@ uint32_t mScriptContextSetWeakref(struct mScriptContext*, struct mScriptValue* v
|
||||||
struct mScriptValue* mScriptContextMakeWeakref(struct mScriptContext*, struct mScriptValue* value);
|
struct mScriptValue* mScriptContextMakeWeakref(struct mScriptContext*, struct mScriptValue* value);
|
||||||
struct mScriptValue* mScriptContextAccessWeakref(struct mScriptContext*, struct mScriptValue* value);
|
struct mScriptValue* mScriptContextAccessWeakref(struct mScriptContext*, struct mScriptValue* value);
|
||||||
void mScriptContextClearWeakref(struct mScriptContext*, uint32_t weakref);
|
void mScriptContextClearWeakref(struct mScriptContext*, uint32_t weakref);
|
||||||
|
void mScriptContextDisownWeakref(struct mScriptContext*, uint32_t weakref);
|
||||||
|
|
||||||
void mScriptContextAttachStdlib(struct mScriptContext* context);
|
void mScriptContextAttachStdlib(struct mScriptContext* context);
|
||||||
void mScriptContextAttachSocket(struct mScriptContext* context);
|
void mScriptContextAttachSocket(struct mScriptContext* context);
|
||||||
|
|
|
@ -76,6 +76,7 @@ CXX_GUARD_START
|
||||||
#define mSCRIPT_TYPE_FIELD_W(TYPE) opaque
|
#define mSCRIPT_TYPE_FIELD_W(TYPE) opaque
|
||||||
#define mSCRIPT_TYPE_FIELD_CW(TYPE) opaque
|
#define mSCRIPT_TYPE_FIELD_CW(TYPE) opaque
|
||||||
|
|
||||||
|
#define mSCRIPT_TYPE_MS_VOID (&mSTVoid)
|
||||||
#define mSCRIPT_TYPE_MS_S8 (&mSTSInt8)
|
#define mSCRIPT_TYPE_MS_S8 (&mSTSInt8)
|
||||||
#define mSCRIPT_TYPE_MS_U8 (&mSTUInt8)
|
#define mSCRIPT_TYPE_MS_U8 (&mSTUInt8)
|
||||||
#define mSCRIPT_TYPE_MS_S16 (&mSTSInt16)
|
#define mSCRIPT_TYPE_MS_S16 (&mSTSInt16)
|
||||||
|
@ -97,7 +98,7 @@ CXX_GUARD_START
|
||||||
#define mSCRIPT_TYPE_MS_CS(STRUCT) (&mSTStructConst_ ## STRUCT)
|
#define mSCRIPT_TYPE_MS_CS(STRUCT) (&mSTStructConst_ ## STRUCT)
|
||||||
#define mSCRIPT_TYPE_MS_S_METHOD(STRUCT, NAME) (&_mSTStructBindingType_ ## STRUCT ## _ ## NAME)
|
#define mSCRIPT_TYPE_MS_S_METHOD(STRUCT, NAME) (&_mSTStructBindingType_ ## STRUCT ## _ ## NAME)
|
||||||
#define mSCRIPT_TYPE_MS_PS(STRUCT) (&mSTStructPtr_ ## STRUCT)
|
#define mSCRIPT_TYPE_MS_PS(STRUCT) (&mSTStructPtr_ ## STRUCT)
|
||||||
#define mSCRIPT_TYPE_MS_PCS(STRUCT) (&mSTStructConstPtr_ ## STRUCT)
|
#define mSCRIPT_TYPE_MS_PCS(STRUCT) (&mSTStructPtrConst_ ## STRUCT)
|
||||||
#define mSCRIPT_TYPE_MS_WSTR (&mSTStringWrapper)
|
#define mSCRIPT_TYPE_MS_WSTR (&mSTStringWrapper)
|
||||||
#define mSCRIPT_TYPE_MS_WLIST (&mSTListWrapper)
|
#define mSCRIPT_TYPE_MS_WLIST (&mSTListWrapper)
|
||||||
#define mSCRIPT_TYPE_MS_W(TYPE) (&mSTWrapper_ ## TYPE)
|
#define mSCRIPT_TYPE_MS_W(TYPE) (&mSTWrapper_ ## TYPE)
|
||||||
|
|
|
@ -761,14 +761,16 @@ mSCRIPT_DEFINE_STRUCT_BINDING_DEFAULTS(mScriptConsole, createBuffer)
|
||||||
mSCRIPT_DEFINE_DEFAULTS_END;
|
mSCRIPT_DEFINE_DEFAULTS_END;
|
||||||
|
|
||||||
static struct mScriptConsole* _ensureConsole(struct mScriptContext* context) {
|
static struct mScriptConsole* _ensureConsole(struct mScriptContext* context) {
|
||||||
struct mScriptValue* value = mScriptContextEnsureGlobal(context, "console", mSCRIPT_TYPE_MS_S(mScriptConsole));
|
struct mScriptValue* value = mScriptContextGetGlobal(context, "console");
|
||||||
struct mScriptConsole* console = value->value.opaque;
|
if (value) {
|
||||||
if (!console) {
|
return value->value.opaque;
|
||||||
console = calloc(1, sizeof(*console));
|
|
||||||
value->value.opaque = console;
|
|
||||||
value->flags = mSCRIPT_VALUE_FLAG_FREE_BUFFER;
|
|
||||||
mScriptContextSetDocstring(context, "console", "Singleton instance of struct::mScriptConsole");
|
|
||||||
}
|
}
|
||||||
|
struct mScriptConsole* console = calloc(1, sizeof(*console));
|
||||||
|
value = mScriptValueAlloc(mSCRIPT_TYPE_MS_S(mScriptConsole));
|
||||||
|
value->value.opaque = console;
|
||||||
|
value->flags = mSCRIPT_VALUE_FLAG_FREE_BUFFER;
|
||||||
|
mScriptContextSetGlobal(context, "console", value);
|
||||||
|
mScriptContextSetDocstring(context, "console", "Singleton instance of struct::mScriptConsole");
|
||||||
return console;
|
return console;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,8 +11,6 @@
|
||||||
|
|
||||||
DEFINE_VECTOR(LexVector, struct Token);
|
DEFINE_VECTOR(LexVector, struct Token);
|
||||||
|
|
||||||
DEFINE_VECTOR(IntList, int32_t);
|
|
||||||
|
|
||||||
enum LexState {
|
enum LexState {
|
||||||
LEX_ERROR = -1,
|
LEX_ERROR = -1,
|
||||||
LEX_ROOT = 0,
|
LEX_ROOT = 0,
|
||||||
|
|
|
@ -429,7 +429,7 @@ if(QT_STATIC)
|
||||||
list(APPEND QT_LIBRARIES "-framework AVFoundation" "-framework CoreMedia" "-framework SystemConfiguration" "-framework Security")
|
list(APPEND QT_LIBRARIES "-framework AVFoundation" "-framework CoreMedia" "-framework SystemConfiguration" "-framework Security")
|
||||||
set_target_properties(${QT}::Core PROPERTIES INTERFACE_LINK_LIBRARIES "${QTPCRE}")
|
set_target_properties(${QT}::Core PROPERTIES INTERFACE_LINK_LIBRARIES "${QTPCRE}")
|
||||||
elseif(UNIX)
|
elseif(UNIX)
|
||||||
list(APPEND QT_LIBRARIES ${QT}::FontDatabaseSupport ${QT}::XcbQpa)
|
list(APPEND QT_LIBRARIES ${QT}::FontDatabaseSupport ${QT}::XcbQpa ${QT}::QWaylandIntegrationPlugin)
|
||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
target_link_libraries(${BINARY_NAME}-qt ${PLATFORM_LIBRARY} ${BINARY_NAME} ${QT_LIBRARIES})
|
target_link_libraries(${BINARY_NAME}-qt ${PLATFORM_LIBRARY} ${BINARY_NAME} ${QT_LIBRARIES})
|
||||||
|
|
|
@ -516,10 +516,10 @@ void PainterGL::create() {
|
||||||
|
|
||||||
#if defined(BUILD_GLES2) || defined(BUILD_GLES3)
|
#if defined(BUILD_GLES2) || defined(BUILD_GLES3)
|
||||||
if (m_supportsShaders) {
|
if (m_supportsShaders) {
|
||||||
QOpenGLFunctions_Baseline* fn = m_gl->versionFunctions<QOpenGLFunctions_Baseline>();
|
|
||||||
gl2Backend = static_cast<mGLES2Context*>(malloc(sizeof(mGLES2Context)));
|
gl2Backend = static_cast<mGLES2Context*>(malloc(sizeof(mGLES2Context)));
|
||||||
mGLES2ContextCreate(gl2Backend);
|
mGLES2ContextCreate(gl2Backend);
|
||||||
m_backend = &gl2Backend->d;
|
m_backend = &gl2Backend->d;
|
||||||
|
QOpenGLFunctions* fn = m_gl->functions();
|
||||||
fn->glGenTextures(m_bridgeTexes.size(), m_bridgeTexes.data());
|
fn->glGenTextures(m_bridgeTexes.size(), m_bridgeTexes.data());
|
||||||
for (auto tex : m_bridgeTexes) {
|
for (auto tex : m_bridgeTexes) {
|
||||||
m_freeTex.enqueue(tex);
|
m_freeTex.enqueue(tex);
|
||||||
|
@ -546,7 +546,7 @@ void PainterGL::create() {
|
||||||
#if defined(BUILD_GLES2) || defined(BUILD_GLES3)
|
#if defined(BUILD_GLES2) || defined(BUILD_GLES3)
|
||||||
mGLES2Context* gl2Backend = reinterpret_cast<mGLES2Context*>(painter->m_backend);
|
mGLES2Context* gl2Backend = reinterpret_cast<mGLES2Context*>(painter->m_backend);
|
||||||
if (painter->m_widget && painter->supportsShaders()) {
|
if (painter->m_widget && painter->supportsShaders()) {
|
||||||
QOpenGLFunctions_Baseline* fn = painter->m_gl->versionFunctions<QOpenGLFunctions_Baseline>();
|
QOpenGLFunctions* fn = painter->m_gl->functions();
|
||||||
fn->glFinish();
|
fn->glFinish();
|
||||||
painter->m_widget->setTex(painter->m_finalTex[painter->m_finalTexIdx]);
|
painter->m_widget->setTex(painter->m_finalTex[painter->m_finalTexIdx]);
|
||||||
painter->m_finalTexIdx ^= 1;
|
painter->m_finalTexIdx ^= 1;
|
||||||
|
@ -592,7 +592,7 @@ void PainterGL::destroy() {
|
||||||
}
|
}
|
||||||
makeCurrent();
|
makeCurrent();
|
||||||
#if defined(BUILD_GLES2) || defined(BUILD_GLES3)
|
#if defined(BUILD_GLES2) || defined(BUILD_GLES3)
|
||||||
QOpenGLFunctions_Baseline* fn = m_gl->versionFunctions<QOpenGLFunctions_Baseline>();
|
QOpenGLFunctions* fn = m_gl->functions();
|
||||||
if (m_shader.passes) {
|
if (m_shader.passes) {
|
||||||
mGLES2ShaderFree(&m_shader);
|
mGLES2ShaderFree(&m_shader);
|
||||||
}
|
}
|
||||||
|
@ -683,7 +683,7 @@ void PainterGL::start() {
|
||||||
if (glContextHasBug(OpenGLBug::GLTHREAD_BLOCKS_SWAP)) {
|
if (glContextHasBug(OpenGLBug::GLTHREAD_BLOCKS_SWAP)) {
|
||||||
// Suggested on Discord as a way to strongly hint that glthread should be disabled
|
// Suggested on Discord as a way to strongly hint that glthread should be disabled
|
||||||
// See https://gitlab.freedesktop.org/mesa/mesa/-/issues/8035
|
// See https://gitlab.freedesktop.org/mesa/mesa/-/issues/8035
|
||||||
QOpenGLFunctions_Baseline* fn = m_gl->versionFunctions<QOpenGLFunctions_Baseline>();
|
QOpenGLFunctions* fn = m_gl->functions();
|
||||||
fn->glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
|
fn->glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -975,7 +975,7 @@ QOpenGLContext* PainterGL::shareContext() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void PainterGL::updateFramebufferHandle() {
|
void PainterGL::updateFramebufferHandle() {
|
||||||
QOpenGLFunctions_Baseline* fn = m_gl->versionFunctions<QOpenGLFunctions_Baseline>();
|
QOpenGLFunctions* fn = m_gl->functions();
|
||||||
// TODO: Figure out why glFlush doesn't work here on Intel/Windows
|
// TODO: Figure out why glFlush doesn't work here on Intel/Windows
|
||||||
if (glContextHasBug(OpenGLBug::CROSS_THREAD_FLUSH)) {
|
if (glContextHasBug(OpenGLBug::CROSS_THREAD_FLUSH)) {
|
||||||
fn->glFinish();
|
fn->glFinish();
|
||||||
|
|
|
@ -199,6 +199,8 @@ Window::Window(CoreManager* manager, ConfigController* config, int playerId, QWi
|
||||||
|
|
||||||
#ifdef BUILD_SDL
|
#ifdef BUILD_SDL
|
||||||
m_inputController.addInputDriver(std::make_shared<SDLInputDriver>(&m_inputController));
|
m_inputController.addInputDriver(std::make_shared<SDLInputDriver>(&m_inputController));
|
||||||
|
m_inputController.setGamepadDriver(SDL_BINDING_BUTTON);
|
||||||
|
m_inputController.setSensorDriver(SDL_BINDING_BUTTON);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
m_shortcutController->setConfigController(m_config);
|
m_shortcutController->setConfigController(m_config);
|
||||||
|
|
|
@ -16,11 +16,11 @@ GamepadHatEvent::GamepadHatEvent(QEvent::Type pressType, int hatId, Direction di
|
||||||
: QEvent(pressType)
|
: QEvent(pressType)
|
||||||
, m_hatId(hatId)
|
, m_hatId(hatId)
|
||||||
, m_direction(direction)
|
, m_direction(direction)
|
||||||
, m_key(-1)
|
, m_keys(0)
|
||||||
{
|
{
|
||||||
ignore();
|
ignore();
|
||||||
if (controller && controller->map()) {
|
if (controller && controller->map()) {
|
||||||
m_key = mInputMapHat(controller->map(), type, hatId, direction);
|
m_keys = mInputMapHat(controller->map(), type, hatId, direction);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -25,7 +25,7 @@ public:
|
||||||
|
|
||||||
int hatId() const { return m_hatId; }
|
int hatId() const { return m_hatId; }
|
||||||
Direction direction() const { return m_direction; }
|
Direction direction() const { return m_direction; }
|
||||||
int platformKey() const { return m_key; }
|
int platformKeys() const { return m_keys; }
|
||||||
|
|
||||||
static Type Down();
|
static Type Down();
|
||||||
static Type Up();
|
static Type Up();
|
||||||
|
@ -36,7 +36,7 @@ private:
|
||||||
|
|
||||||
int m_hatId;
|
int m_hatId;
|
||||||
Direction m_direction;
|
Direction m_direction;
|
||||||
int m_key;
|
int m_keys;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -236,7 +236,7 @@ int InputController::gamepadIndex(uint32_t type) const {
|
||||||
if (!driver) {
|
if (!driver) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
return driver->activeGamepad();
|
return driver->activeGamepadIndex();
|
||||||
}
|
}
|
||||||
|
|
||||||
void InputController::setGamepad(uint32_t type, int index) {
|
void InputController::setGamepad(uint32_t type, int index) {
|
||||||
|
@ -357,13 +357,9 @@ Gamepad* InputController::gamepad(uint32_t type) {
|
||||||
}
|
}
|
||||||
if (!driver->supportsGamepads()) {
|
if (!driver->supportsGamepads()) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
|
||||||
QList<Gamepad*> driverPads(driver->connectedGamepads());
|
|
||||||
int activeGamepad = driver->activeGamepad();
|
|
||||||
if (activeGamepad < 0 || activeGamepad >= driverPads.count()) {
|
|
||||||
return nullptr;
|
|
||||||
}
|
}
|
||||||
return driverPads[activeGamepad];
|
|
||||||
|
return driver->activeGamepad();
|
||||||
}
|
}
|
||||||
|
|
||||||
QList<Gamepad*> InputController::gamepads() {
|
QList<Gamepad*> InputController::gamepads() {
|
||||||
|
@ -372,16 +368,15 @@ QList<Gamepad*> InputController::gamepads() {
|
||||||
if (!driver->supportsGamepads()) {
|
if (!driver->supportsGamepads()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
QList<Gamepad*> driverPads(driver->connectedGamepads());
|
Gamepad* pad = driver->activeGamepad();
|
||||||
int activeGamepad = driver->activeGamepad();
|
if (pad) {
|
||||||
if (activeGamepad >= 0 && activeGamepad < driverPads.count()) {
|
pads.append(pad);
|
||||||
pads.append(driverPads[activeGamepad]);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return pads;
|
return pads;
|
||||||
}
|
}
|
||||||
|
|
||||||
QSet<int> InputController::activeGamepadButtons(int type) {
|
QSet<int> InputController::activeGamepadButtons(uint32_t type) {
|
||||||
QSet<int> activeButtons;
|
QSet<int> activeButtons;
|
||||||
Gamepad* pad = gamepad(type);
|
Gamepad* pad = gamepad(type);
|
||||||
if (!pad) {
|
if (!pad) {
|
||||||
|
@ -396,7 +391,7 @@ QSet<int> InputController::activeGamepadButtons(int type) {
|
||||||
return activeButtons;
|
return activeButtons;
|
||||||
}
|
}
|
||||||
|
|
||||||
QSet<QPair<int, GamepadAxisEvent::Direction>> InputController::activeGamepadAxes(int type) {
|
QSet<QPair<int, GamepadAxisEvent::Direction>> InputController::activeGamepadAxes(uint32_t type) {
|
||||||
QSet<QPair<int, GamepadAxisEvent::Direction>> activeAxes;
|
QSet<QPair<int, GamepadAxisEvent::Direction>> activeAxes;
|
||||||
Gamepad* pad = gamepad(type);
|
Gamepad* pad = gamepad(type);
|
||||||
if (!pad) {
|
if (!pad) {
|
||||||
|
@ -417,7 +412,7 @@ QSet<QPair<int, GamepadAxisEvent::Direction>> InputController::activeGamepadAxes
|
||||||
return activeAxes;
|
return activeAxes;
|
||||||
}
|
}
|
||||||
|
|
||||||
QSet<QPair<int, GamepadHatEvent::Direction>> InputController::activeGamepadHats(int type) {
|
QSet<QPair<int, GamepadHatEvent::Direction>> InputController::activeGamepadHats(uint32_t type) {
|
||||||
QSet<QPair<int, GamepadHatEvent::Direction>> activeHats;
|
QSet<QPair<int, GamepadHatEvent::Direction>> activeHats;
|
||||||
Gamepad* pad = gamepad(type);
|
Gamepad* pad = gamepad(type);
|
||||||
if (!pad) {
|
if (!pad) {
|
||||||
|
@ -432,7 +427,7 @@ QSet<QPair<int, GamepadHatEvent::Direction>> InputController::activeGamepadHats(
|
||||||
return activeHats;
|
return activeHats;
|
||||||
}
|
}
|
||||||
|
|
||||||
void InputController::testGamepad(int type) {
|
void InputController::testGamepad(uint32_t type) {
|
||||||
QWriteLocker l(&m_eventsLock);
|
QWriteLocker l(&m_eventsLock);
|
||||||
auto activeAxes = activeGamepadAxes(type);
|
auto activeAxes = activeGamepadAxes(type);
|
||||||
auto oldAxes = m_activeAxes;
|
auto oldAxes = m_activeAxes;
|
||||||
|
@ -496,15 +491,15 @@ void InputController::testGamepad(int type) {
|
||||||
|
|
||||||
for (auto& hat : activeHats) {
|
for (auto& hat : activeHats) {
|
||||||
GamepadHatEvent* event = new GamepadHatEvent(GamepadHatEvent::Down(), hat.first, hat.second, type, this);
|
GamepadHatEvent* event = new GamepadHatEvent(GamepadHatEvent::Down(), hat.first, hat.second, type, this);
|
||||||
postPendingEvent(event->platformKey());
|
postPendingEvents(event->platformKeys());
|
||||||
sendGamepadEvent(event);
|
sendGamepadEvent(event);
|
||||||
if (!event->isAccepted()) {
|
if (!event->isAccepted()) {
|
||||||
clearPendingEvent(event->platformKey());
|
clearPendingEvents(event->platformKeys());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (auto& hat : oldHats) {
|
for (auto& hat : oldHats) {
|
||||||
GamepadHatEvent* event = new GamepadHatEvent(GamepadHatEvent::Up(), hat.first, hat.second, type, this);
|
GamepadHatEvent* event = new GamepadHatEvent(GamepadHatEvent::Up(), hat.first, hat.second, type, this);
|
||||||
clearPendingEvent(event->platformKey());
|
clearPendingEvents(event->platformKeys());
|
||||||
sendGamepadEvent(event);
|
sendGamepadEvent(event);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -530,6 +525,22 @@ void InputController::clearPendingEvent(int key) {
|
||||||
m_pendingEvents.remove(key);
|
m_pendingEvents.remove(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void InputController::postPendingEvents(int keys) {
|
||||||
|
for (int i = 0; keys; ++i, keys >>= 1) {
|
||||||
|
if (keys & 1) {
|
||||||
|
m_pendingEvents.insert(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void InputController::clearPendingEvents(int keys) {
|
||||||
|
for (int i = 0; keys; ++i, keys >>= 1) {
|
||||||
|
if (keys & 1) {
|
||||||
|
m_pendingEvents.remove(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool InputController::hasPendingEvent(int key) const {
|
bool InputController::hasPendingEvent(int key) const {
|
||||||
return m_pendingEvents.contains(key);
|
return m_pendingEvents.contains(key);
|
||||||
}
|
}
|
||||||
|
|
|
@ -82,8 +82,8 @@ public:
|
||||||
static const int32_t AXIS_THRESHOLD = 0x3000;
|
static const int32_t AXIS_THRESHOLD = 0x3000;
|
||||||
|
|
||||||
void setGamepadDriver(uint32_t type);
|
void setGamepadDriver(uint32_t type);
|
||||||
const InputDriver* gamepadDriver() const { return m_inputDrivers.value(m_sensorDriver).get(); }
|
const InputDriver* gamepadDriver() const { return m_inputDrivers.value(m_gamepadDriver).get(); }
|
||||||
InputDriver* gamepadDriver() { return m_inputDrivers.value(m_sensorDriver).get(); }
|
InputDriver* gamepadDriver() { return m_inputDrivers.value(m_gamepadDriver).get(); }
|
||||||
|
|
||||||
QStringList connectedGamepads(uint32_t type = 0) const;
|
QStringList connectedGamepads(uint32_t type = 0) const;
|
||||||
int gamepadIndex(uint32_t type = 0) const;
|
int gamepadIndex(uint32_t type = 0) const;
|
||||||
|
@ -115,7 +115,7 @@ signals:
|
||||||
void luminanceValueChanged(int value);
|
void luminanceValueChanged(int value);
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void testGamepad(int type);
|
void testGamepad(uint32_t type);
|
||||||
void update();
|
void update();
|
||||||
|
|
||||||
void increaseLuminanceLevel();
|
void increaseLuminanceLevel();
|
||||||
|
@ -136,17 +136,19 @@ private slots:
|
||||||
void teardownCam();
|
void teardownCam();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void postPendingEvent(int);
|
void postPendingEvent(int key);
|
||||||
void clearPendingEvent(int);
|
void clearPendingEvent(int key);
|
||||||
bool hasPendingEvent(int) const;
|
void postPendingEvents(int keys);
|
||||||
|
void clearPendingEvents(int keys);
|
||||||
|
bool hasPendingEvent(int key) const;
|
||||||
void sendGamepadEvent(QEvent*);
|
void sendGamepadEvent(QEvent*);
|
||||||
|
|
||||||
Gamepad* gamepad(uint32_t type);
|
Gamepad* gamepad(uint32_t type);
|
||||||
QList<Gamepad*> gamepads();
|
QList<Gamepad*> gamepads();
|
||||||
|
|
||||||
QSet<int> activeGamepadButtons(int type);
|
QSet<int> activeGamepadButtons(uint32_t type);
|
||||||
QSet<QPair<int, GamepadAxisEvent::Direction>> activeGamepadAxes(int type);
|
QSet<QPair<int, GamepadAxisEvent::Direction>> activeGamepadAxes(uint32_t type);
|
||||||
QSet<QPair<int, GamepadHatEvent::Direction>> activeGamepadHats(int type);
|
QSet<QPair<int, GamepadHatEvent::Direction>> activeGamepadHats(uint32_t type);
|
||||||
|
|
||||||
struct InputControllerLux : GBALuminanceSource {
|
struct InputControllerLux : GBALuminanceSource {
|
||||||
InputController* p;
|
InputController* p;
|
||||||
|
|
|
@ -40,14 +40,32 @@ QList<Gamepad*> InputDriver::connectedGamepads() const {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
int InputDriver::activeKeySource() const {
|
int InputDriver::activeKeySourceIndex() const {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int InputDriver::activeGamepad() const {
|
int InputDriver::activeGamepadIndex() const {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
KeySource* InputDriver::activeKeySource() {
|
||||||
|
QList<KeySource*> ks(connectedKeySources());
|
||||||
|
int activeKeySource = activeKeySourceIndex();
|
||||||
|
if (activeKeySource < 0 || activeKeySource >= ks.count()) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
return ks[activeKeySource];
|
||||||
|
}
|
||||||
|
|
||||||
|
Gamepad* InputDriver::activeGamepad() {
|
||||||
|
QList<Gamepad*> pads(connectedGamepads());
|
||||||
|
int activeGamepad = activeGamepadIndex();
|
||||||
|
if (activeGamepad < 0 || activeGamepad >= pads.count()) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
return pads[activeGamepad];
|
||||||
|
}
|
||||||
|
|
||||||
void InputDriver::setActiveKeySource(int) {
|
void InputDriver::setActiveKeySource(int) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -44,8 +44,11 @@ public:
|
||||||
virtual QList<KeySource*> connectedKeySources() const;
|
virtual QList<KeySource*> connectedKeySources() const;
|
||||||
virtual QList<Gamepad*> connectedGamepads() const;
|
virtual QList<Gamepad*> connectedGamepads() const;
|
||||||
|
|
||||||
virtual int activeKeySource() const;
|
virtual int activeKeySourceIndex() const;
|
||||||
virtual int activeGamepad() const;
|
virtual int activeGamepadIndex() const;
|
||||||
|
|
||||||
|
KeySource* activeKeySource();
|
||||||
|
Gamepad* activeGamepad();
|
||||||
|
|
||||||
virtual void setActiveKeySource(int);
|
virtual void setActiveKeySource(int);
|
||||||
virtual void setActiveGamepad(int);
|
virtual void setActiveGamepad(int);
|
||||||
|
|
|
@ -66,10 +66,7 @@ int InputMapper::mapAxes(QList<int16_t> axes) const {
|
||||||
int InputMapper::mapHats(QList<GamepadHatEvent::Direction> hats) const {
|
int InputMapper::mapHats(QList<GamepadHatEvent::Direction> hats) const {
|
||||||
int platformKeys = 0;
|
int platformKeys = 0;
|
||||||
for (int i = 0; i < hats.count(); ++i) {
|
for (int i = 0; i < hats.count(); ++i) {
|
||||||
int platformKey = mInputMapHat(m_map, m_type, i, hats[i]);
|
platformKeys |= mInputMapHat(m_map, m_type, i, hats[i]);
|
||||||
if (platformKey >= 0) {
|
|
||||||
platformKeys |= 1 << platformKey;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return platformKeys;
|
return platformKeys;
|
||||||
}
|
}
|
||||||
|
|
|
@ -173,7 +173,7 @@ void SDLInputDriver::updateGamepads() {
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
int SDLInputDriver::activeGamepad() const {
|
int SDLInputDriver::activeGamepadIndex() const {
|
||||||
return m_sdlPlayer.joystick ? m_sdlPlayer.joystick->index : 0;
|
return m_sdlPlayer.joystick ? m_sdlPlayer.joystick->index : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -46,7 +46,7 @@ public:
|
||||||
|
|
||||||
QList<Gamepad*> connectedGamepads() const override;
|
QList<Gamepad*> connectedGamepads() const override;
|
||||||
|
|
||||||
int activeGamepad() const override;
|
int activeGamepadIndex() const override;
|
||||||
void setActiveGamepad(int) override;
|
void setActiveGamepad(int) override;
|
||||||
|
|
||||||
void registerTiltAxisX(int axis) override;
|
void registerTiltAxisX(int axis) override;
|
||||||
|
|
|
@ -42,6 +42,7 @@ Q_IMPORT_PLUGIN(AVFServicePlugin);
|
||||||
#endif
|
#endif
|
||||||
#elif defined(Q_OS_UNIX)
|
#elif defined(Q_OS_UNIX)
|
||||||
Q_IMPORT_PLUGIN(QXcbIntegrationPlugin);
|
Q_IMPORT_PLUGIN(QXcbIntegrationPlugin);
|
||||||
|
Q_IMPORT_PLUGIN(QWaylandIntegrationPlugin);
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -12,8 +12,9 @@ set(TEST_FILES
|
||||||
if(USE_LUA)
|
if(USE_LUA)
|
||||||
list(APPEND SOURCE_FILES engines/lua.c)
|
list(APPEND SOURCE_FILES engines/lua.c)
|
||||||
list(APPEND TEST_FILES
|
list(APPEND TEST_FILES
|
||||||
test/stdlib.c
|
test/context.c
|
||||||
test/lua.c)
|
test/lua.c
|
||||||
|
test/stdlib.c)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
source_group("Scripting" FILES ${SOURCE_FILES})
|
source_group("Scripting" FILES ${SOURCE_FILES})
|
||||||
|
|
|
@ -71,8 +71,8 @@ void mScriptContextInit(struct mScriptContext* context) {
|
||||||
|
|
||||||
void mScriptContextDeinit(struct mScriptContext* context) {
|
void mScriptContextDeinit(struct mScriptContext* context) {
|
||||||
HashTableDeinit(&context->rootScope);
|
HashTableDeinit(&context->rootScope);
|
||||||
HashTableDeinit(&context->weakrefs);
|
|
||||||
mScriptContextDrainPool(context);
|
mScriptContextDrainPool(context);
|
||||||
|
HashTableDeinit(&context->weakrefs);
|
||||||
mScriptListDeinit(&context->refPool);
|
mScriptListDeinit(&context->refPool);
|
||||||
HashTableDeinit(&context->callbacks);
|
HashTableDeinit(&context->callbacks);
|
||||||
TableDeinit(&context->callbackId);
|
TableDeinit(&context->callbackId);
|
||||||
|
@ -102,9 +102,12 @@ void mScriptContextFillPool(struct mScriptContext* context, struct mScriptValue*
|
||||||
void mScriptContextDrainPool(struct mScriptContext* context) {
|
void mScriptContextDrainPool(struct mScriptContext* context) {
|
||||||
size_t i;
|
size_t i;
|
||||||
for (i = 0; i < mScriptListSize(&context->refPool); ++i) {
|
for (i = 0; i < mScriptListSize(&context->refPool); ++i) {
|
||||||
struct mScriptValue* value = mScriptValueUnwrap(mScriptListGetPointer(&context->refPool, i));
|
struct mScriptValue* value = mScriptListGetPointer(&context->refPool, i);
|
||||||
if (value) {
|
if (value->type->base == mSCRIPT_TYPE_WRAPPER) {
|
||||||
|
value = mScriptValueUnwrap(value);
|
||||||
mScriptValueDeref(value);
|
mScriptValueDeref(value);
|
||||||
|
} else if (value->type == mSCRIPT_TYPE_MS_WEAKREF) {
|
||||||
|
mScriptContextClearWeakref(context, value->value.u32);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mScriptListClear(&context->refPool);
|
mScriptListClear(&context->refPool);
|
||||||
|
@ -201,6 +204,13 @@ void mScriptContextClearWeakref(struct mScriptContext* context, uint32_t weakref
|
||||||
TableRemove(&context->weakrefs, weakref);
|
TableRemove(&context->weakrefs, weakref);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void mScriptContextDisownWeakref(struct mScriptContext* context, uint32_t weakref) {
|
||||||
|
struct mScriptValue* poolEntry = mScriptListAppend(&context->refPool);
|
||||||
|
poolEntry->type = mSCRIPT_TYPE_MS_WEAKREF;
|
||||||
|
poolEntry->value.u32 = weakref;
|
||||||
|
poolEntry->refs = mSCRIPT_VALUE_UNREF;
|
||||||
|
}
|
||||||
|
|
||||||
void mScriptContextTriggerCallback(struct mScriptContext* context, const char* callback) {
|
void mScriptContextTriggerCallback(struct mScriptContext* context, const char* callback) {
|
||||||
struct mScriptValue* list = HashTableLookup(&context->callbacks, callback);
|
struct mScriptValue* list = HashTableLookup(&context->callbacks, callback);
|
||||||
if (!list) {
|
if (!list) {
|
||||||
|
|
|
@ -738,7 +738,19 @@ bool _luaWrap(struct mScriptEngineContextLua* luaContext, struct mScriptValue* v
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case mSCRIPT_TYPE_STRING:
|
case mSCRIPT_TYPE_STRING:
|
||||||
lua_pushlstring(luaContext->lua, value->value.string->buffer, value->value.string->size);
|
if (!value->value.string) {
|
||||||
|
lua_pushnil(luaContext->lua);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (value->type == mSCRIPT_TYPE_MS_STR) {
|
||||||
|
lua_pushlstring(luaContext->lua, value->value.string->buffer, value->value.string->size);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (value->type == mSCRIPT_TYPE_MS_CHARP) {
|
||||||
|
lua_pushstring(luaContext->lua, value->value.copaque);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
ok = false;
|
||||||
break;
|
break;
|
||||||
case mSCRIPT_TYPE_LIST:
|
case mSCRIPT_TYPE_LIST:
|
||||||
newValue = lua_newuserdata(luaContext->lua, sizeof(*newValue));
|
newValue = lua_newuserdata(luaContext->lua, sizeof(*newValue));
|
||||||
|
@ -769,6 +781,10 @@ bool _luaWrap(struct mScriptEngineContextLua* luaContext, struct mScriptValue* v
|
||||||
mScriptValueDeref(value);
|
mScriptValueDeref(value);
|
||||||
break;
|
break;
|
||||||
case mSCRIPT_TYPE_OBJECT:
|
case mSCRIPT_TYPE_OBJECT:
|
||||||
|
if (!value->value.opaque) {
|
||||||
|
lua_pushnil(luaContext->lua);
|
||||||
|
break;
|
||||||
|
}
|
||||||
newValue = lua_newuserdata(luaContext->lua, sizeof(*newValue));
|
newValue = lua_newuserdata(luaContext->lua, sizeof(*newValue));
|
||||||
if (needsWeakref) {
|
if (needsWeakref) {
|
||||||
*newValue = mSCRIPT_MAKE(WEAKREF, weakref);
|
*newValue = mSCRIPT_MAKE(WEAKREF, weakref);
|
||||||
|
|
|
@ -14,6 +14,8 @@ struct TestA {
|
||||||
int32_t i2;
|
int32_t i2;
|
||||||
int8_t b8;
|
int8_t b8;
|
||||||
int16_t hUnaligned;
|
int16_t hUnaligned;
|
||||||
|
struct mScriptValue table;
|
||||||
|
struct mScriptList list;
|
||||||
int32_t (*ifn0)(struct TestA*);
|
int32_t (*ifn0)(struct TestA*);
|
||||||
int32_t (*ifn1)(struct TestA*, int);
|
int32_t (*ifn1)(struct TestA*, int);
|
||||||
void (*vfn0)(struct TestA*);
|
void (*vfn0)(struct TestA*);
|
||||||
|
@ -103,6 +105,8 @@ mSCRIPT_DEFINE_STRUCT(TestA)
|
||||||
mSCRIPT_DEFINE_STRUCT_MEMBER(TestA, S32, i2)
|
mSCRIPT_DEFINE_STRUCT_MEMBER(TestA, S32, i2)
|
||||||
mSCRIPT_DEFINE_STRUCT_MEMBER(TestA, S8, b8)
|
mSCRIPT_DEFINE_STRUCT_MEMBER(TestA, S8, b8)
|
||||||
mSCRIPT_DEFINE_STRUCT_MEMBER(TestA, S16, hUnaligned)
|
mSCRIPT_DEFINE_STRUCT_MEMBER(TestA, S16, hUnaligned)
|
||||||
|
mSCRIPT_DEFINE_STRUCT_MEMBER(TestA, TABLE, table)
|
||||||
|
mSCRIPT_DEFINE_STRUCT_MEMBER(TestA, LIST, list)
|
||||||
mSCRIPT_DEFINE_STRUCT_METHOD(TestA, ifn0)
|
mSCRIPT_DEFINE_STRUCT_METHOD(TestA, ifn0)
|
||||||
mSCRIPT_DEFINE_STRUCT_METHOD(TestA, ifn1)
|
mSCRIPT_DEFINE_STRUCT_METHOD(TestA, ifn1)
|
||||||
mSCRIPT_DEFINE_STRUCT_METHOD(TestA, icfn0)
|
mSCRIPT_DEFINE_STRUCT_METHOD(TestA, icfn0)
|
||||||
|
@ -187,6 +191,20 @@ M_TEST_DEFINE(testALayout) {
|
||||||
assert_ptr_equal(member->type, mSCRIPT_TYPE_MS_S16);
|
assert_ptr_equal(member->type, mSCRIPT_TYPE_MS_S16);
|
||||||
assert_int_not_equal(member->offset, sizeof(int32_t) * 2 + 1);
|
assert_int_not_equal(member->offset, sizeof(int32_t) * 2 + 1);
|
||||||
|
|
||||||
|
member = HashTableLookup(&cls->instanceMembers, "table");
|
||||||
|
assert_non_null(member);
|
||||||
|
assert_string_equal(member->name, "table");
|
||||||
|
assert_null(member->docstring);
|
||||||
|
assert_ptr_equal(member->type, mSCRIPT_TYPE_MS_TABLE);
|
||||||
|
assert_int_equal(member->offset, &((struct TestA*) 0)->table);
|
||||||
|
|
||||||
|
member = HashTableLookup(&cls->instanceMembers, "list");
|
||||||
|
assert_non_null(member);
|
||||||
|
assert_string_equal(member->name, "list");
|
||||||
|
assert_null(member->docstring);
|
||||||
|
assert_ptr_equal(member->type, mSCRIPT_TYPE_MS_LIST);
|
||||||
|
assert_int_equal(member->offset, &((struct TestA*) 0)->list);
|
||||||
|
|
||||||
member = HashTableLookup(&cls->instanceMembers, "unknown");
|
member = HashTableLookup(&cls->instanceMembers, "unknown");
|
||||||
assert_null(member);
|
assert_null(member);
|
||||||
|
|
||||||
|
@ -280,6 +298,12 @@ M_TEST_DEFINE(testAGet) {
|
||||||
.hUnaligned = 4
|
.hUnaligned = 4
|
||||||
};
|
};
|
||||||
|
|
||||||
|
mScriptListInit(&s.list, 1);
|
||||||
|
*mScriptListAppend(&s.list) = mSCRIPT_MAKE_S32(5);
|
||||||
|
|
||||||
|
s.table.type = mSCRIPT_TYPE_MS_TABLE;
|
||||||
|
s.table.type->alloc(&s.table);
|
||||||
|
|
||||||
struct mScriptValue sval = mSCRIPT_MAKE_S(TestA, &s);
|
struct mScriptValue sval = mSCRIPT_MAKE_S(TestA, &s);
|
||||||
struct mScriptValue val;
|
struct mScriptValue val;
|
||||||
struct mScriptValue compare;
|
struct mScriptValue compare;
|
||||||
|
@ -300,8 +324,34 @@ M_TEST_DEFINE(testAGet) {
|
||||||
assert_true(mScriptObjectGet(&sval, "hUnaligned", &val));
|
assert_true(mScriptObjectGet(&sval, "hUnaligned", &val));
|
||||||
assert_true(compare.type->equal(&compare, &val));
|
assert_true(compare.type->equal(&compare, &val));
|
||||||
|
|
||||||
|
compare = mSCRIPT_MAKE_S32(5);
|
||||||
|
assert_true(mScriptObjectGet(&sval, "list", &val));
|
||||||
|
assert_ptr_equal(val.type, mSCRIPT_TYPE_MS_LIST);
|
||||||
|
assert_int_equal(mScriptListSize(val.value.list), 1);
|
||||||
|
assert_true(compare.type->equal(&compare, mScriptListGetPointer(val.value.list, 0)));
|
||||||
|
|
||||||
|
*mScriptListAppend(&s.list) = mSCRIPT_MAKE_S32(6);
|
||||||
|
compare = mSCRIPT_MAKE_S32(6);
|
||||||
|
assert_int_equal(mScriptListSize(val.value.list), 2);
|
||||||
|
assert_true(compare.type->equal(&compare, mScriptListGetPointer(val.value.list, 1)));
|
||||||
|
|
||||||
|
struct mScriptValue* ival = &val;
|
||||||
|
assert_true(mScriptObjectGet(&sval, "table", &val));
|
||||||
|
if (val.type->base == mSCRIPT_TYPE_WRAPPER) {
|
||||||
|
ival = mScriptValueUnwrap(&val);
|
||||||
|
}
|
||||||
|
assert_ptr_equal(ival->type, mSCRIPT_TYPE_MS_TABLE);
|
||||||
|
assert_int_equal(mScriptTableSize(ival), 0);
|
||||||
|
compare = mSCRIPT_MAKE_S32(7);
|
||||||
|
mScriptTableInsert(&s.table, &compare, &compare);
|
||||||
|
assert_int_equal(mScriptTableSize(&s.table), 1);
|
||||||
|
assert_int_equal(mScriptTableSize(ival), 1);
|
||||||
|
|
||||||
assert_false(mScriptObjectGet(&sval, "unknown", &val));
|
assert_false(mScriptObjectGet(&sval, "unknown", &val));
|
||||||
|
|
||||||
|
mScriptListDeinit(&s.list);
|
||||||
|
mSCRIPT_TYPE_MS_TABLE->free(&s.table);
|
||||||
|
|
||||||
assert_true(cls->init);
|
assert_true(cls->init);
|
||||||
mScriptClassDeinit(cls);
|
mScriptClassDeinit(cls);
|
||||||
assert_false(cls->init);
|
assert_false(cls->init);
|
||||||
|
|
|
@ -0,0 +1,103 @@
|
||||||
|
/* Copyright (c) 2013-2023 Jeffrey Pfau
|
||||||
|
*
|
||||||
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
#include "util/test/suite.h"
|
||||||
|
|
||||||
|
#include <mgba/script/context.h>
|
||||||
|
#include <mgba/script/macros.h>
|
||||||
|
#include <mgba/script/types.h>
|
||||||
|
|
||||||
|
M_TEST_DEFINE(weakrefBasic) {
|
||||||
|
struct mScriptContext context;
|
||||||
|
mScriptContextInit(&context);
|
||||||
|
|
||||||
|
struct mScriptValue weakref = mSCRIPT_VAL(WEAKREF, 1);
|
||||||
|
struct mScriptValue fakeVal = mSCRIPT_S32(0x7E57CA5E);
|
||||||
|
struct mScriptValue* val;
|
||||||
|
|
||||||
|
assert_int_equal(TableSize(&context.weakrefs), 0);
|
||||||
|
assert_null(TableLookup(&context.weakrefs, 1));
|
||||||
|
assert_int_equal(context.nextWeakref, 1);
|
||||||
|
assert_null(mScriptContextAccessWeakref(&context, &weakref));
|
||||||
|
|
||||||
|
assert_int_equal(mScriptContextSetWeakref(&context, &fakeVal), 1);
|
||||||
|
assert_int_equal(context.nextWeakref, 2);
|
||||||
|
assert_int_equal(TableSize(&context.weakrefs), 1);
|
||||||
|
val = mScriptContextAccessWeakref(&context, &weakref);
|
||||||
|
assert_non_null(val);
|
||||||
|
assert_int_equal(val->value.u32, 0x7E57CA5E);
|
||||||
|
|
||||||
|
mScriptContextClearWeakref(&context, 1);
|
||||||
|
|
||||||
|
assert_int_equal(TableSize(&context.weakrefs), 0);
|
||||||
|
assert_null(TableLookup(&context.weakrefs, 1));
|
||||||
|
assert_int_equal(context.nextWeakref, 2);
|
||||||
|
assert_null(mScriptContextAccessWeakref(&context, &weakref));
|
||||||
|
|
||||||
|
mScriptContextDeinit(&context);
|
||||||
|
}
|
||||||
|
|
||||||
|
M_TEST_DEFINE(drainPool) {
|
||||||
|
struct mScriptContext context;
|
||||||
|
mScriptContextInit(&context);
|
||||||
|
|
||||||
|
assert_int_equal(mScriptListSize(&context.refPool), 0);
|
||||||
|
|
||||||
|
struct mScriptValue fakeVal = mSCRIPT_CHARP("foo");
|
||||||
|
fakeVal.refs = 2;
|
||||||
|
|
||||||
|
mScriptContextFillPool(&context, &fakeVal);
|
||||||
|
assert_int_equal(mScriptListSize(&context.refPool), 1);
|
||||||
|
assert_int_equal(fakeVal.refs, 2);
|
||||||
|
|
||||||
|
mScriptContextDrainPool(&context);
|
||||||
|
assert_int_equal(mScriptListSize(&context.refPool), 0);
|
||||||
|
assert_int_equal(fakeVal.refs, 1);
|
||||||
|
|
||||||
|
mScriptContextDeinit(&context);
|
||||||
|
}
|
||||||
|
|
||||||
|
M_TEST_DEFINE(disownWeakref) {
|
||||||
|
struct mScriptContext context;
|
||||||
|
mScriptContextInit(&context);
|
||||||
|
|
||||||
|
struct mScriptValue weakref = mSCRIPT_VAL(WEAKREF, 1);
|
||||||
|
struct mScriptValue fakeVal = mSCRIPT_S32(0x7E57CA5E);
|
||||||
|
struct mScriptValue* val;
|
||||||
|
|
||||||
|
assert_int_equal(mScriptListSize(&context.refPool), 0);
|
||||||
|
assert_int_equal(TableSize(&context.weakrefs), 0);
|
||||||
|
assert_null(TableLookup(&context.weakrefs, 1));
|
||||||
|
assert_int_equal(context.nextWeakref, 1);
|
||||||
|
assert_null(mScriptContextAccessWeakref(&context, &weakref));
|
||||||
|
|
||||||
|
assert_int_equal(mScriptContextSetWeakref(&context, &fakeVal), 1);
|
||||||
|
assert_int_equal(TableSize(&context.weakrefs), 1);
|
||||||
|
assert_int_equal(context.nextWeakref, 2);
|
||||||
|
val = mScriptContextAccessWeakref(&context, &weakref);
|
||||||
|
assert_non_null(val);
|
||||||
|
assert_int_equal(val->value.u32, 0x7E57CA5E);
|
||||||
|
|
||||||
|
mScriptContextDisownWeakref(&context, 1);
|
||||||
|
assert_int_equal(mScriptListSize(&context.refPool), 1);
|
||||||
|
assert_int_equal(TableSize(&context.weakrefs), 1);
|
||||||
|
val = mScriptContextAccessWeakref(&context, &weakref);
|
||||||
|
assert_non_null(val);
|
||||||
|
assert_int_equal(val->value.u32, 0x7E57CA5E);
|
||||||
|
|
||||||
|
mScriptContextDrainPool(&context);
|
||||||
|
assert_int_equal(mScriptListSize(&context.refPool), 0);
|
||||||
|
assert_int_equal(TableSize(&context.weakrefs), 0);
|
||||||
|
assert_null(TableLookup(&context.weakrefs, 1));
|
||||||
|
assert_null(mScriptContextAccessWeakref(&context, &weakref));
|
||||||
|
|
||||||
|
mScriptContextDeinit(&context);
|
||||||
|
}
|
||||||
|
|
||||||
|
M_TEST_SUITE_DEFINE(mScript,
|
||||||
|
cmocka_unit_test(weakrefBasic),
|
||||||
|
cmocka_unit_test(drainPool),
|
||||||
|
cmocka_unit_test(disownWeakref),
|
||||||
|
)
|
|
@ -371,6 +371,33 @@ M_TEST_DEFINE(callCFunc) {
|
||||||
|
|
||||||
mScriptContextDeinit(&context);
|
mScriptContextDeinit(&context);
|
||||||
}
|
}
|
||||||
|
M_TEST_DEFINE(globalNull) {
|
||||||
|
SETUP_LUA;
|
||||||
|
|
||||||
|
struct Test s = {};
|
||||||
|
struct mScriptValue* val;
|
||||||
|
struct mScriptValue a;
|
||||||
|
|
||||||
|
LOAD_PROGRAM("assert(a)");
|
||||||
|
|
||||||
|
a = mSCRIPT_MAKE_CHARP("hello");
|
||||||
|
assert_true(lua->setGlobal(lua, "a", &a));
|
||||||
|
assert_true(lua->run(lua));
|
||||||
|
|
||||||
|
a = mSCRIPT_MAKE_CHARP(NULL);
|
||||||
|
assert_true(lua->setGlobal(lua, "a", &a));
|
||||||
|
assert_false(lua->run(lua));
|
||||||
|
|
||||||
|
a = mSCRIPT_MAKE_S(Test, &s);
|
||||||
|
assert_true(lua->setGlobal(lua, "a", &a));
|
||||||
|
assert_true(lua->run(lua));
|
||||||
|
|
||||||
|
a = mSCRIPT_MAKE_S(Test, NULL);
|
||||||
|
assert_true(lua->setGlobal(lua, "a", &a));
|
||||||
|
assert_false(lua->run(lua));
|
||||||
|
|
||||||
|
mScriptContextDeinit(&context);
|
||||||
|
}
|
||||||
|
|
||||||
M_TEST_DEFINE(globalStructFieldGet) {
|
M_TEST_DEFINE(globalStructFieldGet) {
|
||||||
SETUP_LUA;
|
SETUP_LUA;
|
||||||
|
@ -709,6 +736,7 @@ M_TEST_SUITE_DEFINE_SETUP_TEARDOWN(mScriptLua,
|
||||||
cmocka_unit_test(rootScope),
|
cmocka_unit_test(rootScope),
|
||||||
cmocka_unit_test(callLuaFunc),
|
cmocka_unit_test(callLuaFunc),
|
||||||
cmocka_unit_test(callCFunc),
|
cmocka_unit_test(callCFunc),
|
||||||
|
cmocka_unit_test(globalNull),
|
||||||
cmocka_unit_test(globalStructFieldGet),
|
cmocka_unit_test(globalStructFieldGet),
|
||||||
cmocka_unit_test(globalStructFieldSet),
|
cmocka_unit_test(globalStructFieldSet),
|
||||||
cmocka_unit_test(globalStructMethods),
|
cmocka_unit_test(globalStructMethods),
|
||||||
|
|
|
@ -76,6 +76,14 @@ static int isSequential(struct mScriptList* list) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool isNullCharp(const char* arg) {
|
||||||
|
return !arg;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool isNullStruct(struct Test* arg) {
|
||||||
|
return !arg;
|
||||||
|
}
|
||||||
|
|
||||||
mSCRIPT_BIND_FUNCTION(boundVoidOne, S32, voidOne, 0);
|
mSCRIPT_BIND_FUNCTION(boundVoidOne, S32, voidOne, 0);
|
||||||
mSCRIPT_BIND_VOID_FUNCTION(boundDiscard, discard, 1, S32, ignored);
|
mSCRIPT_BIND_VOID_FUNCTION(boundDiscard, discard, 1, S32, ignored);
|
||||||
mSCRIPT_BIND_FUNCTION(boundIdentityInt, S32, identityInt, 1, S32, in);
|
mSCRIPT_BIND_FUNCTION(boundIdentityInt, S32, identityInt, 1, S32, in);
|
||||||
|
@ -86,6 +94,8 @@ mSCRIPT_BIND_FUNCTION(boundAddInts, S32, addInts, 2, S32, a, S32, b);
|
||||||
mSCRIPT_BIND_FUNCTION(boundSubInts, S32, subInts, 2, S32, a, S32, b);
|
mSCRIPT_BIND_FUNCTION(boundSubInts, S32, subInts, 2, S32, a, S32, b);
|
||||||
mSCRIPT_BIND_FUNCTION(boundIsHello, S32, isHello, 1, CHARP, str);
|
mSCRIPT_BIND_FUNCTION(boundIsHello, S32, isHello, 1, CHARP, str);
|
||||||
mSCRIPT_BIND_FUNCTION(boundIsSequential, S32, isSequential, 1, LIST, list);
|
mSCRIPT_BIND_FUNCTION(boundIsSequential, S32, isSequential, 1, LIST, list);
|
||||||
|
mSCRIPT_BIND_FUNCTION(boundIsNullCharp, BOOL, isNullCharp, 1, CHARP, arg);
|
||||||
|
mSCRIPT_BIND_FUNCTION(boundIsNullStruct, BOOL, isNullStruct, 1, S(Test), arg);
|
||||||
|
|
||||||
M_TEST_DEFINE(voidArgs) {
|
M_TEST_DEFINE(voidArgs) {
|
||||||
struct mScriptFrame frame;
|
struct mScriptFrame frame;
|
||||||
|
@ -1261,6 +1271,43 @@ M_TEST_DEFINE(invokeList) {
|
||||||
mScriptListDeinit(&list);
|
mScriptListDeinit(&list);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
M_TEST_DEFINE(nullString) {
|
||||||
|
struct mScriptFrame frame;
|
||||||
|
bool res;
|
||||||
|
mScriptFrameInit(&frame);
|
||||||
|
|
||||||
|
mSCRIPT_PUSH(&frame.arguments, CHARP, "hi");
|
||||||
|
assert_true(mScriptInvoke(&boundIsNullCharp, &frame));
|
||||||
|
assert_true(mScriptPopBool(&frame.returnValues, &res));
|
||||||
|
assert_false(res);
|
||||||
|
|
||||||
|
mSCRIPT_PUSH(&frame.arguments, CHARP, NULL);
|
||||||
|
assert_true(mScriptInvoke(&boundIsNullCharp, &frame));
|
||||||
|
assert_true(mScriptPopBool(&frame.returnValues, &res));
|
||||||
|
assert_true(res);
|
||||||
|
|
||||||
|
mScriptFrameDeinit(&frame);
|
||||||
|
}
|
||||||
|
|
||||||
|
M_TEST_DEFINE(nullStruct) {
|
||||||
|
struct mScriptFrame frame;
|
||||||
|
struct Test v = {};
|
||||||
|
bool res;
|
||||||
|
mScriptFrameInit(&frame);
|
||||||
|
|
||||||
|
mSCRIPT_PUSH(&frame.arguments, S(Test), &v);
|
||||||
|
assert_true(mScriptInvoke(&boundIsNullStruct, &frame));
|
||||||
|
assert_true(mScriptPopBool(&frame.returnValues, &res));
|
||||||
|
assert_false(res);
|
||||||
|
|
||||||
|
mSCRIPT_PUSH(&frame.arguments, S(Test), NULL);
|
||||||
|
assert_true(mScriptInvoke(&boundIsNullStruct, &frame));
|
||||||
|
assert_true(mScriptPopBool(&frame.returnValues, &res));
|
||||||
|
assert_true(res);
|
||||||
|
|
||||||
|
mScriptFrameDeinit(&frame);
|
||||||
|
}
|
||||||
|
|
||||||
M_TEST_SUITE_DEFINE(mScript,
|
M_TEST_SUITE_DEFINE(mScript,
|
||||||
cmocka_unit_test(voidArgs),
|
cmocka_unit_test(voidArgs),
|
||||||
cmocka_unit_test(voidFunc),
|
cmocka_unit_test(voidFunc),
|
||||||
|
@ -1295,4 +1342,6 @@ M_TEST_SUITE_DEFINE(mScript,
|
||||||
cmocka_unit_test(stringIsHello),
|
cmocka_unit_test(stringIsHello),
|
||||||
cmocka_unit_test(stringIsNotHello),
|
cmocka_unit_test(stringIsNotHello),
|
||||||
cmocka_unit_test(invokeList),
|
cmocka_unit_test(invokeList),
|
||||||
|
cmocka_unit_test(nullString),
|
||||||
|
cmocka_unit_test(nullStruct),
|
||||||
)
|
)
|
||||||
|
|
|
@ -1178,6 +1178,12 @@ static bool _accessRawMember(struct mScriptClassMember* member, void* raw, bool
|
||||||
val->type = mSCRIPT_TYPE_MS_WRAPPER;
|
val->type = mSCRIPT_TYPE_MS_WRAPPER;
|
||||||
val->value.table = raw;
|
val->value.table = raw;
|
||||||
break;
|
break;
|
||||||
|
case mSCRIPT_TYPE_LIST:
|
||||||
|
val->refs = mSCRIPT_VALUE_UNREF;
|
||||||
|
val->flags = 0;
|
||||||
|
val->type = mSCRIPT_TYPE_MS_LIST;
|
||||||
|
val->value.list = raw;
|
||||||
|
break;
|
||||||
case mSCRIPT_TYPE_FUNCTION:
|
case mSCRIPT_TYPE_FUNCTION:
|
||||||
val->refs = mSCRIPT_VALUE_UNREF;
|
val->refs = mSCRIPT_VALUE_UNREF;
|
||||||
val->flags = 0;
|
val->flags = 0;
|
||||||
|
|
|
@ -8,6 +8,7 @@ set(BASE_SOURCE_FILES
|
||||||
hash.c
|
hash.c
|
||||||
string.c
|
string.c
|
||||||
table.c
|
table.c
|
||||||
|
vector.c
|
||||||
vfs.c)
|
vfs.c)
|
||||||
|
|
||||||
set(SOURCE_FILES
|
set(SOURCE_FILES
|
||||||
|
|
|
@ -5,12 +5,8 @@
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
#include <mgba-util/string.h>
|
#include <mgba-util/string.h>
|
||||||
|
|
||||||
#include <mgba-util/vector.h>
|
|
||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
DEFINE_VECTOR(StringList, char*);
|
|
||||||
|
|
||||||
#ifndef HAVE_STRNDUP
|
#ifndef HAVE_STRNDUP
|
||||||
char* strndup(const char* start, size_t len) {
|
char* strndup(const char* start, size_t len) {
|
||||||
// This is suboptimal, but anything recent should have strndup
|
// This is suboptimal, but anything recent should have strndup
|
||||||
|
|
|
@ -0,0 +1,17 @@
|
||||||
|
/* Copyright (c) 2013-2023 Jeffrey Pfau
|
||||||
|
*
|
||||||
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
#include <mgba-util/vector.h>
|
||||||
|
|
||||||
|
DEFINE_VECTOR(IntList, int);
|
||||||
|
DEFINE_VECTOR(SInt8List, int8_t);
|
||||||
|
DEFINE_VECTOR(SInt16List, int16_t);
|
||||||
|
DEFINE_VECTOR(SInt32List, int32_t);
|
||||||
|
DEFINE_VECTOR(SIntPtrList, intptr_t);
|
||||||
|
DEFINE_VECTOR(UInt8List, uint8_t);
|
||||||
|
DEFINE_VECTOR(UInt16List, uint16_t);
|
||||||
|
DEFINE_VECTOR(UInt32List, uint32_t);
|
||||||
|
DEFINE_VECTOR(UIntPtrList, uintptr_t);
|
||||||
|
DEFINE_VECTOR(StringList, char*);
|
Loading…
Reference in New Issue