diff --git a/assets/icon.ico b/assets/icon.ico new file mode 100644 index 0000000..2a10780 Binary files /dev/null and b/assets/icon.ico differ diff --git a/assets/resource.h b/assets/resource.h new file mode 100644 index 0000000..32015bd --- /dev/null +++ b/assets/resource.h @@ -0,0 +1 @@ +#define IDI_APPICON 101 diff --git a/assets/resource.rc b/assets/resource.rc new file mode 100644 index 0000000..293e38d --- /dev/null +++ b/assets/resource.rc @@ -0,0 +1,4 @@ +#include +#include "resource.h" + +IDI_APPICON ICON "icon.ico" diff --git a/binding-mri/binding-mri.cpp b/binding-mri/binding-mri.cpp index 7d9865a..57e6db1 100644 --- a/binding-mri/binding-mri.cpp +++ b/binding-mri/binding-mri.cpp @@ -82,6 +82,7 @@ RB_METHOD(mriP); RB_METHOD(mkxpDataDirectory); RB_METHOD(mkxpPuts); RB_METHOD(mkxpRawKeyStates); +RB_METHOD(mkxpMouseInWindow); RB_METHOD(mriRgssMain); RB_METHOD(mriRgssStop); @@ -146,6 +147,7 @@ static void mriBindingInit() _rb_define_module_function(mod, "data_directory", mkxpDataDirectory); _rb_define_module_function(mod, "puts", mkxpPuts); _rb_define_module_function(mod, "raw_key_states", mkxpRawKeyStates); + _rb_define_module_function(mod, "mouse_in_window", mkxpMouseInWindow); rb_gv_set("MKXP", Qtrue); } @@ -237,6 +239,13 @@ RB_METHOD(mkxpRawKeyStates) return str; } +RB_METHOD(mkxpMouseInWindow) +{ + RB_UNUSED_PARAM; + + return rb_bool_new(EventThread::mouseState.inWindow); +} + static VALUE rgssMainCb(VALUE block) { rb_funcall2(block, rb_intern("call"), 0, 0); @@ -483,8 +492,9 @@ static void runRMXPScripts(BacktraceData &btData) } /* Execute preloaded scripts */ - for (size_t i = 0; i < conf.preloadScripts.size(); ++i) - runCustomScript(conf.preloadScripts[i]); + for (std::set::iterator i = conf.preloadScripts.begin(); + i != conf.preloadScripts.end(); ++i) + runCustomScript(*i); VALUE exc = rb_gv_get("$!"); if (exc != Qnil) diff --git a/src/config.cpp b/src/config.cpp index 248c2c2..c5e0867 100644 --- a/src/config.cpp +++ b/src/config.cpp @@ -134,6 +134,12 @@ static std::string prefPath(const char *org, const char *app) return str; } +template +std::set setFromVec(const std::vector &vec) +{ + return std::set(vec.begin(), vec.end()); +} + typedef std::vector StringVec; namespace po = boost::program_options; @@ -226,7 +232,7 @@ void Config::read(int argc, char *argv[]) PO_DESC_ALL; - GUARD_ALL( preloadScripts = vm["preloadScript"].as(); ); + GUARD_ALL( preloadScripts = setFromVec(vm["preloadScript"].as()); ); GUARD_ALL( rtps = vm["RTP"].as(); ); diff --git a/src/config.h b/src/config.h index 9e43faf..57a9e33 100644 --- a/src/config.h +++ b/src/config.h @@ -24,6 +24,7 @@ #include #include +#include struct CropTexture { @@ -83,7 +84,7 @@ struct Config bool useScriptNames; std::string customScript; - std::vector preloadScripts; + std::set preloadScripts; std::vector rtps; std::vector fontSubs; diff --git a/src/eventthread.cpp b/src/eventthread.cpp index 00c1b3e..42dab49 100644 --- a/src/eventthread.cpp +++ b/src/eventthread.cpp @@ -83,6 +83,7 @@ enum REQUEST_SETCURSORVISIBLE, UPDATE_FPS, + UPDATE_SCREEN_RECT, EVENT_COUNT }; @@ -131,6 +132,8 @@ void EventThread::process(RGSSThreadData &rtData) bool displayingFPS = false; bool cursorInWindow = false; + /* Will be updated eventually */ + SDL_Rect gameScreen = { 0, 0, 0, 0 }; /* SDL doesn't send an initial FOCUS_GAINED event */ bool windowFocused = true; @@ -170,7 +173,7 @@ void EventThread::process(RGSSThreadData &rtData) delete sMenu; sMenu = 0; - updateCursorState(cursorInWindow && windowFocused); + updateCursorState(cursorInWindow && windowFocused, gameScreen); } continue; @@ -211,14 +214,14 @@ void EventThread::process(RGSSThreadData &rtData) case SDL_WINDOWEVENT_ENTER : cursorInWindow = true; mouseState.inWindow = true; - updateCursorState(cursorInWindow && windowFocused && !sMenu); + updateCursorState(cursorInWindow && windowFocused && !sMenu, gameScreen); break; case SDL_WINDOWEVENT_LEAVE : cursorInWindow = false; mouseState.inWindow = false; - updateCursorState(cursorInWindow && windowFocused && !sMenu); + updateCursorState(cursorInWindow && windowFocused && !sMenu, gameScreen); break; @@ -229,13 +232,13 @@ void EventThread::process(RGSSThreadData &rtData) case SDL_WINDOWEVENT_FOCUS_GAINED : windowFocused = true; - updateCursorState(cursorInWindow && windowFocused && !sMenu); + updateCursorState(cursorInWindow && windowFocused && !sMenu, gameScreen); break; case SDL_WINDOWEVENT_FOCUS_LOST : windowFocused = false; - updateCursorState(cursorInWindow && windowFocused && !sMenu); + updateCursorState(cursorInWindow && windowFocused && !sMenu, gameScreen); resetInputStates(); break; @@ -268,7 +271,7 @@ void EventThread::process(RGSSThreadData &rtData) if (!sMenu) { sMenu = new SettingsMenu(rtData); - updateCursorState(false); + updateCursorState(false, gameScreen); } sMenu->raise(); @@ -374,6 +377,7 @@ void EventThread::process(RGSSThreadData &rtData) case SDL_MOUSEMOTION : mouseState.x = event.motion.x; mouseState.y = event.motion.y; + updateCursorState(cursorInWindow, gameScreen); break; case SDL_FINGERDOWN : @@ -413,7 +417,7 @@ void EventThread::process(RGSSThreadData &rtData) case REQUEST_SETCURSORVISIBLE : showCursor = event.user.code; - updateCursorState(cursorInWindow); + updateCursorState(cursorInWindow, gameScreen); break; case UPDATE_FPS : @@ -438,6 +442,15 @@ void EventThread::process(RGSSThreadData &rtData) SDL_SetWindowTitle(win, buffer); break; + + case UPDATE_SCREEN_RECT : + gameScreen.x = event.user.windowID; + gameScreen.y = event.user.code; + gameScreen.w = reinterpret_cast(event.user.data1); + gameScreen.h = reinterpret_cast(event.user.data2); + updateCursorState(cursorInWindow, gameScreen); + + break; } } @@ -532,9 +545,13 @@ void EventThread::setFullscreen(SDL_Window *win, bool mode) fullscreen = mode; } -void EventThread::updateCursorState(bool inWindow) +void EventThread::updateCursorState(bool inWindow, + const SDL_Rect &screen) { - if (inWindow) + SDL_Point pos = { mouseState.x, mouseState.y }; + bool inScreen = inWindow && SDL_PointInRect(&pos, &screen); + + if (inScreen) SDL_ShowCursor(showCursor ? SDL_TRUE : SDL_FALSE); else SDL_ShowCursor(SDL_TRUE); @@ -640,6 +657,19 @@ void EventThread::notifyFrame() SDL_PushEvent(&event); } +void EventThread::notifyGameScreenChange(const SDL_Rect &screen) +{ + /* We have to get a bit hacky here to fit the rectangle + * data into the user event struct */ + SDL_Event event; + event.type = usrIdStart + UPDATE_SCREEN_RECT; + event.user.windowID = screen.x; + event.user.code = screen.y; + event.user.data1 = reinterpret_cast(screen.w); + event.user.data2 = reinterpret_cast(screen.h); + SDL_PushEvent(&event); +} + void SyncPoint::haltThreads() { if (mainSync.locked) diff --git a/src/eventthread.h b/src/eventthread.h index 46051f1..02a9ea1 100644 --- a/src/eventthread.h +++ b/src/eventthread.h @@ -98,12 +98,16 @@ public: /* 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); + void updateCursorState(bool inWindow, + const SDL_Rect &screen); bool fullscreen; bool showCursor; diff --git a/src/filesystem.cpp b/src/filesystem.cpp index fe5d403..d7fd36b 100644 --- a/src/filesystem.cpp +++ b/src/filesystem.cpp @@ -458,7 +458,7 @@ struct FontSetsCBData SharedFontState *sfs; }; -static void fontSetEnumCB(void *data, const char *, +static void fontSetEnumCB(void *data, const char *dir, const char *fname) { FontSetsCBData *d = static_cast(data); @@ -480,7 +480,7 @@ static void fontSetEnumCB(void *data, const char *, return; char filename[512]; - snprintf(filename, sizeof(filename), "Fonts/%s", fname); + snprintf(filename, sizeof(filename), "%s/%s", dir, fname); PHYSFS_File *handle = PHYSFS_openRead(filename); @@ -495,11 +495,29 @@ static void fontSetEnumCB(void *data, const char *, SDL_RWclose(&ops); } +/* Basically just a case-insensitive search + * for the folder "Fonts"... */ +static void findFontsFolderCB(void *data, const char *, + const char *fname) +{ + size_t i = 0; + char buffer[512]; + const char *s = fname; + + while (s && i < sizeof(buffer)) + buffer[i++] = tolower(*s++); + + buffer[i] = '\0'; + + if (strcmp(buffer, "fonts") == 0) + PHYSFS_enumerateFilesCallback(fname, fontSetEnumCB, data); +} + void FileSystem::initFontSets(SharedFontState &sfs) { FontSetsCBData d = { p, &sfs }; - PHYSFS_enumerateFilesCallback("Fonts", fontSetEnumCB, &d); + PHYSFS_enumerateFilesCallback(".", findFontsFolderCB, &d); } struct OpenReadEnumData diff --git a/src/graphics.cpp b/src/graphics.cpp index 7836c1b..0a73ba0 100644 --- a/src/graphics.cpp +++ b/src/graphics.cpp @@ -566,6 +566,9 @@ struct GraphicsPrivate glState.viewport.refresh(); recalculateScreenSize(threadData); updateScreenResoRatio(threadData); + + SDL_Rect screen = { scOffset.x, scOffset.y, scSize.x, scSize.y }; + threadData->ethread->notifyGameScreenChange(screen); } } diff --git a/src/input.cpp b/src/input.cpp index 32bb8cb..4afa04f 100644 --- a/src/input.cpp +++ b/src/input.cpp @@ -671,9 +671,6 @@ int Input::mouseX() { RGSSThreadData &rtData = shState->rtData(); - if (!EventThread::mouseState.inWindow) - return -20; - return (EventThread::mouseState.x - rtData.screenOffset.x) * rtData.sizeResoRatio.x; } @@ -681,9 +678,6 @@ int Input::mouseY() { RGSSThreadData &rtData = shState->rtData(); - if (!EventThread::mouseState.inWindow) - return -20; - return (EventThread::mouseState.y - rtData.screenOffset.y) * rtData.sizeResoRatio.y; } diff --git a/src/main.cpp b/src/main.cpp index 5d654e9..401aa33 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -40,7 +40,11 @@ #include "binding.h" +#ifdef __WINDOWS__ +#include "resource.h" +#elif __LINUX__ #include "icon.png.xxd" +#endif static void rgssThreadError(RGSSThreadData *rtData, const std::string &msg) @@ -166,6 +170,24 @@ static void showInitError(const std::string &msg) SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "mkxp", msg.c_str(), 0); } +static void setupWindowIcon(const Config &conf, SDL_Window *win) +{ + SDL_RWops *iconSrc; + + if (conf.iconPath.empty()) + iconSrc = SDL_RWFromConstMem(assets_icon_png, assets_icon_png_len); + else + iconSrc = SDL_RWFromFile(conf.iconPath.c_str(), "rb"); + + SDL_Surface *iconImg = IMG_Load_RW(iconSrc, SDL_TRUE); + + if (iconImg) + { + SDL_SetWindowIcon(win, iconImg); + SDL_FreeSurface(iconImg); + } +} + int main(int argc, char *argv[]) { SDL_SetHint(SDL_HINT_VIDEO_MINIMIZE_ON_FOCUS_LOSS, "0"); @@ -239,16 +261,6 @@ int main(int argc, char *argv[]) return 0; } - /* Setup application icon */ - SDL_RWops *iconSrc; - - if (conf.iconPath.empty()) - iconSrc = SDL_RWFromConstMem(assets_icon_png, assets_icon_png_len); - else - iconSrc = SDL_RWFromFile(conf.iconPath.c_str(), "rb"); - - SDL_Surface *iconImg = IMG_Load_RW(iconSrc, SDL_TRUE); - SDL_Window *win; Uint32 winFlags = SDL_WINDOW_OPENGL | SDL_WINDOW_INPUT_FOCUS; @@ -267,11 +279,13 @@ int main(int argc, char *argv[]) return 0; } - if (iconImg) - { - SDL_SetWindowIcon(win, iconImg); - SDL_FreeSurface(iconImg); - } + /* OSX and Windows have their own native ways of + * dealing with icons; don't interfere with them */ +#ifdef __LINUX__ + setupWindowIcon(conf, win); +#else + (void) setupWindowIcon; +#endif ALCdevice *alcDev = alcOpenDevice(0);