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:
|
||||
- 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)
|
||||
Other fixes:
|
||||
- Qt: Fix crash when attempting to use OpenGL 2.1 to 3.1 (fixes mgba.io/i/2794)
|
||||
Misc:
|
||||
- GB Serialize: Add missing savestate support for MBC6 and NT (newer)
|
||||
- GBA: Improve detection of valid ELF ROMs
|
||||
- Qt: Include wayland QPA in AppImage (fixes mgba.io/i/2796)
|
||||
|
||||
0.10.1: (2023-01-10)
|
||||
Emulation fixes:
|
||||
|
|
|
@ -34,6 +34,16 @@ CXX_GUARD_START
|
|||
size_t NAME ## Index(const struct NAME* vector, const TYPE* member); \
|
||||
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) \
|
||||
void NAME ## Init(struct NAME* vector, size_t capacity) { \
|
||||
vector->size = 0; \
|
||||
|
@ -50,9 +60,11 @@ CXX_GUARD_START
|
|||
vector->size = 0; \
|
||||
} \
|
||||
TYPE* NAME ## GetPointer(struct NAME* vector, size_t location) { \
|
||||
VECTOR_BOUNDS_CHECK(NAME, vector, location); \
|
||||
return &vector->vector[location]; \
|
||||
} \
|
||||
TYPE const* NAME ## GetConstPointer(const struct NAME* vector, size_t location) { \
|
||||
VECTOR_BOUNDS_CHECK(NAME, vector, location); \
|
||||
return &vector->vector[location]; \
|
||||
} \
|
||||
TYPE* NAME ## Append(struct NAME* vector) { \
|
||||
|
@ -78,10 +90,12 @@ CXX_GUARD_START
|
|||
vector->vector = realloc(vector->vector, vector->capacity * sizeof(TYPE)); \
|
||||
} \
|
||||
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)); \
|
||||
vector->size -= difference; \
|
||||
} \
|
||||
void NAME ## Unshift(struct NAME* vector, size_t location, size_t difference) { \
|
||||
VECTOR_BOUNDS_CHECK(NAME, vector, location); \
|
||||
NAME ## Resize(vector, difference); \
|
||||
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; \
|
||||
} \
|
||||
|
||||
DECLARE_VECTOR(StringList, char*);
|
||||
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
|
||||
|
||||
|
|
|
@ -89,6 +89,7 @@ uint32_t mScriptContextSetWeakref(struct mScriptContext*, struct mScriptValue* v
|
|||
struct mScriptValue* mScriptContextMakeWeakref(struct mScriptContext*, struct mScriptValue* value);
|
||||
struct mScriptValue* mScriptContextAccessWeakref(struct mScriptContext*, struct mScriptValue* value);
|
||||
void mScriptContextClearWeakref(struct mScriptContext*, uint32_t weakref);
|
||||
void mScriptContextDisownWeakref(struct mScriptContext*, uint32_t weakref);
|
||||
|
||||
void mScriptContextAttachStdlib(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_CW(TYPE) opaque
|
||||
|
||||
#define mSCRIPT_TYPE_MS_VOID (&mSTVoid)
|
||||
#define mSCRIPT_TYPE_MS_S8 (&mSTSInt8)
|
||||
#define mSCRIPT_TYPE_MS_U8 (&mSTUInt8)
|
||||
#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_S_METHOD(STRUCT, NAME) (&_mSTStructBindingType_ ## STRUCT ## _ ## NAME)
|
||||
#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_WLIST (&mSTListWrapper)
|
||||
#define mSCRIPT_TYPE_MS_W(TYPE) (&mSTWrapper_ ## TYPE)
|
||||
|
|
|
@ -761,14 +761,16 @@ mSCRIPT_DEFINE_STRUCT_BINDING_DEFAULTS(mScriptConsole, createBuffer)
|
|||
mSCRIPT_DEFINE_DEFAULTS_END;
|
||||
|
||||
static struct mScriptConsole* _ensureConsole(struct mScriptContext* context) {
|
||||
struct mScriptValue* value = mScriptContextEnsureGlobal(context, "console", mSCRIPT_TYPE_MS_S(mScriptConsole));
|
||||
struct mScriptConsole* console = value->value.opaque;
|
||||
if (!console) {
|
||||
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 mScriptValue* value = mScriptContextGetGlobal(context, "console");
|
||||
if (value) {
|
||||
return value->value.opaque;
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -11,8 +11,6 @@
|
|||
|
||||
DEFINE_VECTOR(LexVector, struct Token);
|
||||
|
||||
DEFINE_VECTOR(IntList, int32_t);
|
||||
|
||||
enum LexState {
|
||||
LEX_ERROR = -1,
|
||||
LEX_ROOT = 0,
|
||||
|
|
|
@ -429,7 +429,7 @@ if(QT_STATIC)
|
|||
list(APPEND QT_LIBRARIES "-framework AVFoundation" "-framework CoreMedia" "-framework SystemConfiguration" "-framework Security")
|
||||
set_target_properties(${QT}::Core PROPERTIES INTERFACE_LINK_LIBRARIES "${QTPCRE}")
|
||||
elseif(UNIX)
|
||||
list(APPEND QT_LIBRARIES ${QT}::FontDatabaseSupport ${QT}::XcbQpa)
|
||||
list(APPEND QT_LIBRARIES ${QT}::FontDatabaseSupport ${QT}::XcbQpa ${QT}::QWaylandIntegrationPlugin)
|
||||
endif()
|
||||
endif()
|
||||
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 (m_supportsShaders) {
|
||||
QOpenGLFunctions_Baseline* fn = m_gl->versionFunctions<QOpenGLFunctions_Baseline>();
|
||||
gl2Backend = static_cast<mGLES2Context*>(malloc(sizeof(mGLES2Context)));
|
||||
mGLES2ContextCreate(gl2Backend);
|
||||
m_backend = &gl2Backend->d;
|
||||
QOpenGLFunctions* fn = m_gl->functions();
|
||||
fn->glGenTextures(m_bridgeTexes.size(), m_bridgeTexes.data());
|
||||
for (auto tex : m_bridgeTexes) {
|
||||
m_freeTex.enqueue(tex);
|
||||
|
@ -546,7 +546,7 @@ void PainterGL::create() {
|
|||
#if defined(BUILD_GLES2) || defined(BUILD_GLES3)
|
||||
mGLES2Context* gl2Backend = reinterpret_cast<mGLES2Context*>(painter->m_backend);
|
||||
if (painter->m_widget && painter->supportsShaders()) {
|
||||
QOpenGLFunctions_Baseline* fn = painter->m_gl->versionFunctions<QOpenGLFunctions_Baseline>();
|
||||
QOpenGLFunctions* fn = painter->m_gl->functions();
|
||||
fn->glFinish();
|
||||
painter->m_widget->setTex(painter->m_finalTex[painter->m_finalTexIdx]);
|
||||
painter->m_finalTexIdx ^= 1;
|
||||
|
@ -592,7 +592,7 @@ void PainterGL::destroy() {
|
|||
}
|
||||
makeCurrent();
|
||||
#if defined(BUILD_GLES2) || defined(BUILD_GLES3)
|
||||
QOpenGLFunctions_Baseline* fn = m_gl->versionFunctions<QOpenGLFunctions_Baseline>();
|
||||
QOpenGLFunctions* fn = m_gl->functions();
|
||||
if (m_shader.passes) {
|
||||
mGLES2ShaderFree(&m_shader);
|
||||
}
|
||||
|
@ -683,7 +683,7 @@ void PainterGL::start() {
|
|||
if (glContextHasBug(OpenGLBug::GLTHREAD_BLOCKS_SWAP)) {
|
||||
// Suggested on Discord as a way to strongly hint that glthread should be disabled
|
||||
// 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);
|
||||
}
|
||||
#endif
|
||||
|
@ -975,7 +975,7 @@ QOpenGLContext* PainterGL::shareContext() {
|
|||
}
|
||||
|
||||
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
|
||||
if (glContextHasBug(OpenGLBug::CROSS_THREAD_FLUSH)) {
|
||||
fn->glFinish();
|
||||
|
|
|
@ -199,6 +199,8 @@ Window::Window(CoreManager* manager, ConfigController* config, int playerId, QWi
|
|||
|
||||
#ifdef BUILD_SDL
|
||||
m_inputController.addInputDriver(std::make_shared<SDLInputDriver>(&m_inputController));
|
||||
m_inputController.setGamepadDriver(SDL_BINDING_BUTTON);
|
||||
m_inputController.setSensorDriver(SDL_BINDING_BUTTON);
|
||||
#endif
|
||||
|
||||
m_shortcutController->setConfigController(m_config);
|
||||
|
|
|
@ -16,11 +16,11 @@ GamepadHatEvent::GamepadHatEvent(QEvent::Type pressType, int hatId, Direction di
|
|||
: QEvent(pressType)
|
||||
, m_hatId(hatId)
|
||||
, m_direction(direction)
|
||||
, m_key(-1)
|
||||
, m_keys(0)
|
||||
{
|
||||
ignore();
|
||||
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; }
|
||||
Direction direction() const { return m_direction; }
|
||||
int platformKey() const { return m_key; }
|
||||
int platformKeys() const { return m_keys; }
|
||||
|
||||
static Type Down();
|
||||
static Type Up();
|
||||
|
@ -36,7 +36,7 @@ private:
|
|||
|
||||
int m_hatId;
|
||||
Direction m_direction;
|
||||
int m_key;
|
||||
int m_keys;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -236,7 +236,7 @@ int InputController::gamepadIndex(uint32_t type) const {
|
|||
if (!driver) {
|
||||
return -1;
|
||||
}
|
||||
return driver->activeGamepad();
|
||||
return driver->activeGamepadIndex();
|
||||
}
|
||||
|
||||
void InputController::setGamepad(uint32_t type, int index) {
|
||||
|
@ -357,13 +357,9 @@ Gamepad* InputController::gamepad(uint32_t type) {
|
|||
}
|
||||
if (!driver->supportsGamepads()) {
|
||||
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() {
|
||||
|
@ -372,16 +368,15 @@ QList<Gamepad*> InputController::gamepads() {
|
|||
if (!driver->supportsGamepads()) {
|
||||
continue;
|
||||
}
|
||||
QList<Gamepad*> driverPads(driver->connectedGamepads());
|
||||
int activeGamepad = driver->activeGamepad();
|
||||
if (activeGamepad >= 0 && activeGamepad < driverPads.count()) {
|
||||
pads.append(driverPads[activeGamepad]);
|
||||
Gamepad* pad = driver->activeGamepad();
|
||||
if (pad) {
|
||||
pads.append(pad);
|
||||
}
|
||||
}
|
||||
return pads;
|
||||
}
|
||||
|
||||
QSet<int> InputController::activeGamepadButtons(int type) {
|
||||
QSet<int> InputController::activeGamepadButtons(uint32_t type) {
|
||||
QSet<int> activeButtons;
|
||||
Gamepad* pad = gamepad(type);
|
||||
if (!pad) {
|
||||
|
@ -396,7 +391,7 @@ QSet<int> InputController::activeGamepadButtons(int type) {
|
|||
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;
|
||||
Gamepad* pad = gamepad(type);
|
||||
if (!pad) {
|
||||
|
@ -417,7 +412,7 @@ QSet<QPair<int, GamepadAxisEvent::Direction>> InputController::activeGamepadAxes
|
|||
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;
|
||||
Gamepad* pad = gamepad(type);
|
||||
if (!pad) {
|
||||
|
@ -432,7 +427,7 @@ QSet<QPair<int, GamepadHatEvent::Direction>> InputController::activeGamepadHats(
|
|||
return activeHats;
|
||||
}
|
||||
|
||||
void InputController::testGamepad(int type) {
|
||||
void InputController::testGamepad(uint32_t type) {
|
||||
QWriteLocker l(&m_eventsLock);
|
||||
auto activeAxes = activeGamepadAxes(type);
|
||||
auto oldAxes = m_activeAxes;
|
||||
|
@ -496,15 +491,15 @@ void InputController::testGamepad(int type) {
|
|||
|
||||
for (auto& hat : activeHats) {
|
||||
GamepadHatEvent* event = new GamepadHatEvent(GamepadHatEvent::Down(), hat.first, hat.second, type, this);
|
||||
postPendingEvent(event->platformKey());
|
||||
postPendingEvents(event->platformKeys());
|
||||
sendGamepadEvent(event);
|
||||
if (!event->isAccepted()) {
|
||||
clearPendingEvent(event->platformKey());
|
||||
clearPendingEvents(event->platformKeys());
|
||||
}
|
||||
}
|
||||
for (auto& hat : oldHats) {
|
||||
GamepadHatEvent* event = new GamepadHatEvent(GamepadHatEvent::Up(), hat.first, hat.second, type, this);
|
||||
clearPendingEvent(event->platformKey());
|
||||
clearPendingEvents(event->platformKeys());
|
||||
sendGamepadEvent(event);
|
||||
}
|
||||
}
|
||||
|
@ -530,6 +525,22 @@ void InputController::clearPendingEvent(int 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 {
|
||||
return m_pendingEvents.contains(key);
|
||||
}
|
||||
|
|
|
@ -82,8 +82,8 @@ public:
|
|||
static const int32_t AXIS_THRESHOLD = 0x3000;
|
||||
|
||||
void setGamepadDriver(uint32_t type);
|
||||
const InputDriver* gamepadDriver() const { return m_inputDrivers.value(m_sensorDriver).get(); }
|
||||
InputDriver* gamepadDriver() { 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_gamepadDriver).get(); }
|
||||
|
||||
QStringList connectedGamepads(uint32_t type = 0) const;
|
||||
int gamepadIndex(uint32_t type = 0) const;
|
||||
|
@ -115,7 +115,7 @@ signals:
|
|||
void luminanceValueChanged(int value);
|
||||
|
||||
public slots:
|
||||
void testGamepad(int type);
|
||||
void testGamepad(uint32_t type);
|
||||
void update();
|
||||
|
||||
void increaseLuminanceLevel();
|
||||
|
@ -136,17 +136,19 @@ private slots:
|
|||
void teardownCam();
|
||||
|
||||
private:
|
||||
void postPendingEvent(int);
|
||||
void clearPendingEvent(int);
|
||||
bool hasPendingEvent(int) const;
|
||||
void postPendingEvent(int key);
|
||||
void clearPendingEvent(int key);
|
||||
void postPendingEvents(int keys);
|
||||
void clearPendingEvents(int keys);
|
||||
bool hasPendingEvent(int key) const;
|
||||
void sendGamepadEvent(QEvent*);
|
||||
|
||||
Gamepad* gamepad(uint32_t type);
|
||||
QList<Gamepad*> gamepads();
|
||||
|
||||
QSet<int> activeGamepadButtons(int type);
|
||||
QSet<QPair<int, GamepadAxisEvent::Direction>> activeGamepadAxes(int type);
|
||||
QSet<QPair<int, GamepadHatEvent::Direction>> activeGamepadHats(int type);
|
||||
QSet<int> activeGamepadButtons(uint32_t type);
|
||||
QSet<QPair<int, GamepadAxisEvent::Direction>> activeGamepadAxes(uint32_t type);
|
||||
QSet<QPair<int, GamepadHatEvent::Direction>> activeGamepadHats(uint32_t type);
|
||||
|
||||
struct InputControllerLux : GBALuminanceSource {
|
||||
InputController* p;
|
||||
|
|
|
@ -40,14 +40,32 @@ QList<Gamepad*> InputDriver::connectedGamepads() const {
|
|||
return {};
|
||||
}
|
||||
|
||||
int InputDriver::activeKeySource() const {
|
||||
int InputDriver::activeKeySourceIndex() const {
|
||||
return -1;
|
||||
}
|
||||
|
||||
int InputDriver::activeGamepad() const {
|
||||
int InputDriver::activeGamepadIndex() const {
|
||||
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) {
|
||||
}
|
||||
|
||||
|
|
|
@ -44,8 +44,11 @@ public:
|
|||
virtual QList<KeySource*> connectedKeySources() const;
|
||||
virtual QList<Gamepad*> connectedGamepads() const;
|
||||
|
||||
virtual int activeKeySource() const;
|
||||
virtual int activeGamepad() const;
|
||||
virtual int activeKeySourceIndex() const;
|
||||
virtual int activeGamepadIndex() const;
|
||||
|
||||
KeySource* activeKeySource();
|
||||
Gamepad* activeGamepad();
|
||||
|
||||
virtual void setActiveKeySource(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 platformKeys = 0;
|
||||
for (int i = 0; i < hats.count(); ++i) {
|
||||
int platformKey = mInputMapHat(m_map, m_type, i, hats[i]);
|
||||
if (platformKey >= 0) {
|
||||
platformKeys |= 1 << platformKey;
|
||||
}
|
||||
platformKeys |= mInputMapHat(m_map, m_type, i, hats[i]);
|
||||
}
|
||||
return platformKeys;
|
||||
}
|
||||
|
|
|
@ -173,7 +173,7 @@ void SDLInputDriver::updateGamepads() {
|
|||
}
|
||||
#endif
|
||||
|
||||
int SDLInputDriver::activeGamepad() const {
|
||||
int SDLInputDriver::activeGamepadIndex() const {
|
||||
return m_sdlPlayer.joystick ? m_sdlPlayer.joystick->index : 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -46,7 +46,7 @@ public:
|
|||
|
||||
QList<Gamepad*> connectedGamepads() const override;
|
||||
|
||||
int activeGamepad() const override;
|
||||
int activeGamepadIndex() const override;
|
||||
void setActiveGamepad(int) override;
|
||||
|
||||
void registerTiltAxisX(int axis) override;
|
||||
|
|
|
@ -42,6 +42,7 @@ Q_IMPORT_PLUGIN(AVFServicePlugin);
|
|||
#endif
|
||||
#elif defined(Q_OS_UNIX)
|
||||
Q_IMPORT_PLUGIN(QXcbIntegrationPlugin);
|
||||
Q_IMPORT_PLUGIN(QWaylandIntegrationPlugin);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
|
|
@ -12,8 +12,9 @@ set(TEST_FILES
|
|||
if(USE_LUA)
|
||||
list(APPEND SOURCE_FILES engines/lua.c)
|
||||
list(APPEND TEST_FILES
|
||||
test/stdlib.c
|
||||
test/lua.c)
|
||||
test/context.c
|
||||
test/lua.c
|
||||
test/stdlib.c)
|
||||
endif()
|
||||
|
||||
source_group("Scripting" FILES ${SOURCE_FILES})
|
||||
|
|
|
@ -71,8 +71,8 @@ void mScriptContextInit(struct mScriptContext* context) {
|
|||
|
||||
void mScriptContextDeinit(struct mScriptContext* context) {
|
||||
HashTableDeinit(&context->rootScope);
|
||||
HashTableDeinit(&context->weakrefs);
|
||||
mScriptContextDrainPool(context);
|
||||
HashTableDeinit(&context->weakrefs);
|
||||
mScriptListDeinit(&context->refPool);
|
||||
HashTableDeinit(&context->callbacks);
|
||||
TableDeinit(&context->callbackId);
|
||||
|
@ -102,9 +102,12 @@ void mScriptContextFillPool(struct mScriptContext* context, struct mScriptValue*
|
|||
void mScriptContextDrainPool(struct mScriptContext* context) {
|
||||
size_t i;
|
||||
for (i = 0; i < mScriptListSize(&context->refPool); ++i) {
|
||||
struct mScriptValue* value = mScriptValueUnwrap(mScriptListGetPointer(&context->refPool, i));
|
||||
if (value) {
|
||||
struct mScriptValue* value = mScriptListGetPointer(&context->refPool, i);
|
||||
if (value->type->base == mSCRIPT_TYPE_WRAPPER) {
|
||||
value = mScriptValueUnwrap(value);
|
||||
mScriptValueDeref(value);
|
||||
} else if (value->type == mSCRIPT_TYPE_MS_WEAKREF) {
|
||||
mScriptContextClearWeakref(context, value->value.u32);
|
||||
}
|
||||
}
|
||||
mScriptListClear(&context->refPool);
|
||||
|
@ -201,6 +204,13 @@ void mScriptContextClearWeakref(struct mScriptContext* context, uint32_t 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) {
|
||||
struct mScriptValue* list = HashTableLookup(&context->callbacks, callback);
|
||||
if (!list) {
|
||||
|
|
|
@ -738,7 +738,19 @@ bool _luaWrap(struct mScriptEngineContextLua* luaContext, struct mScriptValue* v
|
|||
}
|
||||
break;
|
||||
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;
|
||||
case mSCRIPT_TYPE_LIST:
|
||||
newValue = lua_newuserdata(luaContext->lua, sizeof(*newValue));
|
||||
|
@ -769,6 +781,10 @@ bool _luaWrap(struct mScriptEngineContextLua* luaContext, struct mScriptValue* v
|
|||
mScriptValueDeref(value);
|
||||
break;
|
||||
case mSCRIPT_TYPE_OBJECT:
|
||||
if (!value->value.opaque) {
|
||||
lua_pushnil(luaContext->lua);
|
||||
break;
|
||||
}
|
||||
newValue = lua_newuserdata(luaContext->lua, sizeof(*newValue));
|
||||
if (needsWeakref) {
|
||||
*newValue = mSCRIPT_MAKE(WEAKREF, weakref);
|
||||
|
|
|
@ -14,6 +14,8 @@ struct TestA {
|
|||
int32_t i2;
|
||||
int8_t b8;
|
||||
int16_t hUnaligned;
|
||||
struct mScriptValue table;
|
||||
struct mScriptList list;
|
||||
int32_t (*ifn0)(struct TestA*);
|
||||
int32_t (*ifn1)(struct TestA*, int);
|
||||
void (*vfn0)(struct TestA*);
|
||||
|
@ -103,6 +105,8 @@ mSCRIPT_DEFINE_STRUCT(TestA)
|
|||
mSCRIPT_DEFINE_STRUCT_MEMBER(TestA, S32, i2)
|
||||
mSCRIPT_DEFINE_STRUCT_MEMBER(TestA, S8, b8)
|
||||
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, ifn1)
|
||||
mSCRIPT_DEFINE_STRUCT_METHOD(TestA, icfn0)
|
||||
|
@ -187,6 +191,20 @@ M_TEST_DEFINE(testALayout) {
|
|||
assert_ptr_equal(member->type, mSCRIPT_TYPE_MS_S16);
|
||||
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");
|
||||
assert_null(member);
|
||||
|
||||
|
@ -280,6 +298,12 @@ M_TEST_DEFINE(testAGet) {
|
|||
.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 val;
|
||||
struct mScriptValue compare;
|
||||
|
@ -300,8 +324,34 @@ M_TEST_DEFINE(testAGet) {
|
|||
assert_true(mScriptObjectGet(&sval, "hUnaligned", &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));
|
||||
|
||||
mScriptListDeinit(&s.list);
|
||||
mSCRIPT_TYPE_MS_TABLE->free(&s.table);
|
||||
|
||||
assert_true(cls->init);
|
||||
mScriptClassDeinit(cls);
|
||||
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);
|
||||
}
|
||||
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) {
|
||||
SETUP_LUA;
|
||||
|
@ -709,6 +736,7 @@ M_TEST_SUITE_DEFINE_SETUP_TEARDOWN(mScriptLua,
|
|||
cmocka_unit_test(rootScope),
|
||||
cmocka_unit_test(callLuaFunc),
|
||||
cmocka_unit_test(callCFunc),
|
||||
cmocka_unit_test(globalNull),
|
||||
cmocka_unit_test(globalStructFieldGet),
|
||||
cmocka_unit_test(globalStructFieldSet),
|
||||
cmocka_unit_test(globalStructMethods),
|
||||
|
|
|
@ -76,6 +76,14 @@ static int isSequential(struct mScriptList* list) {
|
|||
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_VOID_FUNCTION(boundDiscard, discard, 1, S32, ignored);
|
||||
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(boundIsHello, S32, isHello, 1, CHARP, str);
|
||||
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) {
|
||||
struct mScriptFrame frame;
|
||||
|
@ -1261,6 +1271,43 @@ M_TEST_DEFINE(invokeList) {
|
|||
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,
|
||||
cmocka_unit_test(voidArgs),
|
||||
cmocka_unit_test(voidFunc),
|
||||
|
@ -1295,4 +1342,6 @@ M_TEST_SUITE_DEFINE(mScript,
|
|||
cmocka_unit_test(stringIsHello),
|
||||
cmocka_unit_test(stringIsNotHello),
|
||||
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->value.table = raw;
|
||||
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:
|
||||
val->refs = mSCRIPT_VALUE_UNREF;
|
||||
val->flags = 0;
|
||||
|
|
|
@ -8,6 +8,7 @@ set(BASE_SOURCE_FILES
|
|||
hash.c
|
||||
string.c
|
||||
table.c
|
||||
vector.c
|
||||
vfs.c)
|
||||
|
||||
set(SOURCE_FILES
|
||||
|
|
|
@ -5,12 +5,8 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
#include <mgba-util/string.h>
|
||||
|
||||
#include <mgba-util/vector.h>
|
||||
|
||||
#include <string.h>
|
||||
|
||||
DEFINE_VECTOR(StringList, char*);
|
||||
|
||||
#ifndef HAVE_STRNDUP
|
||||
char* strndup(const char* start, size_t len) {
|
||||
// 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