From 5b3c1d2b13764abedb4b903ef55cdbc16230826e Mon Sep 17 00:00:00 2001 From: Ghabry Date: Sun, 29 Apr 2018 19:18:36 +0200 Subject: [PATCH] WIP: Emscripten support --- CMakeLists.txt | 39 +++++++++++++++----- binding-mri/binding-mri.cpp | 14 +++++++- binding-mri/input-binding.cpp | 2 ++ src/boost-hash.h | 11 +++--- src/config.cpp | 25 ++++++++----- src/config.h | 54 ++++++++++++++-------------- src/eventthread.cpp | 67 +++++++++++++---------------------- src/eventthread.h | 31 +++++++++++++++- src/filesystem.cpp | 2 +- src/fluid-fun.cpp | 6 +++- src/graphics.cpp | 9 ++++- src/main.cpp | 11 +++--- 12 files changed, 168 insertions(+), 103 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index d875826..0e9ebb1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,4 +1,5 @@ cmake_minimum_required(VERSION 2.8.11) +set(CMAKE_CXX_STANDARD 14) Project(mkxp) ## Setup options ## @@ -14,7 +15,7 @@ set(EXTERNAL_LIB_PATH "" CACHE PATH "External precompiled lib prefix") include(cmake/PrepUtils.cmake) set(CMAKE_INCLUDE_CURRENT_DIR ON) - +set(CMAKE_EXECUTABLE_SUFFIX ".html") IF("${CMAKE_SYSTEM}" MATCHES "Linux") SET(LINUX ON) ENDIF() @@ -53,6 +54,16 @@ elseif(APPLE) set(LIB_PATH "lib") endif() +set(EMTERPRETER_OPT "-O0 -s ASSERTIONS=0 -s TOTAL_MEMORY=67108864 -s ABORTING_MALLOC=0 -s EMTERPRETIFY=1 -s EMTERPRETIFY_ASYNC=1 -s NO_EXIT_RUNTIME=1 --embed-file \"game\"") +set(EMTERPRETER_OPT "${EMTERPRETER_OPT} -s EMTERPRETIFY_WHITELIST=\"['__ZN8Graphics10transitionEiPKci','__ZL18graphicsTransitioniPmm','_call_cfunc','_rb_call0','_rb_call','_rb_eval','_rb_eval_string','_eval_node','_eval','_rb_f_eval','_rb_funcall2','_rb_protect','_rb_yield_0','_loop_i','_rb_rescue2','_rb_f_loop','__ZL10evalHelperP7evalArg','__ZL10evalStringmmPi','__ZL14runRMXPScriptsR13BacktraceData','__Z13rgssThreadFunPv','_main','__ZL11inputUpdateiPmm','__ZN11EventThread7processER14RGSSThreadData','__ZL17mriBindingExecutev','__ZL14mriBindingInitv','_module_setup']\"") + +message(STATUS ${EMTERPRETER_OPT}) + +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${EMTERPRETER_OPT}") +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${EMTERPRETER_OPT}") + +message(STATUS ${CMAKE_C_FLAGS}) + set(CMAKE_SKIP_BUILD_RPATH TRUE) set(CMAKE_BUILD_WITH_INSTALL_RPATH TRUE) set(CMAKE_INSTALL_RPATH ${BIN_RPATH}) @@ -64,12 +75,12 @@ find_package(PkgConfig REQUIRED) if (EXTERNAL_LIB_PATH) set(CMAKE_PREFIX_PATH ${EXTERNAL_LIB_PATH}) - + if(EXISTS "${EXTERNAL_LIB_PATH}/${LIB_PATH}/pkgconfig/") SET(ENV{PKG_CONFIG_PATH} "${EXTERNAL_LIB_PATH}/${LIB_PATH}/pkgconfig/") endif() if(APPLE) - set(PLATFORM_SHARED_LIBS + set(PLATFORM_SHARED_LIBS libSDL2.dylib libSDL2_image-2.0.0.dylib libSDL2_ttf-2.0.0.dylib libSDL_sound-1.0.1.dylib libfreetype.6.dylib libsigc-2.0.0.dylib CACHE STRING "List of shared libraries that need to be copied into the OS X bundle") @@ -92,9 +103,10 @@ pkg_check_modules(SDL2_TTF REQUIRED SDL2_ttf) pkg_check_modules(SDL2_IMAGE REQUIRED SDL2_image) pkg_check_modules(SDL_SOUND REQUIRED SDL_sound) -find_package(Boost 1.49 COMPONENTS program_options REQUIRED) +#find_package(Boost 1.49 COMPONENTS program_options REQUIRED) find_package(OpenAL REQUIRED) -find_package(ZLIB REQUIRED) +pkg_check_modules(ZLIB REQUIRED zlib) +#find_package(ZLIB REQUIRED) ## Setup main source ## @@ -388,7 +400,7 @@ link_directories( ${PIXMAN_LIBRARY_DIRS} ${PHYSFS_LIBRARY_DIRS} ${SDL2_LIBRARY_DIRS} # Blindly assume other SDL bits are in same directory - ${Boost_LIBRARY_DIR} +# ${Boost_LIBRARY_DIR} ${MRI_LIBDIR} ) @@ -409,11 +421,13 @@ target_include_directories(${PROJECT_NAME} PRIVATE ${PIXMAN_INCLUDE_DIRS} ${PHYSFS_INCLUDE_DIRS} ${SDL2_INCLUDE_DIRS} # Blindly assume other SDL bits are in same directory - ${Boost_INCLUDE_DIR} +# ${Boost_INCLUDE_DIR} ${MRI_INCLUDE_DIRS} ${VORBISFILE_INCLUDE_DIRS} ${FLUID_INCLUDE_DIRS} ${OPENAL_INCLUDE_DIR} + ${SDL_SOUND_INCLUDE_DIRS} + ${FREETYPE_INCLUDE_DIRS} ) target_link_libraries(${PROJECT_NAME} @@ -424,14 +438,21 @@ target_link_libraries(${PROJECT_NAME} ${SDL_SOUND_LIBRARIES} ${PHYSFS_LIBRARIES} ${PIXMAN_LIBRARIES} - ${Boost_LIBRARIES} +# ${Boost_LIBRARIES} ${MRI_LIBRARIES} ${VORBISFILE_LIBRARIES} ${FLUID_LIBRARIES} ${OPENAL_LIBRARY} ${ZLIB_LIBRARY} - ${PLATFORM_LIBRARIES} + "libruby-static.a" + "libfreetype.a" + "libz.a" + "libpng.a" + "libogg.a" + "libvorbis.a" + "libvorbisfile.a" + "libjpeg.a" ) PostBuildMacBundle(${PROJECT_NAME} "" "${PLATFORM_COPY_LIBS}") diff --git a/binding-mri/binding-mri.cpp b/binding-mri/binding-mri.cpp index 168e52e..2054900 100644 --- a/binding-mri/binding-mri.cpp +++ b/binding-mri/binding-mri.cpp @@ -155,7 +155,9 @@ static void mriBindingInit() static void showMsg(const std::string &msg) { - shState->eThread().showMessageBox(msg.c_str()); + printf("Show msg %s\n", msg.c_str()); + return; +// shState->eThread().showMessageBox(msg.c_str()); } static void printP(int argc, VALUE *argv, @@ -341,6 +343,9 @@ static VALUE evalHelper(evalArg *arg) return rb_funcall2(Qnil, rb_intern("eval"), ARRAY_SIZE(argv), argv); } +#ifdef __EMSCRIPTEN__ +#include +#endif static VALUE evalString(VALUE string, VALUE filename, int *state) { evalArg arg = { string, filename }; @@ -473,6 +478,10 @@ static void runRMXPScripts(BacktraceData &btData) while (true) { +#ifdef __EMSCRIPTEN + emscripten_sleep(10); +#endif + for (long i = 0; i < scriptCount; ++i) { VALUE script = rb_ary_entry(scriptArray, i); @@ -499,6 +508,9 @@ static void runRMXPScripts(BacktraceData &btData) break; } + printf("tick\n"); + shState->eThread().process(shState->rtData()); + VALUE exc = rb_gv_get("$!"); if (rb_obj_class(exc) != getRbData()->exc[Reset]) break; diff --git a/binding-mri/input-binding.cpp b/binding-mri/input-binding.cpp index f20b06a..85562b3 100644 --- a/binding-mri/input-binding.cpp +++ b/binding-mri/input-binding.cpp @@ -24,12 +24,14 @@ #include "exception.h" #include "binding-util.h" #include "util.h" +#include "eventthread.h" RB_METHOD(inputUpdate) { RB_UNUSED_PARAM; shState->input().update(); +shState->eThread().process(shState->rtData()); return Qnil; } diff --git a/src/boost-hash.h b/src/boost-hash.h index 3ce746a..9d65958 100644 --- a/src/boost-hash.h +++ b/src/boost-hash.h @@ -21,10 +21,9 @@ #ifndef BOOSTHASH_H #define BOOSTHASH_H - -#include -#include - +#include +#include +#include #include /* Wrappers around the boost unordered template classes, @@ -34,7 +33,7 @@ template class BoostHash { private: - typedef boost::unordered_map BoostType; + typedef std::map BoostType; typedef std::pair PairType; BoostType p; @@ -98,7 +97,7 @@ template class BoostSet { private: - typedef boost::unordered_set BoostType; + typedef std::set BoostType; BoostType p; public: diff --git a/src/config.cpp b/src/config.cpp index 33d8160..b0e1547 100644 --- a/src/config.cpp +++ b/src/config.cpp @@ -21,9 +21,9 @@ #include "config.h" -#include -#include -#include +//#include +//#include +//#include #include @@ -140,8 +140,8 @@ std::set setFromVec(const std::vector &vec) return std::set(vec.begin(), vec.end()); } -typedef std::vector StringVec; -namespace po = boost::program_options; +//typedef std::vector StringVec; +//namespace po = boost::program_options; #define CONF_FILE "mkxp.conf" @@ -150,6 +150,8 @@ Config::Config() void Config::read(int argc, char *argv[]) { + gameFolder = "game"; +#if 0 #define PO_DESC_ALL \ PO_DESC(rgssVersion, int, 0) \ PO_DESC(debugMode, bool, false) \ @@ -244,6 +246,8 @@ void Config::read(int argc, char *argv[]) #undef PO_DESC #undef PO_DESC_ALL +#endif + preloadScripts.insert("win32_wrap.rb"); rgssVersion = clamp(rgssVersion, 0, 3); @@ -276,6 +280,7 @@ static void setupScreenSize(Config &conf) void Config::readGameINI() { + if (!customScript.empty()) { game.title = baseName(customScript); @@ -287,7 +292,7 @@ void Config::readGameINI() return; } - +#if 0 po::options_description podesc; podesc.add_options() ("Game.Title", po::value()) @@ -295,9 +300,11 @@ void Config::readGameINI() ; po::variables_map vm; +#endif + std::string iniFilename = execName + ".ini"; SDLRWStream iniFile(iniFilename.c_str(), "r"); - +#if 0 if (iniFile) { try @@ -317,9 +324,11 @@ void Config::readGameINI() GUARD_ALL( game.title = vm["Game.Title"].as(); ); GUARD_ALL( game.scripts = vm["Game.Scripts"].as(); ); +#endif + game.scripts = "Data/Scripts.rxdata"; + strReplace(game.scripts, '\\', '/'); - #ifdef INI_ENCODING /* Can add more later */ const char *languages[] = diff --git a/src/config.h b/src/config.h index d2d4650..272337a 100644 --- a/src/config.h +++ b/src/config.h @@ -28,56 +28,56 @@ struct Config { - int rgssVersion; + int rgssVersion = 0; - bool debugMode; - bool printFPS; + bool debugMode = false; + bool printFPS = false; - bool winResizable; - bool fullscreen; - bool fixedAspectRatio; - bool smoothScaling; - bool vsync; + bool winResizable = false; + bool fullscreen = false; + bool fixedAspectRatio = true; + bool smoothScaling = true; + bool vsync = false; - int defScreenW; - int defScreenH; + int defScreenW = 0; + int defScreenH = 0; - int fixedFramerate; - bool frameSkip; - bool syncToRefreshrate; + int fixedFramerate = 0; + bool frameSkip =true; + bool syncToRefreshrate = false; - bool solidFonts; + bool solidFonts = false; - bool subImageFix; - bool enableBlitting; - int maxTextureSize; + bool subImageFix = false; + bool enableBlitting = true; + int maxTextureSize = 0; - std::string gameFolder; - bool anyAltToggleFS; - bool enableReset; - bool allowSymlinks; - bool pathCache; + std::string gameFolder = "."; + bool anyAltToggleFS = false; + bool enableReset = true; + bool allowSymlinks = false; + bool pathCache=true; std::string dataPathOrg; std::string dataPathApp; std::string iconPath; - std::string execName; + std::string execName = "Game"; std::string titleLanguage; struct { std::string soundFont; - bool chorus; - bool reverb; + bool chorus = false; + bool reverb = false; } midi; struct { - int sourceCount; + int sourceCount = 6; } SE; - bool useScriptNames; + bool useScriptNames = false; std::string customScript; std::set preloadScripts; diff --git a/src/eventthread.cpp b/src/eventthread.cpp index 08b6c29..6749767 100644 --- a/src/eventthread.cpp +++ b/src/eventthread.cpp @@ -100,7 +100,9 @@ bool EventThread::allocUserEvents() return true; } - +#ifdef __EMSCRIPTEN__ +#include +#endif EventThread::EventThread() : fullscreen(false), showCursor(false) @@ -108,64 +110,43 @@ EventThread::EventThread() void EventThread::process(RGSSThreadData &rtData) { + SDL_Event event; + UnidirMessage windowSizeMsg; + + static bool once = true; + if (once) { SDL_Event event; SDL_Window *win = rtData.window; UnidirMessage &windowSizeMsg = rtData.windowSizeMsg; initALCFunctions(rtData.alcDev); - // XXX this function breaks input focus on OSX -#ifndef __MACOSX__ - SDL_SetEventFilter(eventFilter, &rtData); -#endif fullscreen = rtData.config.fullscreen; - int toggleFSMod = rtData.config.anyAltToggleFS ? KMOD_ALT : KMOD_LALT; + toggleFSMod = rtData.config.anyAltToggleFS ? KMOD_ALT : KMOD_LALT; fps.lastFrame = SDL_GetPerformanceCounter(); fps.displayCounter = 0; fps.acc = 0; fps.accDiv = 0; - if (rtData.config.printFPS) - fps.sendUpdates.set(); - - 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; - - bool terminate = false; - - SDL_Joystick *js = 0; if (SDL_NumJoysticks() > 0) js = SDL_JoystickOpen(0); - char buffer[128]; - - char pendingTitle[128]; - bool havePendingTitle = false; - - bool resetting = false; - - int winW, winH; - int i; - SDL_GetWindowSize(win, &winW, &winH); - SettingsMenu *sMenu = 0; - - while (true) + once = false; + } + while (SDL_PollEvent(&event)) { - if (!SDL_WaitEvent(&event)) - { - Debug() << "EventThread: Event error"; - break; - } +#ifdef __EMSCRIPTEN__ + emscripten_sleep(10); +#endif +// if (!SDL_WaitEvent(&event)) +// { +// Debug() << "EventThread: Event error"; +// break; +// } if (sMenu && sMenu->onEvent(event)) { @@ -460,12 +441,12 @@ void EventThread::process(RGSSThreadData &rtData) } /* Just in case */ - rtData.syncPoint.resumeThreads(); + //rtData.syncPoint.resumeThreads(); - if (SDL_JoystickGetAttached(js)) - SDL_JoystickClose(js); + //if (SDL_JoystickGetAttached(js)) + // SDL_JoystickClose(js); - delete sMenu; + //delete sMenu; } int EventThread::eventFilter(void *data, SDL_Event *event) diff --git a/src/eventthread.h b/src/eventthread.h index 02a9ea1..76860f9 100644 --- a/src/eventthread.h +++ b/src/eventthread.h @@ -35,7 +35,7 @@ #include #include - +class SettingsMenu; struct RGSSThreadData; typedef struct ALCdevice_struct ALCdevice; struct SDL_Window; @@ -123,6 +123,35 @@ private: double acc; uint32_t accDiv; } fps; + + SDL_Window *win; + int toggleFSMod; + + 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; + + bool terminate = false; + + SDL_Joystick *js = 0; + + char buffer[128]; + + char pendingTitle[128]; + bool havePendingTitle = false; + + bool resetting = false; + + int winW, winH; + int i; + + SettingsMenu *sMenu = 0; + }; /* Used to asynchronously inform the RGSS thread diff --git a/src/filesystem.cpp b/src/filesystem.cpp index d7fd36b..5fc5eae 100644 --- a/src/filesystem.cpp +++ b/src/filesystem.cpp @@ -18,7 +18,7 @@ ** You should have received a copy of the GNU General Public License ** along with mkxp. If not, see . */ - +#include #include "filesystem.h" #include "rgssad.h" diff --git a/src/fluid-fun.cpp b/src/fluid-fun.cpp index d49157d..a4c86b2 100644 --- a/src/fluid-fun.cpp +++ b/src/fluid-fun.cpp @@ -17,7 +17,7 @@ #elif __WINDOWS__ #define FLUID_LIB "fluidsynth.dll" #else -#error "platform not recognized" +//#error "platform not recognized" #endif struct FluidFunctions fluid; @@ -26,6 +26,7 @@ static void *so; void initFluidFunctions() { +#if 0 #ifdef SHARED_FLUID #define FLUID_FUN(name, type) \ @@ -64,4 +65,7 @@ fail: SDL_UnloadObject(so); so = 0; #endif +#endif + so = 0; + return; } diff --git a/src/graphics.cpp b/src/graphics.cpp index d205697..c8e66d1 100644 --- a/src/graphics.cpp +++ b/src/graphics.cpp @@ -318,7 +318,9 @@ private: /* Nanoseconds per second */ #define NS_PER_S 1000000000 - +#ifdef __EMSCRIPTEN__ +#include +#endif struct FPSLimiter { uint64_t lastTickCount; @@ -420,6 +422,7 @@ struct FPSLimiter private: void delayTicks(uint64_t ticks) { +#ifndef __EMSCRIPTEN__ #if defined(HAVE_NANOSLEEP) struct timespec req; uint64_t nsec = ticks / tickFreqNS; @@ -441,6 +444,10 @@ private: } #else SDL_Delay(ticks / tickFreqMS); +#endif +#endif +#ifdef __EMSCRIPTEN + emscripten_sleep(ticks /tickFreqMS); #endif } }; diff --git a/src/main.cpp b/src/main.cpp index 1a3fc4e..2db1ed9 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -232,7 +232,7 @@ int main(int argc, char *argv[]) } conf.readGameINI(); - + printf("%s\n", conf.gameFolder.c_str()); assert(conf.rgssVersion >= 1 && conf.rgssVersion <= 3); printRgssVersion(conf.rgssVersion); @@ -322,8 +322,9 @@ int main(int argc, char *argv[]) rtData.bindingUpdateMsg.post(loadBindings(conf)); /* Start RGSS thread */ - SDL_Thread *rgssThread = - SDL_CreateThread(rgssThreadFun, "rgss", &rtData); + //SDL_Thread *rgssThread = + // SDL_CreateThread(rgssThreadFun, "rgss", &rtData); + ::rgssThreadFun(&rtData); /* Start event processing */ eventThread.process(rtData); @@ -347,8 +348,8 @@ int main(int argc, char *argv[]) /* If RGSS thread ack'd request, wait for it to shutdown, * otherwise abandon hope and just end the process as is. */ - if (rtData.rqTermAck) - SDL_WaitThread(rgssThread, 0); + if (rtData.rqTermAck){} + //SDL_WaitThread(rgssThread, 0); else SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, conf.game.title.c_str(), "The RGSS script seems to be stuck and mkxp will now force quit", win);