Compare commits

..

9 commits

14 changed files with 210 additions and 38 deletions

View file

@ -0,0 +1,18 @@
#pragma once
#include <psemek/io/stream.hpp>
#include <filesystem>
#include <memory>
namespace psemek::app
{
std::filesystem::path storage_root();
void set_storage_root(std::filesystem::path const & root);
// Implemented by a backend library
std::unique_ptr<io::istream> read_storage(std::filesystem::path const & relative_path);
std::unique_ptr<io::ostream> write_storage(std::filesystem::path const & relative_path);
}

View file

@ -0,0 +1,24 @@
#include <psemek/app/storage.hpp>
#include <psemek/util/executable_path.hpp>
namespace psemek::app
{
namespace
{
static std::filesystem::path global_storage_root = util::executable_path().parent_path();
}
std::filesystem::path storage_root()
{
return global_storage_root;
}
void set_storage_root(std::filesystem::path const & root)
{
global_storage_root = root;
}
}

View file

@ -4,19 +4,40 @@
#include <filesystem>
#include <cstdio>
#include <memory>
namespace psemek::io
{
namespace detail
{
#ifdef __EMSCRIPTEN__
struct buffer_hook
{
static constexpr std::size_t buffer_size = 1 << 20; // 1 MB
std::unique_ptr<char[]> buffer{new char[buffer_size]};
void apply(FILE * file)
{
std::setvbuf(file, buffer.get(), _IOFBF, buffer_size);
}
};
#else
struct buffer_hook
{
void apply(FILE *) {}
};
#endif
}
struct file_istream
: istream
{
file_istream() = default;
file_istream(FILE * file)
: file_{file}
{}
file_istream(FILE * file);
file_istream(std::filesystem::path const & path);
file_istream(file_istream && s)
@ -49,6 +70,7 @@ namespace psemek::io
private:
FILE * file_ = nullptr;
[[no_unique_address]] detail::buffer_hook buffer_hook_;
};
struct file_ostream
@ -58,10 +80,7 @@ namespace psemek::io
file_ostream() = default;
file_ostream(FILE * file)
: file_{file}
{}
file_ostream(FILE * file);
file_ostream(std::filesystem::path const & path, unsigned flags = 0);
file_ostream(file_ostream && s)
@ -94,6 +113,7 @@ namespace psemek::io
private:
FILE * file_ = nullptr;
[[no_unique_address]] detail::buffer_hook buffer_hook_;
};
}

View file

@ -3,6 +3,7 @@
#include <psemek/io/stream.hpp>
#include <string_view>
#include <vector>
namespace psemek::io
{
@ -131,4 +132,55 @@ namespace psemek::io
char * end_ = nullptr;
};
struct expanding_memory_ostream
: ostream
{
expanding_memory_ostream() = default;
expanding_memory_ostream(std::vector<char> & storage)
: buffer_(&storage)
{}
expanding_memory_ostream(expanding_memory_ostream && s)
: storage_(std::move(s.storage_))
, buffer_(s.buffer_)
{
s.reset();
}
expanding_memory_ostream & operator = (expanding_memory_ostream && s)
{
if (this != &s)
{
storage_ = std::move(s.storage_);
buffer_ = s.buffer_;
s.reset();
}
return *this;
}
void reset()
{
storage_.clear();
buffer_ = &storage_;
}
void swap(expanding_memory_ostream & s)
{
std::swap(storage_, s.storage_);
std::swap(buffer_, s.buffer_);
}
char * data() const { return buffer_->data(); }
std::vector<char> & buffer() { return *buffer_; }
std::size_t write(char const * p, std::size_t size) override;
private:
std::vector<char> storage_;
std::vector<char> * buffer_ = &storage_;
};
}

View file

@ -41,7 +41,11 @@ namespace psemek::io
#else
char const * fopen_read_mode()
{
#ifdef __EMSCRIPTEN__
return "r+b";
#else
return "rb";
#endif
}
char const * fopen_write_mode(unsigned flags)
@ -65,9 +69,17 @@ namespace psemek::io
}
file_istream::file_istream(FILE * file)
: file_{file}
{
buffer_hook_.apply(file_);
}
file_istream::file_istream(std::filesystem::path const & path)
: file_{safe_fopen(path, fopen_read_mode())}
{}
{
buffer_hook_.apply(file_);
}
void file_istream::reset()
{
@ -88,9 +100,17 @@ namespace psemek::io
return std::feof(file_) != 0;
}
file_ostream::file_ostream(FILE * file)
: file_{file}
{
buffer_hook_.apply(file_);
}
file_ostream::file_ostream(std::filesystem::path const & path, unsigned flags)
: file_{safe_fopen(path, fopen_write_mode(flags))}
{}
{
buffer_hook_.apply(file_);
}
void file_ostream::reset()
{

View file

@ -23,4 +23,10 @@ namespace psemek::io
return size;
}
std::size_t expanding_memory_ostream::write(char const * p, std::size_t size)
{
buffer_->insert(buffer_->end(), p, p + size);
return size;
}
}

