diff --git a/CMakeLists.txt b/CMakeLists.txt index 1243b4d9..8cdc2e47 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -8,7 +8,9 @@ execute_process(COMMAND git rev-parse --short HEAD OUTPUT_STRIP_TRAILING_WHITESPACE ) -find_package(GLEW REQUIRED) +if (NOT EMSCRIPTEN) + find_package(GLEW REQUIRED) +endif() find_package(fmt REQUIRED) include(cmake/utils.cmake) @@ -21,6 +23,9 @@ option(ESSAGUI_EXAMPLES "Compile examples" ON) option(ESSAGUI_UTIL_ONLY "Compile only EssaUtil (no GUI or Engine)" OFF) include_directories(${Essa_SOURCE_DIR}) +if (EMSCRIPTEN) + include_directories(${fmt_DIR}/../../../include) +endif() add_subdirectory(EssaUtil) diff --git a/Essa/GUI/CMakeLists.txt b/Essa/GUI/CMakeLists.txt index e78fbf2f..145de547 100644 --- a/Essa/GUI/CMakeLists.txt +++ b/Essa/GUI/CMakeLists.txt @@ -85,8 +85,3 @@ set_target_properties(GUI PROPERTIES OUTPUT_NAME "essa-gui") set_target_properties(GUI PROPERTIES SOVERSION ${ESSA_GIT_REVISION}) essautil_setup_target(GUI) target_link_libraries(GUI PUBLIC Util LLGL-OpenGL LLGL-Window LLGL-Resources) - -# FIXME: This breaks build of eml/AST.cpp somewhere in Value::string() -target_compile_options(GUI PRIVATE -Wno-restrict) -# FIXME: This breaks build of RadioGroup::add_widget(). -target_compile_options(GUI PUBLIC -Wno-address) diff --git a/Essa/GUI/Debug.hpp b/Essa/GUI/Debug.hpp index 28730e9a..4407ffcb 100644 --- a/Essa/GUI/Debug.hpp +++ b/Essa/GUI/Debug.hpp @@ -33,9 +33,11 @@ class DebugSwitch { /*global*/ ::GUI::DebugSwitch __debug_##name { \ # name \ } -#define DBG_PRINTLN(name, fmtstr, ...) \ - { \ - if (DBG_ENABLED(name)) { \ - fmt::vprint(fmtstr "\n", fmt::make_format_args(__VA_ARGS__)); \ - } \ - } + +#define DBG_PRINTLN(name, fmtstr, ...) \ + do { \ + if (DBG_ENABLED(name)) { \ + const auto& vargs = fmt::make_format_args(__VA_ARGS__); \ + fmt::vprint(fmtstr "\n", vargs); \ + } \ + } while (false) diff --git a/Essa/GUI/EML/AST.cpp b/Essa/GUI/EML/AST.cpp index 26f54779..8cca8390 100644 --- a/Essa/GUI/EML/AST.cpp +++ b/Essa/GUI/EML/AST.cpp @@ -58,7 +58,7 @@ template struct overloaded : Ts... { std::string Value::string() const { return std::visit( - overloaded { + Util::Overloaded { [](double d) -> std::string { return fmt::format("{}", d); }, [](bool b) -> std::string { return b ? "true" : "false"; }, [](Util::UString const& str) -> std::string { return "\"" + str.encode() + "\""; }, diff --git a/Essa/GUI/EventLoop.cpp b/Essa/GUI/EventLoop.cpp index b7c51397..86b2fbc9 100644 --- a/Essa/GUI/EventLoop.cpp +++ b/Essa/GUI/EventLoop.cpp @@ -11,6 +11,8 @@ #ifdef __linux__ # include +#elif defined(__EMSCRIPTEN__) +# include #endif using namespace std::chrono_literals; @@ -39,8 +41,24 @@ void increase_system_timer_resolution() { void EventLoop::run() { auto old_event_loop = s_current_event_loop; s_current_event_loop = this; - Util::ScopeGuard guard = [&]() { s_current_event_loop = old_event_loop; }; +#ifdef __EMSCRIPTEN__ + if (!old_event_loop) { + emscripten_set_main_loop( + []() { + s_current_event_loop->tick(); + if (!s_current_event_loop->m_running) { + // FIXME: Make this work properly with dialogs. It may require + // refactoring them to be asynchronous ? + emscripten_cancel_main_loop(); + } + }, + 0, true + ); + return; + } +#else + Util::ScopeGuard guard = [&]() { s_current_event_loop = old_event_loop; }; Util::Clock clock; increase_system_timer_resolution(); @@ -73,6 +91,7 @@ void EventLoop::run() { } } } +#endif } EventLoop::TimerHandle EventLoop::set_timeout(Timer::Clock::duration const& timeout, Timer::Callback&& callback) { diff --git a/Essa/GUI/Graphics/DefaultGUIShader.cpp b/Essa/GUI/Graphics/DefaultGUIShader.cpp index fd85021f..799fe48e 100644 --- a/Essa/GUI/Graphics/DefaultGUIShader.cpp +++ b/Essa/GUI/Graphics/DefaultGUIShader.cpp @@ -6,6 +6,45 @@ namespace Gfx { +#ifdef __EMSCRIPTEN__ +static std::string_view VertexShader = R"~~~(// Default GUI VS +precision highp float; +precision highp int; + +attribute vec2 position; +attribute vec4 color; +attribute vec2 texCoords; + +uniform mat4 projectionMatrix; +uniform mat4 viewMatrix; +uniform mat4 modelMatrix; +uniform mat4 submodelMatrix; + +varying vec4 fColor; +varying vec2 fTexCoords; + +void main() { + fColor = color; + fTexCoords = texCoords; + gl_Position = projectionMatrix * (viewMatrix * (modelMatrix * (submodelMatrix * vec4(position, 0, 1)))); +} +)~~~"; + +static std::string_view FragmentShader = R"~~~(// Default GUI FS +precision highp float; +precision highp int; + +varying vec4 fColor; +varying vec2 fTexCoords; + +uniform sampler2D texture; +uniform bool textureSet; + +void main() { + gl_FragColor = textureSet ? fColor * texture2D(texture, fTexCoords.xy) : fColor; +} +)~~~"; +#else static std::string_view VertexShader = R"~~~(// Default GUI VS #version 330 core @@ -41,6 +80,7 @@ void main() { gl_FragColor = textureSet ? fColor * texture2D(texture, fTexCoords.xy) : fColor; } )~~~"; +#endif std::string_view DefaultGUIShader::source(llgl::ShaderType type) const { switch (type) { diff --git a/Essa/GUI/Graphics/Drawing/Shape.hpp b/Essa/GUI/Graphics/Drawing/Shape.hpp index 9c71d2a5..f28c025e 100644 --- a/Essa/GUI/Graphics/Drawing/Shape.hpp +++ b/Essa/GUI/Graphics/Drawing/Shape.hpp @@ -80,7 +80,6 @@ class Shape { private: Shape const& m_shape; - size_t m_index = 0; }; Points points() const { return Points { *this }; } diff --git a/Essa/GUI/Graphics/GUIBuilder.hpp b/Essa/GUI/Graphics/GUIBuilder.hpp index a9176f6b..0f6f7c92 100644 --- a/Essa/GUI/Graphics/GUIBuilder.hpp +++ b/Essa/GUI/Graphics/GUIBuilder.hpp @@ -54,6 +54,7 @@ class GUIBuilder : public llgl::Builder { virtual void render_range(llgl::Renderer& renderer, llgl::VertexArray const& vao, GUIBuilderRenderRange const& range) const override { + static Gfx::DefaultGUIShader m_shader; Gfx::DefaultGUIShader::Uniforms uniforms; uniforms.set_transform(range.model.matrix(), range.view.matrix(), range.projection.matrix()); uniforms.set_texture(range.texture); @@ -62,7 +63,6 @@ class GUIBuilder : public llgl::Builder { renderer.draw_vertices(vao, llgl::DrawState { m_shader, uniforms, range.type }, range.first, range.size); } - mutable Gfx::DefaultGUIShader m_shader; llgl::Projection m_projection; llgl::Transform m_view; llgl::Transform m_model; diff --git a/Essa/GUI/Graphics/ResourceManager.cpp b/Essa/GUI/Graphics/ResourceManager.cpp index 33cec7c7..9b087da7 100644 --- a/Essa/GUI/Graphics/ResourceManager.cpp +++ b/Essa/GUI/Graphics/ResourceManager.cpp @@ -77,6 +77,8 @@ llgl::TTFFont& ResourceManager::fixed_width_font() const { static std::filesystem::path exec_path() { #ifdef __linux__ return std::filesystem::read_symlink("/proc/" + std::to_string(getpid()) + "/exe").parent_path(); +#elif __EMSCRIPTEN__ + return "/"; #else # error OS not supported (install linux) #endif diff --git a/Essa/GUI/Overlays/FileExplorer.cpp b/Essa/GUI/Overlays/FileExplorer.cpp index 3ef9fbd0..2c3c358e 100644 --- a/Essa/GUI/Overlays/FileExplorer.cpp +++ b/Essa/GUI/Overlays/FileExplorer.cpp @@ -15,7 +15,9 @@ #include #include #include +#include #include +#include #include #include #include @@ -63,12 +65,13 @@ Variant FileModel::data(Node row, size_t column) const { case 4: { return Util::UString { file_type(file) }; } - case 3: - std::time_t cftime - = std::chrono::system_clock::to_time_t(std::chrono::file_clock::to_sys(std::filesystem::last_write_time(file.path))); - std::string string = std::asctime(std::localtime(&cftime)); - string.pop_back(); // trailing \n - return Util::UString { string }; + case 3: { + using namespace std::chrono_literals; + namespace ch = std::chrono; + // FIXME: Use clock cast when clang supports this. + auto time = ch::file_clock::to_sys(ch::time_point_cast(std::filesystem::last_write_time(file.path))); + return Util::UString { fmt::format("{:%x %X}", time) }; + } } return ""; } diff --git a/Essa/GUI/Widgets/Container.cpp b/Essa/GUI/Widgets/Container.cpp index 72f15663..fe654503 100644 --- a/Essa/GUI/Widgets/Container.cpp +++ b/Essa/GUI/Widgets/Container.cpp @@ -398,7 +398,9 @@ void Container::dump(unsigned depth) { for (unsigned i = 0; i < depth; i++) std::cout << "- "; if (m_layout) { - std::cout << "layout: " << typeid(*m_layout).name() << std::endl; + // Note: Temporary variable is a workaround for -Wpotentially-evaluated-expression on Clang + auto& layout = *m_layout; + std::cout << "layout: " << typeid(layout).name() << std::endl; } else { std::cout << "layout: NONE!" << std::endl; diff --git a/Essa/GUI/Widgets/ListView.cpp b/Essa/GUI/Widgets/ListView.cpp index d52bce6b..0f70eae1 100644 --- a/Essa/GUI/Widgets/ListView.cpp +++ b/Essa/GUI/Widgets/ListView.cpp @@ -93,34 +93,34 @@ void ListView::draw(Gfx::Painter& wnd) const { // configurable std::visit( - overloaded { [&](Util::UString const& data) { - Gfx::Text text { data, Application::the().bold_font() }; - text.set_font_size(theme().label_font_size); - text.set_fill_color(c % 2 == 0 ? list_even.text : list_odd.text); - text.align( - Align::CenterLeft, { (cell_position + Util::Vector2i(5, 0)).cast(), cell_size.cast() } - ); - text.draw(wnd); - }, - [&](Gfx::RichText const& data) { - Gfx::RichTextDrawable drawable { data, - { - .default_font = Application::the().font(), - .font_size = static_cast(theme().label_font_size), - .text_alignment = GUI::Align::CenterLeft, - } }; - drawable.set_rect({ (cell_position + Util::Vector2i(5, 0)).cast(), cell_size.cast() }); - drawable.draw(wnd); - }, - [&](llgl::Texture const* data) { - Gfx::RectangleDrawOptions rect; - rect.texture = data; - wnd.deprecated_draw_rectangle( - { { cell_position.x() + cell_size.x() / 2 - 8, cell_position.y() + cell_size.y() / 2 - 8 }, - { 16, 16 } }, - rect - ); - } }, + Util::Overloaded { + [&](Util::UString const& data) { + Gfx::Text text { data, Application::the().bold_font() }; + text.set_font_size(theme().label_font_size); + text.set_fill_color(c % 2 == 0 ? list_even.text : list_odd.text); + text.align( + Align::CenterLeft, { (cell_position + Util::Vector2i(5, 0)).cast(), cell_size.cast() } + ); + text.draw(wnd); + }, + [&](Gfx::RichText const& data) { + Gfx::RichTextDrawable drawable { data, + { + .default_font = Application::the().font(), + .font_size = static_cast(theme().label_font_size), + .text_alignment = GUI::Align::CenterLeft, + } }; + drawable.set_rect({ (cell_position + Util::Vector2i(5, 0)).cast(), cell_size.cast() }); + drawable.draw(wnd); + }, + [&](llgl::Texture const* data) { + Gfx::RectangleDrawOptions rect; + rect.texture = data; + wnd.deprecated_draw_rectangle( + { { cell_position.x() + cell_size.x() / 2 - 8, cell_position.y() + cell_size.y() / 2 - 8 }, { 16, 16 } }, + rect + ); + } }, data ); } diff --git a/Essa/LLGL/OpenGL/Error.cpp b/Essa/LLGL/OpenGL/Error.cpp index 80d515f2..4238e9f5 100644 --- a/Essa/LLGL/OpenGL/Error.cpp +++ b/Essa/LLGL/OpenGL/Error.cpp @@ -4,23 +4,25 @@ #include -#include -#include #include +#include namespace llgl::opengl { void enable_debug_output() { ensure_glew(); + +#ifndef __EMSCRIPTEN__ OpenGL::Enable(GL_DEBUG_OUTPUT); glDebugMessageCallback( []([[maybe_unused]] GLenum source, GLenum type, [[maybe_unused]] GLuint id, [[maybe_unused]] GLenum severity, - [[maybe_unused]] GLsizei length, const GLchar* message, [[maybe_unused]] const void* user_param) { + [[maybe_unused]] GLsizei length, GLchar const* message, [[maybe_unused]] void const* user_param) { if (type == GL_DEBUG_TYPE_ERROR) std::cout << "GL Error: " << message << std::endl; }, 0 ); +#endif } void handle_error(std::source_location location) { diff --git a/Essa/LLGL/OpenGL/FBO.cpp b/Essa/LLGL/OpenGL/FBO.cpp index 97f92a75..37951ec9 100644 --- a/Essa/LLGL/OpenGL/FBO.cpp +++ b/Essa/LLGL/OpenGL/FBO.cpp @@ -1,18 +1,16 @@ #include "FBO.hpp" -#include #include +#include #include namespace llgl::opengl { FBO::FBO(Util::Size2u size) { - opengl::ensure_glew(); OpenGL::GenFramebuffers(1, &m_fbo); + FBOScope scope { *this }; resize(size); - FBOScope scope { *this }; - OpenGL::FramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, m_depth_renderbuffer); GLenum buffers[] = { GL_COLOR_ATTACHMENT0 }; OpenGL::DrawBuffers(1, buffers); @@ -41,25 +39,35 @@ void FBO::bind(Target target) const { } void FBO::resize(Util::Size2u size) { - FBOScope scope { *this }; if (m_color_texture.size() == size) return; + + FBOScope scope { *this }; + + // Color if (!m_color_texture.id()) m_color_texture = Texture::create_empty(size, Texture::Format::RGBA); else m_color_texture.recreate(size, Texture::Format::RGBA); - OpenGL::FramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, m_color_texture.id(), 0); + + OpenGL::FramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_color_texture.id(), 0); + + // Depth if (m_depth_renderbuffer) OpenGL::DeleteRenderbuffers(1, &m_depth_renderbuffer); + OpenGL::GenRenderbuffers(1, &m_depth_renderbuffer); OpenGL::BindRenderbuffer(GL_RENDERBUFFER, m_depth_renderbuffer); OpenGL::RenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, size.x(), size.y()); + OpenGL::FramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, m_depth_renderbuffer); // std::cout << "FBO: recreated with size " << size.x << "," << size.y << std::endl; } void FBO::set_label(std::string const& str) { +#ifndef __EMSCRIPTEN__ OpenGL::ObjectLabel(GL_FRAMEBUFFER, m_fbo, str.size(), str.data()); +#endif m_color_texture.set_label("FBO Texture: " + str); } diff --git a/Essa/LLGL/OpenGL/Texture.cpp b/Essa/LLGL/OpenGL/Texture.cpp index 95dcea30..5f892cb4 100644 --- a/Essa/LLGL/OpenGL/Texture.cpp +++ b/Essa/LLGL/OpenGL/Texture.cpp @@ -73,7 +73,7 @@ void Texture::ensure_initialized(Format format) { TextureBinder binder(*this); // std::cout << "glTexImage2D(" << m_size << ")\n"; - OpenGL::TexImage2D(GL_TEXTURE_2D, 0, gl_format(format), m_size.x(), m_size.y(), 0, gl_format(format), GL_FLOAT, nullptr); + OpenGL::TexImage2D(GL_TEXTURE_2D, 0, gl_format(format), m_size.x(), m_size.y(), 0, gl_format(format), GL_UNSIGNED_BYTE, nullptr); } } @@ -83,7 +83,7 @@ void Texture::recreate(Util::Size2u size, Format format) { if (m_id) { TextureBinder binder(*this); // std::cout << "glTexImage2D(" << m_size << ")\n"; - glTexImage2D(GL_TEXTURE_2D, 0, gl_format(format), m_size.x(), m_size.y(), 0, gl_format(format), GL_FLOAT, nullptr); + glTexImage2D(GL_TEXTURE_2D, 0, gl_format(format), m_size.x(), m_size.y(), 0, gl_format(format), GL_UNSIGNED_BYTE, nullptr); } ensure_initialized(format); @@ -126,6 +126,10 @@ void Texture::set_filtering(Filtering filtering) { void Texture::bind(Texture const* texture) { OpenGL::BindTexture(GL_TEXTURE_2D, texture ? texture->id() : 0); } -void Texture::set_label(std::string const& label) { OpenGL::ObjectLabel(GL_TEXTURE, m_id, label.size(), label.data()); } +void Texture::set_label([[maybe_unused]] std::string const& label) { +#ifndef __EMSCRIPTEN__ + OpenGL::ObjectLabel(GL_TEXTURE, m_id, label.size(), label.data()); +#endif +} } diff --git a/Essa/LLGL/Resources/CMakeLists.txt b/Essa/LLGL/Resources/CMakeLists.txt index f9f63e09..dd7a6df4 100644 --- a/Essa/LLGL/Resources/CMakeLists.txt +++ b/Essa/LLGL/Resources/CMakeLists.txt @@ -4,4 +4,9 @@ set(SOURCES TTFFont.cpp ) add_llgl_library(Resources resources) -target_link_libraries(LLGL-Resources LLGL-Core LLGL-OpenGL SDL2_image SDL2_ttf) +target_link_libraries(LLGL-Resources LLGL-Core LLGL-OpenGL) +if (EMSCRIPTEN) + target_link_options(LLGL-Resources PUBLIC "SHELL:-s USE_SDL_IMAGE=2 -s USE_SDL_TTF=2 -s SDL2_IMAGE_FORMATS=\'[\"png\",\"jpg\"]\'") +else() + target_link_libraries(LLGL-Resources SDL2_image SDL2_ttf) +endif() diff --git a/Essa/LLGL/Resources/ImageLoader.cpp b/Essa/LLGL/Resources/ImageLoader.cpp index 44968f25..7b87b719 100644 --- a/Essa/LLGL/Resources/ImageLoader.cpp +++ b/Essa/LLGL/Resources/ImageLoader.cpp @@ -33,9 +33,11 @@ static Uint32 get_pixel(SDL_Surface& surface, Util::Point2u position) { } std::optional ImageLoader::load_from_file(std::string const& path) { - auto surface = IMG_Load(path.c_str()); - if (!surface) + auto* surface = IMG_Load(path.c_str()); + if (!surface) { + fmt::print("IMG_Load({}) failed: {}\n", path, SDL_GetError()); return {}; + } auto image = load_from_sdl_surface(surface); SDL_FreeSurface(surface); diff --git a/Essa/LLGL/Window/AbstractOpenGLHelper.hpp b/Essa/LLGL/Window/AbstractOpenGLHelper.hpp index b7c4c044..53367520 100644 --- a/Essa/LLGL/Window/AbstractOpenGLHelper.hpp +++ b/Essa/LLGL/Window/AbstractOpenGLHelper.hpp @@ -21,6 +21,7 @@ class OpenGL { ADD_OPENGL_FUNCTION(GenTextures) ADD_OPENGL_FUNCTION(TexImage2D) ADD_OPENGL_FUNCTION(FramebufferTexture) + ADD_OPENGL_FUNCTION(FramebufferTexture2D) ADD_OPENGL_FUNCTION(GetTexImage) ADD_OPENGL_FUNCTION(BufferData) diff --git a/Essa/LLGL/Window/CMakeLists.txt b/Essa/LLGL/Window/CMakeLists.txt index 0844af06..004ba6e1 100644 --- a/Essa/LLGL/Window/CMakeLists.txt +++ b/Essa/LLGL/Window/CMakeLists.txt @@ -7,4 +7,11 @@ set(SOURCES Window.cpp ) add_llgl_library(Window window) -target_link_libraries(LLGL-Window Util SDL2 Xrender) +if(NOT EMSCRIPTEN) # FIXME: if(LINUX) + set(X11_LIBS Xrender) +endif() +target_link_libraries(LLGL-Window Util SDL2 ${X11_LIBS}) +if(EMSCRIPTEN) + target_compile_options(LLGL-Window PUBLIC "SHELL:-s USE_SDL=2") + target_link_options(LLGL-Window PUBLIC "SHELL:-s MAX_WEBGL_VERSION=2 -s USE_WEBGL2=1 -s MIN_WEBGL_VERSION=2 -s FULL_ES3=1") +endif() diff --git a/Essa/LLGL/Window/Impls/SDLHelpers.cpp b/Essa/LLGL/Window/Impls/SDLHelpers.cpp index 69dc2e99..b073cbef 100644 --- a/Essa/LLGL/Window/Impls/SDLHelpers.cpp +++ b/Essa/LLGL/Window/Impls/SDLHelpers.cpp @@ -1,15 +1,19 @@ #include "SDLHelpers.hpp" #include +#ifndef __EMSCRIPTEN__ #include #include +#endif #include #include #include #include #include +#ifndef __EMSCRIPTEN__ #include #include +#endif #include #include #include diff --git a/Essa/LLGL/Window/Impls/SDLWindow.cpp b/Essa/LLGL/Window/Impls/SDLWindow.cpp index adf33d99..52c1eddb 100644 --- a/Essa/LLGL/Window/Impls/SDLWindow.cpp +++ b/Essa/LLGL/Window/Impls/SDLWindow.cpp @@ -39,6 +39,10 @@ void Window::create_impl(Util::Size2u size, Util::UString const& title, WindowSe initialized = true; +#ifdef __EMSCRIPTEN__ + SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2); + SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0); +#else // Note: Remember to add these attributes to GLX in transparent window implementation SDL_GL_SetAttribute(SDL_GL_ACCELERATED_VISUAL, 1); SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); @@ -49,6 +53,7 @@ void Window::create_impl(Util::Size2u size, Util::UString const& title, WindowSe SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8); SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8); SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24); +#endif uint32_t sdl_flags = SDLHelpers::llgl_window_flags_to_sdl(settings.flags); if (has_flag(settings.flags, WindowFlags::TransparentBackground)) { @@ -80,10 +85,14 @@ void Window::create_impl(Util::Size2u size, Util::UString const& title, WindowSe } if (!s_context) s_context = SDL_GL_CreateContext(m_data->window); + if (!s_context) { + fmt::print("Failed to create OpenGL context: {}\n", SDL_GetError()); + } int major, minor; SDL_GL_GetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, &major); SDL_GL_GetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, &minor); std::cout << "SDLWindow: Created OpenGL context version " << major << "." << minor << std::endl; + std::cout << "GL_VERSION=" << glGetString(GL_VERSION) << std::endl; set_active(); } diff --git a/Essa/LLGL/Window/Window.hpp b/Essa/LLGL/Window/Window.hpp index f1b23bf1..2873411f 100644 --- a/Essa/LLGL/Window/Window.hpp +++ b/Essa/LLGL/Window/Window.hpp @@ -14,7 +14,7 @@ namespace llgl { namespace Detail { -class SDLWindowData; +struct SDLWindowData; } class Window { diff --git a/EssaUtil/CMakeLists.txt b/EssaUtil/CMakeLists.txt index 2f4cd2a8..f116e24e 100644 --- a/EssaUtil/CMakeLists.txt +++ b/EssaUtil/CMakeLists.txt @@ -27,7 +27,4 @@ essautil_setup_target(Util) install(TARGETS Util EXPORT Essa DESTINATION lib) target_link_libraries(Util PUBLIC fmt::fmt) -# FIXME: This breaks build of eml/AST.cpp somewhere in Value::string() -target_compile_options(Util PRIVATE -Wno-restrict) - add_subdirectory(Tests) diff --git a/EssaUtil/Config.hpp b/EssaUtil/Config.hpp index d484f781..620b50b2 100644 --- a/EssaUtil/Config.hpp +++ b/EssaUtil/Config.hpp @@ -24,6 +24,8 @@ constexpr bool UNREACHABLE = false; // https://en.cppreference.com/w/cpp/utility/variant/visit template struct Overloaded : Ts... { + Overloaded(Ts... ts) + : Ts(std::forward(ts))... { } using Ts::operator()...; }; diff --git a/EssaUtil/CoordinateSystem/GeoCoords.cpp b/EssaUtil/CoordinateSystem/GeoCoords.cpp index 49bfa615..574eebe8 100644 --- a/EssaUtil/CoordinateSystem/GeoCoords.cpp +++ b/EssaUtil/CoordinateSystem/GeoCoords.cpp @@ -1,5 +1,10 @@ #include "GeoCoords.hpp" +// M_PIf is a GCC extension, define it for other compilers +#ifndef M_PIf +# define M_PIf ((float)M_PI) +#endif + namespace Util { GeoCoords GeoCoords::normalized() const { diff --git a/EssaUtil/Error.hpp b/EssaUtil/Error.hpp index 7e730949..a0ac5069 100644 --- a/EssaUtil/Error.hpp +++ b/EssaUtil/Error.hpp @@ -159,7 +159,7 @@ template class [[nodiscard]] ErrorOr : publi auto location() const { return m_location; } - void dump(std::string_view header, CppSourceLocation loc = CppSourceLocation::current()) const { + void dump(std::string_view header, [[maybe_unused]] CppSourceLocation loc = CppSourceLocation::current()) const { if (is_error()) { fmt::print("\e[31;1m{}\e[m", header); std::visit( @@ -171,10 +171,12 @@ template class [[nodiscard]] ErrorOr : publi }, *this ); +#ifndef __EMSCRIPTEN__ fmt::print("\e[m\n"); fmt::print(" at {}\n", CppSourceLocation { location() }); fmt::print(" ...\n"); fmt::print(" at {}\n", loc); +#endif } } @@ -211,7 +213,7 @@ template class [[nodiscard]] ErrorOr requires(std::is_base_of_v) bool is(T const& t) { @@ -12,5 +14,6 @@ is(T const& t) { return dynamic_cast(&t); } +#pragma GCC diagnostic pop } diff --git a/EssaUtil/Stream/File.cpp b/EssaUtil/Stream/File.cpp index 7b70324e..2fc429e6 100644 --- a/EssaUtil/Stream/File.cpp +++ b/EssaUtil/Stream/File.cpp @@ -89,7 +89,7 @@ OsErrorOr ReadableFileStream::read(std::span data) { // TODO: Buffering auto result = ::read(fd(), data.data(), data.size_bytes()); if (result < 0) { - return OsError { .error = static_cast(-result), .function = "FileStream::read_all" }; + return OsError { .error = static_cast(-result), .function = "FileStream::read_all" }; } if (result == 0) { m_eof = true; @@ -115,7 +115,7 @@ OsErrorOr WritableFileStream::write(std::span data) { // TODO: Buffering auto result = ::write(fd(), data.data(), data.size_bytes()); if (result < 0) { - return OsError { .error = static_cast(-result), .function = "FileStream::write_all" }; + return OsError { .error = static_cast(-result), .function = "FileStream::write_all" }; } return static_cast(result); } diff --git a/EssaUtil/Testing.hpp b/EssaUtil/Testing.hpp index 18904db3..c471e4e8 100644 --- a/EssaUtil/Testing.hpp +++ b/EssaUtil/Testing.hpp @@ -16,6 +16,8 @@ using namespace Util; template struct FormatIfFormattable { T const& t; + FormatIfFormattable(T const& t_) + : t(t_) { } }; namespace fmt { diff --git a/EssaUtil/Tests/CMakeLists.txt b/EssaUtil/Tests/CMakeLists.txt index ff992009..ed1e266d 100644 --- a/EssaUtil/Tests/CMakeLists.txt +++ b/EssaUtil/Tests/CMakeLists.txt @@ -7,7 +7,10 @@ essautil_add_test(GenericParser LIBS Util) essautil_add_test(Matrix LIBS Util) essautil_add_test(RAIIUtils LIBS Util) essautil_add_test(Stream LIBS Util) -essautil_add_test(Threading LIBS Util) +if (NOT EMSCRIPTEN) + # FIXME: Implement this + essautil_add_test(Threading LIBS Util) +endif() essautil_add_test(UString LIBS Util) essautil_add_test(UStringBuilder LIBS Util) essautil_add_test(UnitDisplay LIBS Util) diff --git a/EssaUtil/Threading/ThreadPool.hpp b/EssaUtil/Threading/ThreadPool.hpp index 772d7380..3326bca1 100644 --- a/EssaUtil/Threading/ThreadPool.hpp +++ b/EssaUtil/Threading/ThreadPool.hpp @@ -12,6 +12,10 @@ #include #include +#ifdef __clang__ +# error todo: implement this +#endif + namespace Util { template class MutexProtected { diff --git a/EssaUtil/UString.cpp b/EssaUtil/UString.cpp index 7a54f859..7c54b69d 100644 --- a/EssaUtil/UString.cpp +++ b/EssaUtil/UString.cpp @@ -298,11 +298,17 @@ template<> OsErrorOr UString::parse() const { return parse_impl( template<> OsErrorOr UString::parse() const { return parse_impl(std::stold, *this); } std::strong_ordering UString::operator<=>(UString const& other) const { +#ifdef __clang__ + return std::lexicographical_compare(m_storage, m_storage + m_size, other.m_storage, other.m_storage + other.m_size) + ? std::strong_ordering::less + : (*this == other ? std::strong_ordering::equal : std::strong_ordering::greater); +#else return std::lexicographical_compare_three_way(m_storage, m_storage + m_size, other.m_storage, other.m_storage + other.m_size); +#endif } bool UString::operator<(UString const& other) const { return (*this <=> other) == std::strong_ordering::less; } -bool UString::operator==(UString const& other) const { return (*this <=> other) == std::strong_ordering::equal; } +bool UString::operator==(UString const& other) const { return size() == other.size() && std::ranges::equal(span(), other.span()); } bool UString::operator>(UString const& other) const { return (*this <=> other) == std::strong_ordering::greater; } UString operator+(UString const& lhs, UString const& rhs) { diff --git a/cmake/utils.cmake b/cmake/utils.cmake index fb071492..6d37a6f5 100644 --- a/cmake/utils.cmake +++ b/cmake/utils.cmake @@ -44,18 +44,28 @@ function(essautil_setup_target targetname) if (ESSA_IS_PRODUCTION) set_target_properties(${targetname} PROPERTIES INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/lib") endif() + if (EMSCRIPTEN) + target_link_options(${targetname} PRIVATE "SHELL:--embed-file ${Essa_SOURCE_DIR}/assets") + endif() endif() target_include_directories(${targetname} PUBLIC ${PROJECT_SOURCE_DIR}) + if (NOT EMSCRIPTEN) + set(GCC_OPTIONS + -Wno-error=stringop-overflow # FIXME: fmt on CI doesn't like it for some reason, find a way to workaround it! + -Wno-error=restrict # FIXME: This breaks compilation of EML::value() and some more places + ) + endif() + target_compile_options(${targetname} PRIVATE -fdiagnostics-color=always -Wall -Wextra -Werror -Wnon-virtual-dtor -Wno-error=missing-field-initializers # FIXME: This is buggy (?) for *DrawOptions -Wno-error=format # FIXME: We don't use formatting anyway except SimulationClock but this breaks mingw build - -Wno-error=stringop-overflow # FIXME: fmt on CI doesn't like it for some reason, find a way to workaround it! -Wno-error=deprecated-declarations + ${GCC_OPTIONS} ) set_property(TARGET ${targetname} PROPERTY CXX_STANDARD 20) @@ -107,11 +117,15 @@ function(essa_resources targetname dir) set(outfile ${CMAKE_CURRENT_BINARY_DIR}/EssaResources.cpp) file(WRITE ${outfile} "extern \"C\" { const char* ESSA_RESOURCE_DIR = \"") if (ESSA_IS_PRODUCTION) - file(APPEND ${outfile} ${CMAKE_INSTALL_PREFIX}/${DEST_PATH}) + set(resource_dir ${CMAKE_INSTALL_PREFIX}/${DEST_PATH}) else() - file(APPEND ${outfile} ${CMAKE_CURRENT_SOURCE_DIR}/${dir}) + set(resource_dir ${CMAKE_CURRENT_SOURCE_DIR}/${dir}) endif() + file(APPEND ${outfile} ${resource_dir}) file(APPEND ${outfile} "\"; }") target_sources(${targetname} PRIVATE ${outfile}) + if (EMSCRIPTEN) + target_link_options(${targetname} PRIVATE "SHELL:--embed-file ${resource_dir}") + endif() endfunction() diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index 72ef7854..26ffed1f 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -18,7 +18,9 @@ add_example("essa-gui/image-widget") add_example("essa-gui/listboxes") add_example("essa-gui/message-box-multiline") add_example("essa-gui/multiple-windows") -add_example("essa-gui/passthrough" LIBS Xfixes X11) +if(NOT EMSCRIPTEN) + add_example("essa-gui/passthrough" LIBS Xfixes X11) +endif() add_example("essa-gui/progressbars") add_example("essa-gui/rich-text") add_example("essa-gui/scrollable-container")