From e9914e3fbd935e5ca91e522cb2237b6f5a606949 Mon Sep 17 00:00:00 2001 From: Kolyah35 Date: Thu, 19 Mar 2026 02:26:34 +0300 Subject: [PATCH] ADD: WebASM port (no sound/no network) --- CMakeLists.txt | 174 +++++++++++++----- README.md | 31 ++++ misc/web/index.html | 143 ++++++++++++++ src/AppPlatform_glfw.h | 14 +- src/NinecraftApp.cpp | 3 +- src/client/gui/screens/CreditsScreen.cpp | 2 + .../screens/touch/TouchSelectWorldScreen.h | 16 +- src/client/renderer/Tesselator.cpp | 13 +- src/client/renderer/gles.cpp | 10 +- src/client/renderer/gles.h | 26 +-- src/main_glfw.h | 89 +++++---- src/platform/CThread.cpp | 2 +- src/platform/CThread.h | 4 +- 13 files changed, 408 insertions(+), 119 deletions(-) create mode 100644 misc/web/index.html diff --git a/CMakeLists.txt b/CMakeLists.txt index 20ec99c..a88ca61 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -11,48 +11,69 @@ if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang") endif() find_package(Threads REQUIRED) - find_package(OpenSSL) -if (OpenSSL_FOUND) - message(STATUS "found openssl ${OPENSSL_VERSION}") + +if(EMSCRIPTEN) + set(AL_LIBTYPE "STATIC") +else() + set(AL_LIBTYPE "SHARED") endif() -CPMAddPackage("gh:madler/zlib@1.3.2") -CPMAddPackage( - NAME "libpng" - GIT_REPOSITORY "https://github.com/pnggroup/libpng.git" - GIT_TAG "v1.6.55" - EXCLUDE_FROM_ALL TRUE - OPTIONS - "ZLIB_ROOT ${zlib_SOURCE_DIR}" - "ZLIB_INCLUDE_DIRS ${zlib_SOURCE_DIR}" - "PNG_TOOLS OFF" - "PNG_TESTS OFF" - "BUILD_SHARED_LIBS ON" -) +# I totally shocked +if(EMSCRIPTEN) + add_library(zlib INTERFACE IMPORTED) + set_target_properties(zlib PROPERTIES + INTERFACE_LINK_OPTIONS "-sUSE_ZLIB=1" + ) + + add_library(png INTERFACE IMPORTED) + set_target_properties(png PROPERTIES + INTERFACE_LINK_OPTIONS "-sUSE_LIBPNG=1" + ) + + add_library(glfw INTERFACE IMPORTED) + set_target_properties(glfw PROPERTIES + INTERFACE_LINK_OPTIONS "-sUSE_GLFW=3" + ) +else() + CPMAddPackage( + NAME "zlib" + GIT_REPOSITORY "https://github.com/madler/zlib" + GIT_TAG "v1.3.2" + ) + + CPMAddPackage( + NAME "libpng" + GIT_REPOSITORY "https://github.com/pnggroup/libpng.git" + GIT_TAG "v1.6.55" + OPTIONS + "ZLIB_ROOT ${zlib_SOURCE_DIR}" + "ZLIB_INCLUDE_DIRS ${zlib_SOURCE_DIR}" + "PNG_TOOLS OFF" + "PNG_TESTS OFF" + ) + + CPMAddPackage( + NAME "glfw" + GIT_REPOSITORY "https://github.com/glfw/glfw.git" + GIT_TAG "3.4" + EXCLUDE_FROM_ALL TRUE + OPTIONS + "GLFW_BUILD_EXAMPLES OFF" + "GLFW_BUILD_TESTS OFF" + "GLFW_BUILD_DOCS OFF" + ) +endif() CPMAddPackage( NAME "openal" GIT_REPOSITORY "https://github.com/kcat/openal-soft.git" GIT_TAG "1.25.1" - EXCLUDE_FROM_ALL TRUE OPTIONS "ALSOFT_EXAMPLES OFF" "ALSOFT_TESTS OFF" "ALSOFT_UTILS OFF" - "BUILD_SHARED_LIBS ON" -) - -CPMAddPackage( - NAME "glfw" - GIT_REPOSITORY "https://github.com/glfw/glfw.git" - GIT_TAG "3.4" - EXCLUDE_FROM_ALL TRUE - OPTIONS - "GLFW_BUILD_EXAMPLES OFF" - "GLFW_BUILD_TESTS OFF" - "GLFW_BUILD_DOCS OFF" - "BUILD_SHARED_LIBS ON" + "LIBTYPE ${AL_LIBTYPE}" ) # TODO: Clear this paths with * @@ -242,11 +263,15 @@ endif() if(PLATFORM STREQUAL "PLATFORM_WIN32") - list(APPEND CLIENT_SOURCES "src/AppPlatform_win32.cpp") + list(APPEND CLIENT_SOURCES "src/AppPlatform_win32.cpp" "glad/src/glad.c") endif() if(PLATFORM STREQUAL "PLATFORM_GLFW") - list(APPEND CLIENT_SOURCES "src/AppPlatform_glfw.cpp") + list(APPEND CLIENT_SOURCES "src/AppPlatform_glfw.cpp" "glad/src/glad.c") +endif() + +if(EMSCRIPTEN) + list(APPEND CLIENT_SOURCES "glad/src/glad.c") endif() # Server @@ -260,13 +285,10 @@ target_include_directories("${PROJECT_NAME}-server" PUBLIC "project/lib_projects/raknet/jni/RaknetSources" ) -target_link_libraries("${PROJECT_NAME}-server" ${CMAKE_THREAD_LIBS_INIT} png_shared) +target_link_libraries("${PROJECT_NAME}-server" ${CMAKE_THREAD_LIBS_INIT}) endif() -add_executable(${PROJECT_NAME} - ${CLIENT_SOURCES} - "glad/src/glad.c" -) +add_executable(${PROJECT_NAME} ${CLIENT_SOURCES}) if(WIN32) set(EXTRA_LIBS "ws2_32") @@ -277,8 +299,6 @@ if(PLATFORM STREQUAL "PLATFORM_WIN32" OR PLATFORM STREQUAL "PLATFORM_GLFW") target_compile_definitions(${PROJECT_NAME} PUBLIC "PLATFORM_DESKTOP") endif() - - target_include_directories(${PROJECT_NAME} PUBLIC "${CMAKE_SOURCE_DIR}/glad/include/" "${CMAKE_SOURCE_DIR}/src" @@ -287,9 +307,53 @@ target_include_directories(${PROJECT_NAME} PUBLIC "lib/include" ) +if(EMSCRIPTEN) + set(CMAKE_CXX_STANDARD 11) + # uuuh i hate it + set(EM_FLAGS "-pthread -sUSE_PTHREADS=1 -sSHARED_MEMORY=1") + + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${EM_FLAGS}") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${EM_FLAGS}") + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${EM_FLAGS} --preload-file ${CMAKE_SOURCE_DIR}/data@/data -sPROXY_TO_PTHREAD") + + target_compile_options(${PROJECT_NAME} PUBLIC + "-Os" + "-Wno-invalid-source-encoding" + "-Wno-narrowing" + "-Wno-deprecated-register" + "-Wno-reserved-user-defined-literal" + ) + + target_link_options(${PROJECT_NAME} PUBLIC + "-Os" + "-sALLOW_MEMORY_GROWTH=1" + "-sFORCE_FILESYSTEM=1" + "-sLEGACY_GL_EMULATION=1" + "-sGL_UNSAFE_OPTS=0" + "-sEMULATE_FUNCTION_POINTER_CASTS=1" + "-sALLOW_TABLE_GROWTH=1" + "-sEXPORTED_RUNTIME_METHODS=['FS','stringToUTF8','UTF8ToString','cwrap','ccall','HEAP8','HEAPU8','HEAP32','HEAPU32']" + "-sEXPORTED_FUNCTIONS=['_main']" + ) + + if (CMAKE_BUILD_TYPE STREQUAL "Debug") + message("DEBUG MODE") + + target_link_options(${PROJECT_NAME} PUBLIC + "-sASSERTIONS=2" + "-sSTACK_OVERFLOW_CHECK=2" + "-sSTACK_SIZE=5242880" + "-sGL_DEBUG=1" + ) + endif() + + target_compile_definitions(${PROJECT_NAME} PUBLIC "__EMSCRIPTEN__" "NO_SOUND" "NO_NETWORK") + set(EXTRA_LIBS "idbfs.js") +endif() + # Client target_compile_definitions(${PROJECT_NAME} PUBLIC "OPENGL_ES" "NO_EGL" ${PLATFORM}) -target_link_libraries(${PROJECT_NAME} zlib png_shared alsoft.common OpenAL::OpenAL glfw ${EXTRA_LIBS}) +target_link_libraries(${PROJECT_NAME} zlib png alsoft.common OpenAL::OpenAL glfw ${EXTRA_LIBS}) if (OpenSSL_FOUND) target_link_libraries(${PROJECT_NAME} OpenSSL::SSL OpenSSL::Crypto) @@ -297,19 +361,27 @@ if (OpenSSL_FOUND) endif() if (NOT UNIX) -add_custom_command( - TARGET ${PROJECT_NAME} - POST_BUILD - COMMAND ${CMAKE_COMMAND} -E copy_if_different $ $ - COMMAND_EXPAND_LISTS -) + add_custom_command( + TARGET ${PROJECT_NAME} + POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy_if_different $ $ + COMMAND_EXPAND_LISTS + ) endif() -add_custom_command( - TARGET ${PROJECT_NAME} - POST_BUILD - COMMAND ${CMAKE_COMMAND} -E copy_directory "${CMAKE_SOURCE_DIR}/data" $/data -) +if(NOT EMSCRIPTEN) + add_custom_command( + TARGET ${PROJECT_NAME} + POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy_directory "${CMAKE_SOURCE_DIR}/data" $/data + ) +else() + add_custom_command( + TARGET ${PROJECT_NAME} + POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_SOURCE_DIR}/misc/web/index.html" $ + ) +endif() # Installing and packing diff --git a/README.md b/README.md index a5bf6be..22c89bd 100644 --- a/README.md +++ b/README.md @@ -167,3 +167,34 @@ cmake --build . 8. Re run `build.sh` +## Web +1. Download and install **emsdk**: https://emscripten.org/docs/getting_started/downloads.html + > [!NOTE] + > On arch linux you can use AUR: + > `yay -Sy emsdk` + +2. Configure and build project: + ``` + mkdir build && cd build + cmake .. -B . -G Ninja "-DCMAKE_TOOLCHAIN_FILE=$EMSDK/upstream/emscripten/cmake/Modules/Platform/Emscripten.cmake" + cmake --build . --target MinecraftPE + ``` + > [!NOTE] + > If you are using VSCode with CMake plugin, you can add Emscripten kit + > 1. Press Ctrl + Shift + P + > 2. Type `CMake: Edit User-Local CMake Kits` and hit Enter + > 3. Add this: + ```json + { + "name": "Emscripten", + "compilers": { + "C": "/usr/lib/emsdk/upstream/bin/clang", + "CXX": "/usr/lib/emsdk/upstream/bin/clang++" + }, + "toolchainFile": "/usr/lib/emsdk/upstream/emscripten/cmake/Modules/Platform/Emscripten.cmake" + } + ``` +3. Run game: + ``` + emrun --port 8080 . + ``` \ No newline at end of file diff --git a/misc/web/index.html b/misc/web/index.html new file mode 100644 index 0000000..108e109 --- /dev/null +++ b/misc/web/index.html @@ -0,0 +1,143 @@ + + + + + + Emscripten-Generated Code + + + +
+
emscripten
+
Downloading...
+
+ +
+
+ +
+
+
+ Resize canvas + Lock/hide mouse pointer +     + +
+ +
+ +
+ + + + \ No newline at end of file diff --git a/src/AppPlatform_glfw.h b/src/AppPlatform_glfw.h index 38eb66c..4c7eb72 100755 --- a/src/AppPlatform_glfw.h +++ b/src/AppPlatform_glfw.h @@ -31,7 +31,7 @@ public: { } - BinaryBlob readAssetFile(const std::string& filename) { + BinaryBlob readAssetFile(const std::string& filename) override { FILE* fp = fopen(("data/" + filename).c_str(), "r"); if (!fp) return BinaryBlob(); @@ -48,7 +48,7 @@ public: return blob; } - void saveScreenshot(const std::string& filename, int glWidth, int glHeight) { + void saveScreenshot(const std::string& filename, int glWidth, int glHeight) override { //@todo } @@ -56,7 +56,7 @@ public: return (p & 0xff00ff00) | ((p >> 16) & 0xff) | ((p << 16) & 0xff0000); } - TextureData loadTexture(const std::string& filename_, bool textureFolder) + TextureData loadTexture(const std::string& filename_, bool textureFolder) override { // Support fetching PNG textures via HTTP/HTTPS (for skins, etc) if (Util::startsWith(filename_, "http://") || Util::startsWith(filename_, "https://")) { @@ -132,10 +132,10 @@ public: return std::string(mbstr); } - virtual int getScreenWidth() { return 854; }; - virtual int getScreenHeight() { return 480; }; + virtual int getScreenWidth() override { return 854; }; + virtual int getScreenHeight() override { return 480; }; - virtual float getPixelsPerMillimeter(); + virtual float getPixelsPerMillimeter() override; virtual bool supportsTouchscreen() override { return true; } @@ -148,6 +148,8 @@ public: #endif } + GLFWwindow* window; + private: }; #endif /*APPPLATFORM_GLFW_H__*/ diff --git a/src/NinecraftApp.cpp b/src/NinecraftApp.cpp index 2e88549..69e01c3 100755 --- a/src/NinecraftApp.cpp +++ b/src/NinecraftApp.cpp @@ -245,8 +245,9 @@ void NinecraftApp::initGLStates() glCullFace(GL_BACK); glEnable2(GL_TEXTURE_2D); +#ifndef _EMSCRIPTEN_ glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST); - +#endif // Both updates isPowerVR flag in java and returns if the graphics chip is PowerVR SGX or not _powerVr = platform()->isPowerVR(); #ifdef __APPLE__ diff --git a/src/client/gui/screens/CreditsScreen.cpp b/src/client/gui/screens/CreditsScreen.cpp index ae2c224..56f13ac 100644 --- a/src/client/gui/screens/CreditsScreen.cpp +++ b/src/client/gui/screens/CreditsScreen.cpp @@ -37,6 +37,8 @@ void CreditsScreen::init() { _lines.push_back("mschiller890"); _lines.push_back("InviseDivine"); _lines.push_back("Kolyah35"); + _lines.push_back("karson"); + _lines.push_back("deepfriedwaffles"); _lines.push_back(""); // avoid color tags around the URL so it isn't mangled by the parser please _lines.push_back("Join our Discord server: https://discord.gg/c58YesBxve"); diff --git a/src/client/gui/screens/touch/TouchSelectWorldScreen.h b/src/client/gui/screens/touch/TouchSelectWorldScreen.h index f02f5e0..525116b 100755 --- a/src/client/gui/screens/touch/TouchSelectWorldScreen.h +++ b/src/client/gui/screens/touch/TouchSelectWorldScreen.h @@ -86,21 +86,21 @@ public: SelectWorldScreen(); virtual ~SelectWorldScreen(); - virtual void init(); - virtual void setupPositions(); + virtual void init() override; + virtual void setupPositions() override; - virtual void tick(); - virtual void render(int xm, int ym, float a); + virtual void tick() override; + virtual void render(int xm, int ym, float a) override; virtual bool isIndexValid(int index); - virtual bool handleBackEvent(bool isDown); - virtual void buttonClicked(Button* button); - virtual void keyPressed(int eventKey); + virtual bool handleBackEvent(bool isDown) override; + virtual void buttonClicked(Button* button) override; + virtual void keyPressed(int eventKey) override; // support for mouse wheel when desktop code uses touch variant virtual void mouseWheel(int dx, int dy, int xm, int ym) override; - bool isInGameScreen(); + bool isInGameScreen() override; private: void loadLevelSource(); std::string getUniqueLevelName(const std::string& level); diff --git a/src/client/renderer/Tesselator.cpp b/src/client/renderer/Tesselator.cpp index 2fe36e1..dedaca3 100755 --- a/src/client/renderer/Tesselator.cpp +++ b/src/client/renderer/Tesselator.cpp @@ -79,6 +79,9 @@ RenderChunk Tesselator::end( bool useMine, int bufferId ) const int o_vertices = vertices; if (vertices > 0) { + if (p <= 0 || p > maxVertices) { clear(); return RenderChunk(); } + int bytes = p * sizeof(VERTEX); + if (bytes <= 0) return RenderChunk(); if (++vboId >= vboCounts) vboId = 0; @@ -92,11 +95,11 @@ RenderChunk Tesselator::end( bool useMine, int bufferId ) bufferId = vboIds[vboId]; #endif int access = GL_STATIC_DRAW;//(accessMode==ACCESS_DYNAMIC) ? GL_DYNAMIC_DRAW : GL_STATIC_DRAW; - int bytes = p * sizeof(VERTEX); glBindBuffer2(GL_ARRAY_BUFFER, bufferId); glBufferData2(GL_ARRAY_BUFFER, bytes, _varray, access); // GL_STREAM_DRAW + totalSize += bytes; - + #ifndef USE_VBO // 0 1 2 3 4 5 6 7 // x y z u v c @@ -264,6 +267,7 @@ void Tesselator::vertex( float x, float y, float z ) for (int i = 0; i < 2; i++) { const int offs = 3 - i; + if (p - offs < 0 || p >= maxVertices) { clear(); return; } VERTEX& src = _varray[p - offs]; VERTEX& dst = _varray[p]; @@ -287,6 +291,7 @@ void Tesselator::vertex( float x, float y, float z ) } } + if (p < 0 || p >= maxVertices) { clear(); return; } VERTEX& vertex = _varray[p]; if (hasTexture) { @@ -377,13 +382,15 @@ void Tesselator::draw() tesselating = false; if (vertices > 0) { + if (p <= 0 || p > maxVertices) { clear(); return; } + int bytes = p * sizeof(VERTEX); + if (bytes <= 0) { clear(); return; } if (++vboId >= vboCounts) vboId = 0; int bufferId = vboIds[vboId]; int access = GL_DYNAMIC_DRAW;//(accessMode==ACCESS_DYNAMIC) ? GL_DYNAMIC_DRAW : GL_STATIC_DRAW; - int bytes = p * sizeof(VERTEX); glBindBuffer2(GL_ARRAY_BUFFER, bufferId); glBufferData2(GL_ARRAY_BUFFER, bytes, _varray, access); // GL_STREAM_DRAW diff --git a/src/client/renderer/gles.cpp b/src/client/renderer/gles.cpp index f29fbc2..04ae3d3 100755 --- a/src/client/renderer/gles.cpp +++ b/src/client/renderer/gles.cpp @@ -47,9 +47,13 @@ void glInit() } void anGenBuffers(GLsizei n, GLuint* buffers) { - static GLuint k = 1; - for (int i = 0; i < n; ++i) - buffers[i] = ++k; +#ifdef __EMSCRIPTEN__ + glGenBuffers(n, buffers); +#else + static GLuint k = 1; + for (int i = 0; i < n; ++i) + buffers[i] = ++k; +#endif } #ifdef USE_VBO diff --git a/src/client/renderer/gles.h b/src/client/renderer/gles.h index b016c37..32b16d2 100755 --- a/src/client/renderer/gles.h +++ b/src/client/renderer/gles.h @@ -10,13 +10,13 @@ #endif // Other systems might run it, if they #define OPENGL_ES -#if defined(OPENGL_ES) // || defined(ANDROID) +// #if defined(OPENGL_ES) // || defined(ANDROID) #define USE_VBO #define GL_QUADS 0x0007 #if defined(__APPLE__) #import #import - #elif defined(ANDROID) + #elif defined(ANDROID) || defined(__EMSCRIPTEN__) #include #include #else @@ -28,18 +28,18 @@ #define glClearDepthf(x) glClearDepth(x) #define glDepthRangef(a,b) glDepthRange(a,b) #endif -#else - // Uglyness to fix redeclaration issues - #ifdef WIN32 - #include - #include - #endif - #include - #include +// #else +// // Uglyness to fix redeclaration issues +// #ifdef WIN32 +// #include +// #include +// #endif +// #include +// #include - #define glFogx(a,b) glFogi(a,b) - #define glOrthof(a,b,c,d,e,f) glOrtho(a,b,c,d,e,f) -#endif +// #define glFogx(a,b) glFogi(a,b) +// #define glOrthof(a,b,c,d,e,f) glOrtho(a,b,c,d,e,f) +// #endif #define GLERRDEBUG 1 diff --git a/src/main_glfw.h b/src/main_glfw.h index 9226b16..ecee3ad 100755 --- a/src/main_glfw.h +++ b/src/main_glfw.h @@ -2,9 +2,9 @@ #define MAIN_GLFW_H__ #include "App.h" -#include "GLFW/glfw3.h" +#include "client/renderer/entity/PlayerRenderer.h" #include "client/renderer/gles.h" -#include "SharedConstants.h" +#include "GLFW/glfw3.h" #include #include @@ -12,9 +12,10 @@ #include "platform/input/Keyboard.h" #include "platform/input/Mouse.h" #include "platform/input/Multitouch.h" -#include "util/Mth.h" #include "AppPlatform_glfw.h" - +#ifdef __EMSCRIPTEN__ +#include +#endif static App* g_app = 0; int transformKey(int glfwkey) { @@ -112,12 +113,39 @@ void error_callback(int error, const char* desc) { printf("Error: %s\n", desc); } + +void loop() { + using clock = std::chrono::steady_clock; + auto frameStart = clock::now(); + + g_app->update(); + + glfwSwapBuffers(((AppPlatform_glfw*)g_app->platform())->window); + glfwPollEvents(); + + glfwSwapInterval(((MAIN_CLASS*)g_app)->options.getBooleanValue(OPTIONS_VSYNC) ? 1 : 0); + if(((MAIN_CLASS*)g_app)->options.getBooleanValue(OPTIONS_LIMIT_FRAMERATE)) { + auto frameEnd = clock::now(); + auto elapsed = std::chrono::duration_cast(frameEnd - frameStart); + auto target = std::chrono::microseconds(33333); // ~30 fps + if(elapsed < target) + std::this_thread::sleep_for(target - elapsed); + } +} + int main(void) { AppContext appContext; #ifndef STANDALONE_SERVER // Platform init. appContext.platform = new AppPlatform_glfw(); +#if defined(DEBUG) && defined(__EMSCRIPTEN__) + EM_ASM({ + console.log(FS.readdir("/")); + console.log(FS.readdir("/data")); + console.log(FS.readdir("/data/images")); + }); +#endif glfwSetErrorCallback(error_callback); @@ -126,26 +154,36 @@ int main(void) { } glfwWindowHint(GLFW_CONTEXT_CREATION_API, GLFW_NATIVE_CONTEXT_API); +#ifndef __EMSCRIPTEN__ glfwWindowHint(GLFW_CLIENT_API, GLFW_OPENGL_API); glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 2); glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 1); +#else + glfwWindowHint(GLFW_CLIENT_API, GLFW_OPENGL_ES_API); + glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 1); + glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0); +#endif - GLFWwindow* window = glfwCreateWindow(appContext.platform->getScreenWidth(), appContext.platform->getScreenHeight(), "main", NULL, NULL); + AppPlatform_glfw* platform = (AppPlatform_glfw*)appContext.platform; + + platform->window = glfwCreateWindow(appContext.platform->getScreenWidth(), appContext.platform->getScreenHeight(), "main", NULL, NULL); - if (window == NULL) { + if (platform->window == NULL) { return 1; } - glfwSetKeyCallback(window, key_callback); - glfwSetCharCallback(window, character_callback); - glfwSetCursorPosCallback(window, cursor_position_callback); - glfwSetMouseButtonCallback(window, mouse_button_callback); - glfwSetScrollCallback(window, scroll_callback); - glfwSetWindowSizeCallback(window, window_size_callback); + glfwSetKeyCallback(platform->window, key_callback); + glfwSetCharCallback(platform->window, character_callback); + glfwSetCursorPosCallback(platform->window, cursor_position_callback); + glfwSetMouseButtonCallback(platform->window, mouse_button_callback); + glfwSetScrollCallback(platform->window, scroll_callback); + glfwSetWindowSizeCallback(platform->window, window_size_callback); - glfwMakeContextCurrent(window); + glfwMakeContextCurrent(platform->window); + #ifndef __EMSCRIPTEN__ gladLoadGLLoader((GLADloadproc)glfwGetProcAddress); glfwSwapInterval(0); + #endif #endif App* app = new MAIN_CLASS(); @@ -156,25 +194,14 @@ int main(void) { g_app->init(appContext); g_app->setSize(appContext.platform->getScreenWidth(), appContext.platform->getScreenHeight()); +#ifdef __EMSCRIPTEN__ + emscripten_set_main_loop(loop, 0, 1); +#else // Main event loop - using clock = std::chrono::steady_clock; - while(!glfwWindowShouldClose(window) && !app->wantToQuit()) { - auto frameStart = clock::now(); - - app->update(); - - glfwSwapBuffers(window); - glfwPollEvents(); - - glfwSwapInterval(((MAIN_CLASS*)app)->options.getBooleanValue(OPTIONS_VSYNC) ? 1 : 0); - if(((MAIN_CLASS*)app)->options.getBooleanValue(OPTIONS_LIMIT_FRAMERATE)) { - auto frameEnd = clock::now(); - auto elapsed = std::chrono::duration_cast(frameEnd - frameStart); - auto target = std::chrono::microseconds(33333); // ~30 fps - if(elapsed < target) - std::this_thread::sleep_for(target - elapsed); - } + while(!glfwWindowShouldClose(platform->window) && !app->wantToQuit()) { + loop(); } +#endif delete app; @@ -184,7 +211,7 @@ int main(void) { #ifndef STANDALONE_SERVER // Exit. - glfwDestroyWindow(window); + glfwDestroyWindow(platform->window); glfwTerminate(); #endif diff --git a/src/platform/CThread.cpp b/src/platform/CThread.cpp index 20e883e..e136198 100755 --- a/src/platform/CThread.cpp +++ b/src/platform/CThread.cpp @@ -25,7 +25,7 @@ &m_threadID // pointer to receive thread ID ); #endif - #if defined(__linux__) || defined(ANDROID) || defined(__APPLE__) || defined(POSIX) + #if defined(__linux__) || defined(ANDROID) || defined(__APPLE__) || defined(POSIX) || defined(__EMSCRIPTEN__) mp_threadFunc = (pthread_fn)threadFunc; pthread_attr_init(&m_attributes); diff --git a/src/platform/CThread.h b/src/platform/CThread.h index 3e2c975..c608e92 100755 --- a/src/platform/CThread.h +++ b/src/platform/CThread.h @@ -13,7 +13,7 @@ typedef void *( * pthread_fn )( void * ); -#if defined(__linux__) || defined(ANDROID) || defined(__APPLE__) || defined(POSIX) +#if defined(__linux__) || defined(ANDROID) || defined(__APPLE__) || defined(POSIX) || defined(__EMSCRIPTEN__) #include #include @@ -38,7 +38,7 @@ typedef void *( * pthread_fn )( void * ); DWORD m_threadID; HANDLE m_threadHandle; #endif - #if defined(__linux__) || defined(ANDROID) || defined(__APPLE__) || defined(POSIX) + #if defined(__linux__) || defined(ANDROID) || defined(__APPLE__) || defined(POSIX) || defined(__EMSCRIPTEN__) pthread_fn mp_threadFunc; pthread_t m_thread; pthread_attr_t m_attributes;