Skip to content
This repository has been archived by the owner on Sep 16, 2024. It is now read-only.

Commit

Permalink
Web build works
Browse files Browse the repository at this point in the history
  • Loading branch information
OFFTKP committed Jan 3, 2024
1 parent 785e1bc commit b174918
Show file tree
Hide file tree
Showing 7 changed files with 129 additions and 34 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/Web.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ jobs:
- name: Setup emsdk
uses: mymindstorm/setup-emsdk@v10
with:
version: 2.0.21
version: 3.1.50
actions-cache-folder: 'emsdk-cache'
- name: Build
run: |
Expand Down
33 changes: 14 additions & 19 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ set(BUILD_STATIC_LIBS ON)
set(DPP_BUILD_TEST OFF)

if (WIN32)
set(HYDRA_DEFINITIONS ${HYDRA_DEFINITIONS} HYDRA_WINDOWS WIN32_LEAN_AND_MEAN)
set(HYDRA_DEFINITIONS ${HYDRA_DEFINITIONS} HYDRA_WINDOWS WIN32_LEAN_AND_MEAN NOMINMAX)
set(HYDRA_WINDOWS 1)
elseif(APPLE)
set(HYDRA_DEFINITIONS ${HYDRA_DEFINITIONS} HYDRA_MACOS)
Expand Down Expand Up @@ -49,11 +49,7 @@ if(HYDRA_WINDOWS)
elseif(HYDRA_MACOS)
set(CMAKE_OSX_DEPLOYMENT_TARGET "10.15" CACHE STRING "Minimum OS X deployment version" FORCE)
set(HYDRA_LIBRARIES ${HYDRA_LIBRARIES}
# "-framework QuartzCore"
# "-framework Cocoa"
# "-framework MetalKit"
# "-framework AudioToolbox"
# "-framework Metal"
"-framework OpenGL"
)
elseif(HYDRA_LINUX)
set(HYDRA_LIBRARIES ${HYDRA_LIBRARIES} OpenGL::GL)
Expand All @@ -71,18 +67,12 @@ elseif(HYDRA_IOS)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -x objective-c")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -x objective-c++")
set(HYDRA_LIBRARIES ${HYDRA_LIBRARIES}
# "-framework Foundation"
# "-framework UIKit"
# "-framework AudioToolbox"
# "-framework AVFoundation"
# "-framework GameController"
"-framework OpenGL"
)
elseif(HYDRA_WEB)
set(LONG_INT 8) # for openssl
set(CMAKE_EXECUTABLE_SUFFIX ".html")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -sEXPORTED_RUNTIME_METHODS=ccall")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -sEXPORTED_RUNTIME_METHODS=ccall")
set_target_properties(hydra PROPERTIES LINK_FLAGS "-sALLOW_MEMORY_GROWTH -s TOTAL_MEMORY=192MB -lidbfs.js -s ELIMINATE\_DUPLICATE\_FUNCTIONS=1 -flto -s USE_CLOSURE_COMPILER=0 --closure 0")
set_target_properties(hydra PROPERTIES LINK_FLAGS "-sEXPORTED_FUNCTIONS=[_main_impl,_main] -sEXPORTED_RUNTIME_METHODS=ccall -sNO_DISABLE_EXCEPTION_CATCHING -sASSERTIONS -sALLOW_MEMORY_GROWTH -s TOTAL_MEMORY=192MB -lidbfs.js -s ELIMINATE\_DUPLICATE\_FUNCTIONS=1 -flto -s USE_CLOSURE_COMPILER=0 --closure 0")
else()
message(FATAL_ERROR "Unsupported platform")
endif()
Expand All @@ -91,12 +81,9 @@ endif()
if (MSVC)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /MT /Ox /Ob2 /Oi /Ot /GT /GF /GS- /fp:fast /fp:except- /MP /sdl- /EHsc /D_SECURE_SCL=0 /D_SCL_SECURE_NO_WARNINGS /D_ITERATOR_DEBUG_LEVEL=0 /D_HAS_ITERATOR_DEBUGGING=0")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /MT /Ox /Ob2 /Oi /Ot /GT /GF /GS- /fp:fast /fp:except- /MP /sdl- /EHsc /D_SECURE_SCL=0 /D_SCL_SECURE_NO_WARNINGS /D_ITERATOR_DEBUG_LEVEL=0 /D_HAS_ITERATOR_DEBUGGING=0")
elseif(NOT HYDRA_WEB)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -O3")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g -O3")
else()
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O3 -DNDEBUG") # it's best to strip out debug symbols for web builds
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O3 -DNDEBUG") # to reduce the binary size
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -O3") # TODO: it's best to strip out debug symbols for web builds
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g -O3") # to reduce the binary size
endif()

