mkxp-z/src/eventthread.h
刘皓 81b94d1498
Remove dependency on SDL headers in libretro builds
I'd already removed the SDL static libraries from libretro builds for
portability, but kept the headers to make it easier to port the codebase
to libretro. Eventually it was time to stop using the SDL headers as a
crutch.
2025-03-29 12:37:07 -04:00

322 lines
6.2 KiB
C++

/*
** eventthread.h
**
** This file is part of mkxp.
**
** Copyright (C) 2013 - 2021 Amaryllis Kulla <ancurio@mapleshrine.eu>
**
** mkxp is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 2 of the License, or
** (at your option) any later version.
**
** mkxp is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with mkxp. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef EVENTTHREAD_H
#define EVENTTHREAD_H
#ifndef MKXPZ_RETRO
# include <SDL_scancode.h>
# include <SDL_mouse.h>
# include <SDL_mutex.h>
# include <SDL_atomic.h>
# include <SDL_gamecontroller.h>
#endif // MKXPZ_RETRO
#include <string>
#include <stdint.h>
#include "config.h"
#include "etc-internal.h"
#include "sdl-util.h"
#ifndef MKXPZ_RETRO
# include "keybindings.h"
#endif // MKXPZ_RETRO
#ifdef MKXPZ_RETRO
# include <alc.h>
#else
typedef struct MKXPZ_ALCDEVICE ALCdevice;
#endif // MKXPZ_RETRO
struct SDL_Window;
union SDL_Event;
#define MAX_FINGERS 4
class EventThread
{
#ifndef MKXPZ_RETRO
public:
struct ControllerState {
int axes[SDL_CONTROLLER_AXIS_MAX];
bool buttons[SDL_CONTROLLER_BUTTON_MAX];
};
struct MouseState
{
int x, y;
bool inWindow;
bool buttons[32];
};
struct FingerState
{
bool down;
int x, y;
};
struct TouchState
{
FingerState fingers[MAX_FINGERS];
};
static uint8_t keyStates[SDL_NUM_SCANCODES];
static ControllerState controllerState;
static MouseState mouseState;
static TouchState touchState;
static SDL_atomic_t verticalScrollDistance;
std::string textInputBuffer;
void lockText(bool lock);
static bool allocUserEvents();
EventThread();
~EventThread();
void process(RGSSThreadData &rtData);
void cleanup();
/* Called from RGSS thread */
void requestFullscreenMode(bool mode);
void requestWindowResize(int width, int height);
void requestWindowReposition(int x, int y);
void requestWindowCenter();
void requestWindowRename(const char *title);
void requestShowCursor(bool mode);
void requestTextInputMode(bool mode);
void requestSettingsMenu();
void requestTerminate();
bool getFullscreen() const;
bool getShowCursor() const;
bool getControllerConnected() const;
SDL_GameController *controller() const;
void showMessageBox(const char *body, int flags = 0);
/* RGSS thread calls this once per frame */
void notifyFrame();
/* Called on game screen (size / offset) changes */
void notifyGameScreenChange(const SDL_Rect &screen);
private:
static int eventFilter(void *, SDL_Event*);
void resetInputStates();
void setFullscreen(SDL_Window *, bool mode);
void updateCursorState(bool inWindow,
const SDL_Rect &screen);
void cursorTimer();
bool fullscreen;
bool showCursor;
SDL_GameController *ctrl;
AtomicFlag msgBoxDone;
SDL_mutex *textInputLock;
struct
{
AtomicFlag sendUpdates;
} fps;
#endif // MKXPZ_RETRO
};
#ifndef MKXPZ_RETRO
/* Used to asynchronously inform the RGSS thread
* about certain value changes */
template<typename T>
struct UnidirMessage
{
#ifndef MKXPZ_RETRO
UnidirMessage()
: mutex(SDL_CreateMutex()),
current(T())
{}
~UnidirMessage()
{
SDL_DestroyMutex(mutex);
}
/* Done from the sending side */
void post(const T &value)
{
SDL_LockMutex(mutex);
changed.set();
current = value;
SDL_UnlockMutex(mutex);
}
/* Done from the receiving side */
bool poll(T &out) const
{
if (!changed)
return false;
SDL_LockMutex(mutex);
out = current;
changed.clear();
SDL_UnlockMutex(mutex);
return true;
}
/* Done from either */
void get(T &out) const
{
SDL_LockMutex(mutex);
out = current;
SDL_UnlockMutex(mutex);
}
private:
SDL_mutex *mutex;
mutable AtomicFlag changed;
T current;
#endif // MKXPZ_RETRO
};
struct SyncPoint
{
/* Used by eventFilter to control sleep/wakeup */
void haltThreads();
void resumeThreads();
/* Used by RGSS thread */
bool mainSyncLocked();
void waitMainSync();
/* Used by secondary (audio) threads */
void passSecondarySync();
private:
struct Util
{
Util();
~Util();
void lock();
void unlock(bool multi);
void waitForUnlock();
AtomicFlag locked;
SDL_mutex *mut;
SDL_cond *cond;
};
Util mainSync;
Util reply;
Util secondSync;
};
#endif // MKXPZ_RETRO
struct RGSSThreadData
{
/* Main thread sets this to request RGSS thread to terminate */
AtomicFlag rqTerm;
/* In response, RGSS thread sets this to confirm
* that it received the request and isn't stuck */
AtomicFlag rqTermAck;
/* Set when F12 is pressed */
AtomicFlag rqReset;
/* Set when F12 is released */
AtomicFlag rqResetFinish;
// Set when window is being adjusted (resize, reposition)
AtomicFlag rqWindowAdjust;
EventThread *ethread;
#ifndef MKXPZ_RETRO
UnidirMessage<Vec2i> windowSizeMsg;
UnidirMessage<Vec2i> drawableSizeMsg;
UnidirMessage<BDescVec> bindingUpdateMsg;
SyncPoint syncPoint;
#endif // MKXPZ_RETRO
const char *argv0;
SDL_Window *window;
ALCdevice *alcDev;
#ifndef MKXPZ_RETRO
SDL_GLContext glContext;
#endif // MKXPZ_RETRO
Vec2 sizeResoRatio;
Vec2i screenOffset;
int scale;
const int refreshRate;
Config config;
std::string rgssErrorMsg;
RGSSThreadData(EventThread *ethread,
const char *argv0,
SDL_Window *window,
ALCdevice *alcDev,
int refreshRate,
int scalingFactor,
#ifdef MKXPZ_RETRO
const Config& newconf
#else
const Config& newconf,
SDL_GLContext ctx
#endif // MKXPZ_RETRO
)
: ethread(ethread),
argv0(argv0),
window(window),
alcDev(alcDev),
sizeResoRatio(1, 1),
refreshRate(refreshRate),
scale(scalingFactor),
#ifdef MKXPZ_RETRO
config(newconf)
#else
config(newconf),
glContext(ctx)
#endif // MKXPZ_RETRO
{
rqResetFinish.set();
}
};
#endif // EVENTTHREAD_H