View file

@ -153,7 +153,7 @@ namespace psemek::log
#if __APPLE__
::pthread_setname_np(name.data());
#else
#if !(defined __EMSCRIPTEN__) || (defined __EMSCRIPTEN_PTHREADS__)
#if !(defined __EMSCRIPTEN__)
::pthread_setname_np(::pthread_self(), name.data());
#endif
#endif

View file

@ -1,6 +1,6 @@
# On web SDL is provided by emsdk itself
if(NOT CMAKE_SYSTEM_NAME STREQUAL Emscripten)
find_package(SDL2 REQUIRED)
if(NOT PSEMEK_PLATFORM_WEB)
find_package(SDL2 REQUIRED)
endif()
file(GLOB_RECURSE PSEMEK_SDL2_HEADERS RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" "include/*.hpp")
@ -14,7 +14,11 @@ endif()
psemek_add_library(psemek-sdl2 ${PSEMEK_SDL2_HEADERS} ${PSEMEK_SDL2_SOURCES} ${PSEMEK_SDL2_PLATFORM_SOURCES})
target_include_directories(psemek-sdl2 PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include")
target_link_libraries(psemek-sdl2 PUBLIC psemek-log psemek-util psemek-audio psemek-app SDL2)
target_link_libraries(psemek-sdl2 PUBLIC psemek-log psemek-util psemek-audio psemek-app)
if(NOT PSEMEK_PLATFORM_WEB)
target_link_libraries(psemek-sdl2 PUBLIC SDL2)
endif()
if(PSEMEK_GRAPHICS_API STREQUAL OPENGL)
target_link_libraries(psemek-sdl2 PUBLIC psemek-gfx)
elseif(PSEMEK_GRAPHICS_API STREQUAL WEBGPU)

View file

@ -1,5 +1,6 @@
#include <psemek/app/application.hpp>
#include <psemek/app/resource.hpp>
#include <psemek/app/storage.hpp>
#include <psemek/gfx/init.hpp>
#include <psemek/sdl2/init.hpp>
#include <psemek/sdl2/window.hpp>
@ -13,16 +14,17 @@
#include <psemek/util/terminal_color.hpp>
#ifdef __EMSCRIPTEN__
#include <emscripten/emscripten.h>
#include <emscripten/html5.h>
#include <emscripten.h>
#include <emscripten/emscripten.h>
#include <emscripten/html5.h>
#include <emscripten.h>
#include <emscripten/wasmfs.h>
struct em_state
{
std::unique_ptr<psemek::app::application> application;
std::unique_ptr<psemek::sdl2::window> window;
psemek::app::application::context context;
} em_state;
struct em_state
{
std::unique_ptr<psemek::app::application> application;
std::unique_ptr<psemek::sdl2::window> window;
psemek::app::application::context context;
} em_state;
#endif
#undef main
@ -52,9 +54,13 @@ int main(int argc, char ** argv) try
log::register_thread("main");
#ifdef __EMSCRIPTEN__
// In web builds, resources are in the root of
// In web builds, resources are stored in
// the Emscripten virtual filesystem
app::set_resource_root("/");
app::set_resource_root("/resources");
backend_t opfs = wasmfs_create_opfs_backend();
wasmfs_create_directory("/storage", 0777, opfs);
app::set_storage_root("/storage");
#endif
auto const factory = app::make_application_factory();
@ -111,19 +117,17 @@ int main(int argc, char ** argv) try
SDL_StopTextInput();
#ifdef __EMSCRIPTEN__
emscripten_request_animation_frame_loop([](double, void*) -> EM_BOOL {
emscripten_set_main_loop([]{
if (sdl2::poll_events(*em_state.application))
em_state.application->stop();
if (!em_state.application->running())
return EM_FALSE;
emscripten_cancel_main_loop();
em_state.application->update();
em_state.application->present();
em_state.window->swap();
return EM_TRUE;
}, nullptr);
}, 0, 1);
#else
while (application->running())
{
@ -134,9 +138,10 @@ int main(int argc, char ** argv) try
application->present();
window.swap();
}
#endif
log::info() << "Quitting";
#endif
return EXIT_SUCCESS;
}
catch (psemek::util::exception const & e)

View file

@ -7,7 +7,7 @@ namespace psemek::app
std::unique_ptr<io::istream> open_resource(std::filesystem::path const & relative_path)
{
log::info() << "Opening resource " << relative_path;
log::debug() << "Opening resource " << relative_path;
return std::make_unique<io::file_istream>(app::resource_root() / relative_path);
}

View file

@ -0,0 +1,20 @@
#include <psemek/app/storage.hpp>
#include <psemek/io/file_stream.hpp>
#include <psemek/log/log.hpp>
namespace psemek::app
{
std::unique_ptr<io::istream> read_storage(std::filesystem::path const & relative_path)
{
log::debug() << "Reading storage " << relative_path;
return std::make_unique<io::file_istream>(app::storage_root() / relative_path);
}
std::unique_ptr<io::ostream> write_storage(std::filesystem::path const & relative_path)
{
log::debug() << "Writing storage " << relative_path;
return std::make_unique<io::file_ostream>(app::storage_root() / relative_path);
}
}

View file

@ -8,7 +8,7 @@ if(PSEMEK_PACKAGE_MODE)
set(PSEMEK_PACKAGE_LINK_FLAGS_RAW)
if(PSEMEK_PLATFORM_WEB)
list(APPEND PSEMEK_PACKAGE_LINK_FLAGS_RAW "-sMIN_WEBGL_VERSION=2" "-sNO_DISABLE_EXCEPTION_CATCHING" "-sFULL_ES3")
list(APPEND PSEMEK_PACKAGE_LINK_FLAGS_RAW -sUSE_SDL=2 -sMIN_WEBGL_VERSION=2 -sNO_DISABLE_EXCEPTION_CATCHING -sFULL_ES3 -sWASMFS -sALLOW_MEMORY_GROWTH -sGROWABLE_ARRAYBUFFERS=0 -sASYNCIFY)
list(APPEND PSEMEK_PACKAGE_LINK_FLAGS_RAW "-sDEFAULT_LIBRARY_FUNCS_TO_INCLUDE='$autoResumeAudioContext','$dynCall'")
if(CMAKE_BUILD_TYPE STREQUAL Debug)
list(APPEND PSEMEK_PACKAGE_LINK_FLAGS_RAW "-g")
@ -218,7 +218,7 @@ function(psemek_package_files target)
elseif(PSEMEK_PLATFORM_WEB)
foreach(_FILE IN LISTS ARGN)
target_link_options(${target} PRIVATE
"--preload-file=${CMAKE_CURRENT_LIST_DIR}/${_FILE}@/${_FILE}"
"--preload-file=${CMAKE_CURRENT_LIST_DIR}/${_FILE}@/resources/${_FILE}"
)
endforeach()
else()

View file

@ -2,10 +2,12 @@ FROM lisyarus/psemek:package-linux
# Install emsdk - the version the build was tested at
WORKDIR /home
RUN git clone --branch 3.1.46 https://github.com/emscripten-core/emsdk.git
RUN git clone --branch 6.0.2 https://github.com/emscripten-core/emsdk.git
WORKDIR /home/emsdk
RUN ./emsdk install 3.1.46
RUN ./emsdk activate 3.1.46
RUN ./emsdk install 6.0.2
RUN ./emsdk activate 6.0.2
RUN . ./emsdk_env.sh && embuilder build sdl2 sdl2-mt
WORKDIR /home
COPY env-helper.sh .
# Source emsdk env variables when running the container
@ -13,6 +15,7 @@ ENTRYPOINT ["/home/env-helper.sh"]
# Install Boost sources
WORKDIR /home
RUN git config --global advice.detachedHead false
RUN git clone --recurse-submodules --branch boost-1.87.0 https://github.com/boostorg/boost.git
# Install toolchain file & main packaging script

View file

@ -14,7 +14,7 @@ rm -rf ./*
# right toolchain.
emcmake cmake \
-DBOOST_SOURCE_ROOT=$(realpath ../source)/psemek/3rdparty/boost \
-DCMAKE_BUILD_TYPE=RelWithDebInfo \
-DCMAKE_BUILD_TYPE=Release \
-DPSEMEK_PACKAGE_MODE=ON \
-DPSEMEK_PACKAGE_HOST=OFF \
-DPSEMEK_PACKAGE_TARGET=ON \