option(BUILD_QT "Build the Qt frontend" OFF)
Expand All @@ -105,6 +92,7 @@ option(BUILD_DISCORD_BOT "Build with discord bot support" OFF)

add_subdirectory(vendored/fmt)
add_subdirectory(vendored/argparse)
set(SDL_TEST_LIBRARY OFF CACHE BOOL "" FORCE)
add_subdirectory(vendored/SDL)

set(HYDRA_INCLUDES ${HYDRA_INCLUDES}
Expand Down Expand Up @@ -141,6 +129,13 @@ if(NOT HYDRA_IOS AND NOT HYDRA_WEB)
find_package(OpenGL REQUIRED)
endif()

if(HYDRA_MACOS AND HYDRA_IOS)
set_target_properties(hydra PROPERTIES
MACOSX_BUNDLE ON
MACOSX_BUNDLE_BUNDLE_NAME hydra
MACOSX_BUNDLE_BUNDLE_IDENTIFIER "com.hydra.hydra_emu")
endif()

set(HYDRA_QT_FILES
data/resources.qrc
qt/mainwindow.cxx
Expand Down
58 changes: 58 additions & 0 deletions include/compatibility.hxx
Original file line number Diff line number Diff line change
@@ -1,10 +1,30 @@
#pragma once

#include <cstdint>
#include <filesystem>
#include <log.hxx>
#include <span>
#include <sstream>
#include <string>
#include <vector>

#ifdef HYDRA_WEB
#include <emscripten.h>
#endif

static void sync_fs()
{
#ifdef HYDRA_WEB
EM_ASM(
FS.syncfs(false, function (err) {
if (err) {
console.log("Failed to sync FS: " + err);
}
});
);
#endif
}

namespace hydra
{
inline std::vector<std::string> split(const std::string& s, char delimiter)
Expand Down Expand Up @@ -44,4 +64,42 @@ namespace hydra
return hash;
}

inline std::string fread(const std::filesystem::path& path)
{
FILE* file = std::fopen(path.string().c_str(), "rb");
if (!file)
{
file = std::fopen(path.string().c_str(), "wb");
if (!file)
{
hydra::log("Failed to open file: %s\n", path.string().c_str());
return "";
}
std::fclose(file);
sync_fs();
return "";
}

std::string contents;
std::fseek(file, 0, SEEK_END);
contents.resize(std::ftell(file));
std::rewind(file);
std::fread(&contents[0], 1, contents.size(), file);
std::fclose(file);
return contents;
}

inline void fwrite(const std::filesystem::path& path, std::span<const uint8_t> contents)
{
FILE* file = std::fopen(path.string().c_str(), "wb");
if (!file)
{
hydra::log("Failed to open file: %s\n", path.string().c_str());
return;
}
std::fwrite(contents.data(), 1, contents.size(), file);
std::fclose(file);
sync_fs();
}

} // namespace hydra
29 changes: 18 additions & 11 deletions include/settings.hxx
Original file line number Diff line number Diff line change
Expand Up @@ -44,17 +44,22 @@ public:
{
map().clear();
save_path() = path;
std::ifstream ifs(save_path());
if (ifs.good())
std::string data = hydra::fread(path);
if (data.empty())
{
json j_map;
ifs >> j_map;
map() = j_map.get<std::map<std::string, std::string>>();
return;
}
else

json j_map;
try
{
throw std::runtime_error("Failed to open settings");
j_map = json::parse(data);
} catch (std::exception& e)
{
hydra::log("Failed to parse settings file: {}", e.what());
return;
}
map() = j_map.get<std::map<std::string, std::string>>();
}

static std::string Get(const std::string& key)
Expand All @@ -71,9 +76,9 @@ public:
static void Set(const std::string& key, const std::string& value)
{
map()[key] = value;
std::ofstream ofs(save_path(), std::ios::trunc);
json j_map(map());
ofs << j_map << std::endl;
std::string data = j_map.dump(4);
hydra::fwrite(save_path(), std::span<const uint8_t>((uint8_t*)data.data(), data.size()));
}

static bool IsEmpty()
Expand All @@ -98,6 +103,8 @@ public:
std::string applicationName;
std::getline(cmdline, applicationName, '\0');
dir = std::filesystem::path("/data") / "data" / applicationName / "files";
#elif defined(HYDRA_WEB)
dir = std::filesystem::path("/hydra");
#endif
if (dir.empty())
{
Expand Down Expand Up @@ -156,12 +163,12 @@ public:
core_info_initialized() = true;
if (Settings::Get("core_path").empty())
{
Settings::Set("core_path", Settings::GetSavePath() / "cores");
Settings::Set("core_path", (Settings::GetSavePath() / "cores").string());
}

if (!std::filesystem::exists(Settings::Get("core_path")))
{
printf("Failed to find initialize core info\n");
printf("Failed to find core info: %s\n", Settings::Get("core_path").c_str());
return;
}

Expand Down
2 changes: 1 addition & 1 deletion src/app.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ static void MainLoopForEmscripten()
extern unsigned int CourierPrime_compressed_size;
extern unsigned int CourierPrime_compressed_data[44980 / 4];

int imgui_main(int argc, char** argv)
int imgui_main(int argc, char* argv[])
{
// TODO: Joystick
if (SDL_Init(SDL_INIT_VIDEO) != 0)
Expand Down
37 changes: 36 additions & 1 deletion src/main.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@
#endif
#include <settings.hxx>

#ifdef HYDRA_WEB
#include <emscripten.h>
#endif

// clang-format off

const char* options =
Expand Down Expand Up @@ -110,12 +114,34 @@ int bot_main_cb(struct argparse*, const struct argparse_option*)
#endif
}

int main(int argc, char* argv[])
#if defined(HYDRA_WEB)
// Setup the offline file system
EM_JS(void, em_init_fs, (),{
FS.mkdir('/hydra');
// Then mount with IDBFS type
FS.mount(IDBFS, {}, '/hydra');
FS.mkdir('/hydra/cores');
FS.mount(IDBFS, {}, '/hydra/cores');
FS.mkdir('/hydra/cache');
FS.mount(IDBFS, {}, '/hydra/cache');
// Then sync
FS.syncfs(true, function (err) {
Module.ccall('main_impl');
});
});
#endif

extern "C" int main_impl(int argc, char* argv[])
{
printf("hydra version %s\n", HYDRA_VERSION);
auto settings_path = Settings::GetSavePath() / "settings.json";
Settings::Open(settings_path);
Settings::InitCoreInfo();

#ifdef HYDRA_WEB
return imgui_main(argc, argv);
#endif

if (argc == 1)
{
return imgui_main(argc, argv);
Expand Down Expand Up @@ -144,3 +170,12 @@ int main(int argc, char* argv[])
argparse_parse(&argparse, argc, const_cast<const char**>(argv));
return 0;
}

int main(int argc, char* argv[])
{
#ifdef HYDRA_WEB
em_init_fs();
#else
return main_impl(argc, argv);
#endif
}
2 changes: 1 addition & 1 deletion vendored/argparse/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ endif()

set(sources argparse.c)

option(ARGPARSE_SHARED "Build shared library" ON)
option(ARGPARSE_SHARED "Build shared library" OFF)
option(ARGPARSE_STATIC "Build static library" ON)

if(ARGPARSE_SHARED)
Expand Down

0 comments on commit b174918

Please sign in to comment.