From 999686a896c19563edb03f082ed9ee3b7d77f6bc Mon Sep 17 00:00:00 2001 From: Emil <65846814+emil28092005@users.noreply.github.com> Date: Fri, 18 Sep 2026 03:40:15 +0300 Subject: [PATCH] Checkpoint 2: integrate native Editor, MCP, gameplay builds and standalone export --- .clang-format | 9 + .gitattributes | 2 + CMakeLists.txt | 37 +- README.md | 2 +- apps/editor_gui.cpp | 110 ++ apps/editor_main.cpp | 172 +++ apps/player_main.cpp | 296 ++++ apps/schema_exporter_main.cpp | 35 + assets/fonts/NOTICE.md | 8 + assets/fonts/NotoSans.ttf | Bin 0 -> 2049096 bytes assets/fonts/OFL.txt | 93 ++ assets/fonts/source.json | 10 + assets/ui/dark.json | 16 + assets/ui/editor-layout.json | 19 + cmake/Assets.cmake | 6 +- cmake/Authoring.cmake | 2 +- cmake/BuildService.cmake | 10 + cmake/EditorCommands.cmake | 8 + cmake/EditorUI.cmake | 15 + cmake/Player.cmake | 24 + cmake/Plugins.cmake | 33 + cmake/Runtime.cmake | 17 +- cmake/Tutorials.cmake | 14 + cmake/UI.cmake | 59 + dependencies.lock.json | 16 + docs/IMPLEMENTATION.md | 57 +- docs/manual/editor/extensions.md | 58 + docs/manual/editor/mcp.md | 85 ++ docs/manual/getting-started/build.md | 20 +- docs/manual/index.md | 2 +- docs/manual/scripting/api.md | 70 + docs/manual/scripting/examples.md | 50 + docs/manual/scripting/first-behavior.md | 67 + docs/manual/scripting/index.md | 57 +- docs/manual/scripting/lifecycle.md | 80 +- docs/manual/scripting/physics.md | 49 + examples/extensions/beacon/Beacon.hpp | 28 + examples/extensions/beacon/Editor.cpp | 119 ++ examples/gameplay/Gameplay.cpp | 85 +- examples/gameplay/Gameplay.hpp | 2 +- examples/tutorials/following/Gameplay.cpp | 43 + examples/tutorials/following/Gameplay.hpp | 7 + examples/tutorials/following/scene.json | 126 ++ examples/tutorials/moving/Gameplay.cpp | 31 + examples/tutorials/moving/Gameplay.hpp | 7 + examples/tutorials/moving/scene.json | 74 + examples/tutorials/physics/Gameplay.cpp | 43 + examples/tutorials/physics/Gameplay.hpp | 7 + examples/tutorials/physics/scene.json | 148 ++ examples/tutorials/spawning/Gameplay.cpp | 70 + examples/tutorials/spawning/Gameplay.hpp | 7 + examples/tutorials/spawning/scene.json | 58 + include/faset/assets/asset_data.hpp | 71 + include/faset/assets/asset_pipeline.hpp | 72 +- include/faset/authoring/schema.hpp | 52 +- include/faset/authoring/service.hpp | 57 +- include/faset/authoring/templates.hpp | 12 +- include/faset/authoring/transforms.hpp | 8 + include/faset/core/error.hpp | 21 +- include/faset/core/hash.hpp | 2 +- include/faset/core/io.hpp | 5 +- include/faset/core/json.hpp | 4 +- include/faset/core/process.hpp | 38 + include/faset/editor/build_service.hpp | 55 + include/faset/editor/commands.hpp | 31 + include/faset/editor/editor_ui.hpp | 28 + include/faset/editor/mcp.hpp | 32 + include/faset/editor/plugin_api.h | 42 + include/faset/editor/plugins.hpp | 24 + include/faset/editor/session.hpp | 69 + include/faset/player/SceneView.hpp | 37 + include/faset/render/render_graph.hpp | 16 +- include/faset/render/renderer.hpp | 85 +- include/faset/runtime/Runtime.hpp | 26 +- include/faset/ui/ui.hpp | 183 +++ licenses/README.md | 9 + licenses/freetype.txt | 169 +++ licenses/harfbuzz.txt | 42 + licenses/json.txt | 6 + mkdocs.yml | 10 + shaders/baseline.slang | 9 +- src/assets/asset_data.cpp | 203 +++ src/assets/asset_pipeline.cpp | 1000 +++++++++---- src/authoring/schema.cpp | 275 ++-- src/authoring/service.cpp | 638 +++++--- src/authoring/templates.cpp | 238 ++- src/authoring/transforms.cpp | 156 ++ src/core/hash.cpp | 140 +- src/core/io.cpp | 140 +- src/core/process.cpp | 427 ++++++ src/editor/build_service.cpp | 747 ++++++++++ src/editor/commands.cpp | 157 ++ src/editor/editor_ui.cpp | 1553 ++++++++++++++++++++ src/editor/mcp.cpp | 175 +++ src/editor/plugins.cpp | 358 +++++ src/editor/session.cpp | 358 +++++ src/player/SceneView.cpp | 378 +++++ src/player/scene_io.cpp | 32 + src/render/math.cpp | 99 +- src/render/render_graph.cpp | 31 +- src/render/renderer.cpp | 1618 ++++++++++++++++++--- src/runtime/Physics.cpp | 272 +++- src/runtime/Physics.hpp | 14 +- src/runtime/Runtime.cpp | 925 +++++++++--- src/ui/font.cpp | 171 +++ src/ui/text.cpp | 196 +++ src/ui/ui.cpp | 1149 +++++++++++++++ tests/assets_pipeline.cpp | 314 +++- tests/authoring_tests.cpp | 212 ++- tests/blender/generate_fixture.py | 28 + tests/build_service_tests.cpp | 289 ++++ tests/core_tests.cpp | 64 +- tests/editor_ui_tests.cpp | 190 +++ tests/mcp_stdio_test.py | 84 ++ tests/mcp_tests.cpp | 76 + tests/plugin_tests.cpp | 87 ++ tests/render_tests.cpp | 148 +- tests/runtime_player_tests.cpp | 184 +++ tests/runtime_tests.cpp | 379 ++++- tests/runtime_tutorials.cpp | 103 ++ tests/ui_render_test.cpp | 115 ++ tests/ui_tests.cpp | 239 +++ tools/project_templates/Gameplay.cpp | 71 + tools/project_templates/Gameplay.hpp | 7 + tools/verify_blender_roundtrip.py | 82 ++ 125 files changed, 16086 insertions(+), 1714 deletions(-) create mode 100644 .clang-format create mode 100644 apps/editor_gui.cpp create mode 100644 apps/editor_main.cpp create mode 100644 apps/player_main.cpp create mode 100644 apps/schema_exporter_main.cpp create mode 100644 assets/fonts/NOTICE.md create mode 100644 assets/fonts/NotoSans.ttf create mode 100644 assets/fonts/OFL.txt create mode 100644 assets/fonts/source.json create mode 100644 assets/ui/dark.json create mode 100644 assets/ui/editor-layout.json create mode 100644 cmake/BuildService.cmake create mode 100644 cmake/EditorCommands.cmake create mode 100644 cmake/EditorUI.cmake create mode 100644 cmake/Player.cmake create mode 100644 cmake/Plugins.cmake create mode 100644 cmake/Tutorials.cmake create mode 100644 cmake/UI.cmake create mode 100644 docs/manual/editor/extensions.md create mode 100644 docs/manual/editor/mcp.md create mode 100644 docs/manual/scripting/api.md create mode 100644 docs/manual/scripting/examples.md create mode 100644 docs/manual/scripting/first-behavior.md create mode 100644 docs/manual/scripting/physics.md create mode 100644 examples/extensions/beacon/Beacon.hpp create mode 100644 examples/extensions/beacon/Editor.cpp create mode 100644 examples/tutorials/following/Gameplay.cpp create mode 100644 examples/tutorials/following/Gameplay.hpp create mode 100644 examples/tutorials/following/scene.json create mode 100644 examples/tutorials/moving/Gameplay.cpp create mode 100644 examples/tutorials/moving/Gameplay.hpp create mode 100644 examples/tutorials/moving/scene.json create mode 100644 examples/tutorials/physics/Gameplay.cpp create mode 100644 examples/tutorials/physics/Gameplay.hpp create mode 100644 examples/tutorials/physics/scene.json create mode 100644 examples/tutorials/spawning/Gameplay.cpp create mode 100644 examples/tutorials/spawning/Gameplay.hpp create mode 100644 examples/tutorials/spawning/scene.json create mode 100644 include/faset/assets/asset_data.hpp create mode 100644 include/faset/authoring/transforms.hpp create mode 100644 include/faset/core/process.hpp create mode 100644 include/faset/editor/build_service.hpp create mode 100644 include/faset/editor/commands.hpp create mode 100644 include/faset/editor/editor_ui.hpp create mode 100644 include/faset/editor/mcp.hpp create mode 100644 include/faset/editor/plugin_api.h create mode 100644 include/faset/editor/plugins.hpp create mode 100644 include/faset/editor/session.hpp create mode 100644 include/faset/player/SceneView.hpp create mode 100644 include/faset/ui/ui.hpp create mode 100644 licenses/freetype.txt create mode 100644 licenses/harfbuzz.txt create mode 100644 src/assets/asset_data.cpp create mode 100644 src/authoring/transforms.cpp create mode 100644 src/core/process.cpp create mode 100644 src/editor/build_service.cpp create mode 100644 src/editor/commands.cpp create mode 100644 src/editor/editor_ui.cpp create mode 100644 src/editor/mcp.cpp create mode 100644 src/editor/plugins.cpp create mode 100644 src/editor/session.cpp create mode 100644 src/player/SceneView.cpp create mode 100644 src/player/scene_io.cpp create mode 100644 src/ui/font.cpp create mode 100644 src/ui/text.cpp create mode 100644 src/ui/ui.cpp create mode 100644 tests/blender/generate_fixture.py create mode 100644 tests/build_service_tests.cpp create mode 100644 tests/editor_ui_tests.cpp create mode 100644 tests/mcp_stdio_test.py create mode 100644 tests/mcp_tests.cpp create mode 100644 tests/plugin_tests.cpp create mode 100644 tests/runtime_player_tests.cpp create mode 100644 tests/runtime_tutorials.cpp create mode 100644 tests/ui_render_test.cpp create mode 100644 tests/ui_tests.cpp create mode 100644 tools/project_templates/Gameplay.cpp create mode 100644 tools/project_templates/Gameplay.hpp create mode 100644 tools/verify_blender_roundtrip.py diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..5f4d143 --- /dev/null +++ b/.clang-format @@ -0,0 +1,9 @@ +BasedOnStyle: LLVM +IndentWidth: 4 +ColumnLimit: 100 +AllowShortFunctionsOnASingleLine: Empty +AllowShortIfStatementsOnASingleLine: Never +AllowShortLoopsOnASingleLine: false +BreakBeforeBraces: Attach +PointerAlignment: Left +SortIncludes: CaseSensitive diff --git a/.gitattributes b/.gitattributes index ac0fa13..bce4344 100644 --- a/.gitattributes +++ b/.gitattributes @@ -3,3 +3,5 @@ licenses/*.txt -whitespace *.png binary *.ttf binary + +assets/fonts/OFL.txt -whitespace diff --git a/CMakeLists.txt b/CMakeLists.txt index ce1bbb5..7fca85d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -27,7 +27,7 @@ else() endif() include(cmake/Dependencies.cmake) -add_library(faset_core STATIC src/core/hash.cpp src/core/io.cpp) +add_library(faset_core STATIC src/core/hash.cpp src/core/io.cpp src/core/process.cpp) target_include_directories(faset_core PUBLIC include) target_link_libraries(faset_core PUBLIC nlohmann_json::nlohmann_json Threads::Threads) target_compile_definitions(faset_core PUBLIC FASET_VERSION="${PROJECT_VERSION}") @@ -50,7 +50,21 @@ endforeach() if(FASET_BUILD_RENDERER AND EXISTS "${PROJECT_SOURCE_DIR}/cmake/Renderer.cmake") include(cmake/Renderer.cmake) endif() -foreach(module UI Editor Applications) +if(TARGET faset_gameplay AND EXISTS "${PROJECT_SOURCE_DIR}/cmake/Player.cmake") + include(cmake/Player.cmake) +endif() +if(TARGET faset_authoring AND EXISTS "${PROJECT_SOURCE_DIR}/cmake/EditorCommands.cmake") + include(cmake/EditorCommands.cmake) +endif() +if(TARGET faset_assets AND EXISTS "${PROJECT_SOURCE_DIR}/cmake/BuildService.cmake") + include(cmake/BuildService.cmake) +endif() +if(TARGET faset_editor_commands AND TARGET faset_build_service) + include(cmake/Plugins.cmake) + add_library(faset_editor_session STATIC src/editor/session.cpp) + target_link_libraries(faset_editor_session PUBLIC faset_editor_commands faset_build_service faset_assets faset_editor_plugins) +endif() +foreach(module UI EditorUI Editor Applications) if(NOT FASET_BUILD_EDITOR) continue() endif() @@ -59,8 +73,27 @@ foreach(module UI Editor Applications) endif() endforeach() +if(TARGET faset_editor_session) + add_executable(faset_editor apps/editor_main.cpp) + target_link_libraries(faset_editor PRIVATE faset_editor_session) + target_compile_definitions(faset_editor PRIVATE FASET_ENGINE_SOURCE="${PROJECT_SOURCE_DIR}") + if(BUILD_TESTING) + find_package(Python3 COMPONENTS Interpreter REQUIRED) + add_test(NAME editor_mcp_stdio COMMAND ${Python3_EXECUTABLE} ${PROJECT_SOURCE_DIR}/tests/mcp_stdio_test.py $) + set_tests_properties(editor_mcp_stdio PROPERTIES TIMEOUT 60) + endif() + if(TARGET faset_editor_ui) + target_link_libraries(faset_editor PRIVATE faset_editor_ui) + target_link_libraries(faset_editor PRIVATE faset_stb) + target_compile_definitions(faset_editor PRIVATE FASET_HAS_EDITOR_UI=1) + target_sources(faset_editor PRIVATE apps/editor_gui.cpp) + endif() +endif() + if(BUILD_TESTING) add_executable(faset_core_tests tests/core_tests.cpp) target_link_libraries(faset_core_tests PRIVATE faset_core) add_test(NAME core COMMAND faset_core_tests) endif() + +include(cmake/Tutorials.cmake) diff --git a/README.md b/README.md index 7cf7403..5f99c7a 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ Faset is an independent engine project for desktop **2D and 3D games on Linux and Windows**. Its priorities are a custom editor that is comfortable to use by hand and through MCP, integration with Blender, and a path toward advanced graphics. -**Current status: MVP implementation is in progress.** Native core, authoring, physics runtime, asset import, and renderer subsystems are being integrated and tested. The complete editor and game export workflow are not yet ready. See the [implementation checkpoints](docs/IMPLEMENTATION.md) for observed results; a technology appearing in the plan does not mean it is complete or benchmarked. +**Current status: MVP implementation is in progress.** The native Editor, shared GUI/MCP authoring, C++ gameplay builds, Vulkan Player, and standalone export are integrated and under acceptance testing. Linux GPU workflows work; complete cross-platform acceptance and the two finished example games remain in progress. See the [implementation checkpoints](docs/IMPLEMENTATION.md) for observed results; a technology appearing in the plan does not mean it is complete or benchmarked. ## Start here diff --git a/apps/editor_gui.cpp b/apps/editor_gui.cpp new file mode 100644 index 0000000..05705a1 --- /dev/null +++ b/apps/editor_gui.cpp @@ -0,0 +1,110 @@ +#include +#include +#include +#include +#include +#include +#define STB_IMAGE_WRITE_IMPLEMENTATION +#include + +namespace faset::editor { +namespace { +std::string base64(const std::vector& bytes) { + constexpr char alphabet[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + std::string out; + out.reserve(((bytes.size() + 2) / 3) * 4); + for (std::size_t i = 0; i < bytes.size(); i += 3) { + const auto a = bytes[i]; + const auto b = i + 1 < bytes.size() ? bytes[i + 1] : 0, + c = i + 2 < bytes.size() ? bytes[i + 2] : 0; + out += alphabet[a >> 2]; + out += alphabet[((a & 3) << 4) | (b >> 4)]; + out += i + 1 < bytes.size() ? alphabet[((b & 15) << 2) | (c >> 6)] : '='; + out += i + 2 < bytes.size() ? alphabet[c & 63] : '='; + } + return out; +} +std::vector png(render::Renderer& renderer, std::array rectangle) { + const auto width = renderer.width(), height = renderer.height(); + const auto pixels = renderer.pixels(); + int x = std::clamp(static_cast(rectangle[0]), 0, static_cast(width) - 1), + y = std::clamp(static_cast(rectangle[1]), 0, static_cast(height) - 1); + const int w = std::clamp(static_cast(rectangle[2]), 1, static_cast(width) - x), + h = std::clamp(static_cast(rectangle[3]), 1, static_cast(height) - y); + std::vector cropped(static_cast(w) * h * 4), encoded; + for (int row = 0; row < h; ++row) + std::copy_n(pixels.begin() + (static_cast(row + y) * width + x) * 4, + static_cast(w) * 4, + cropped.begin() + static_cast(row) * w * 4); + const auto writer = [](void* context, void* data, int count) { + auto& out = *static_cast*>(context); + auto* begin = static_cast(data); + out.insert(out.end(), begin, begin + count); + }; + require(stbi_write_png_to_func(writer, &encoded, w, h, 4, cropped.data(), w * 4) != 0, + "capture.encode", "Cannot encode editor screenshot"); + return encoded; +} +} // namespace +int run_editor_ui(Session& session, bool enable_mcp, std::uint64_t max_frames, + const std::filesystem::path& capture) { + render::Renderer renderer({1440, 900, + "Faset — " + session.project().value("name", std::string("Project")), + false, true}); + const auto font = session.config().engine_root / "assets/fonts/NotoSans.ttf"; + const auto theme = session.config().engine_root / "assets/ui/dark.json"; + EditorUI ui(session, renderer, font, theme); + McpServer server(session.commands()); + StdioTransport transport; + session.commands().add( + "faset_editor_capture", + "Capture the Editor or its authoring viewport as a PNG image. Requires the graphical " + "Editor and Vulkan; never captures a Player process.", + Commands::object_schema( + {{"path", {{"type", "string"}}}, {"viewport_only", {{"type", "boolean"}}}}), + [&](const Json& arguments) { + session.poll(); + ui.frame({}); + renderer.render(ui.snapshot()); + auto region = + arguments.value("viewport_only", true) + ? ui.snapshot().scene_rect + : std::array{0, 0, float(renderer.width()), float(renderer.height())}; + if (region[2] <= 0 || region[3] <= 0) + region = {0, 0, float(renderer.width()), float(renderer.height())}; + auto encoded = png(renderer, region); + const auto relative = + arguments.value("path", std::string(".faset/screenshots/editor.png")); + atomic_write( + project_path(session.config().project_root, relative), + std::string_view(reinterpret_cast(encoded.data()), encoded.size())); + return Json{{"path", relative}, + {"mimeType", "image/png"}, + {"width", static_cast(region[2])}, + {"height", static_cast(region[3])}, + {"image_base64", base64(encoded)}}; + }, + true); + std::uint64_t frame = 0; + while (!renderer.should_close() && (max_frames == 0 || frame < max_frames)) { + if (enable_mcp) + for (const auto& line : transport.poll()) { + try { + const auto reply = server.handle(Json::parse(line)); + if (reply) + transport.send(*reply); + } catch (const Json::exception&) { + transport.send(server.parse_error()); + } + } + session.poll(); + ui.frame(renderer.poll_events()); + renderer.render(ui.snapshot()); + ++frame; + std::this_thread::sleep_for(std::chrono::milliseconds(1)); + } + if (!capture.empty()) + renderer.capture(capture); + return renderer.stats().validation_errors == 0 ? 0 : 2; +} +} // namespace faset::editor diff --git a/apps/editor_main.cpp b/apps/editor_main.cpp new file mode 100644 index 0000000..547a437 --- /dev/null +++ b/apps/editor_main.cpp @@ -0,0 +1,172 @@ +#include +#include +#include +#include +#include +#include +#include +#ifdef FASET_HAS_EDITOR_UI +#include +namespace faset::editor { +int run_editor_ui(Session&, bool, std::uint64_t, const std::filesystem::path&); +} +#endif +#ifdef _WIN32 +#define NOMINMAX +#include +#endif + +namespace { +volatile std::sig_atomic_t interrupted = 0; +void interrupt(int) { + interrupted = 1; +} +std::filesystem::path executable_directory(const char* argument) { +#ifdef _WIN32 + std::wstring path(32768, L'\0'); + const auto length = GetModuleFileNameW(nullptr, path.data(), static_cast(path.size())); + if (length == 0 || length >= path.size()) + throw std::runtime_error("Cannot locate Editor executable"); + path.resize(length); + return std::filesystem::path(path).parent_path(); +#else + std::error_code error; + const auto path = std::filesystem::read_symlink("/proc/self/exe", error); + return error ? std::filesystem::absolute(argument).parent_path() : path.parent_path(); +#endif +} +void help() { + std::cout + << "Faset Editor\n" + " faset_editor --project PATH [--new NAME --dimension 2|3] [--scene RELATIVE_PATH]\n" + " faset_editor --project PATH --mcp [--gui]\n" + " faset_editor --project PATH --command JSON [--wait]\n" + "Options: --engine SDK_SOURCE, --headless, --frames N, --capture PATH.ppm\n" + "MCP uses JSON-RPC over stdio and only exposes authoring/editor services.\n"; +} +} // namespace +int main(int argc, char** argv) { + using namespace faset; + using namespace faset::editor; + try { + std::filesystem::path project, engine = FASET_ENGINE_SOURCE, scene, capture; + std::string new_name, command; + int dimension = 3; + bool mcp = false, gui = true, explicit_gui = false, wait = false; + std::uint64_t frames = 0; + for (int i = 1; i < argc; ++i) { + const std::string arg = argv[i]; + auto value = [&]() { + require(i + 1 < argc, "cli.argument", "Missing value for " + arg); + return std::string(argv[++i]); + }; + if (arg == "--help" || arg == "-h") { + help(); + return 0; + } + if (arg == "--project") + project = value(); + else if (arg == "--engine") + engine = value(); + else if (arg == "--new") + new_name = value(); + else if (arg == "--dimension") + dimension = std::stoi(value()); + else if (arg == "--scene") + scene = value(); + else if (arg == "--mcp") + mcp = true; + else if (arg == "--gui") { + gui = true; + explicit_gui = true; + } else if (arg == "--headless") + gui = false; + else if (arg == "--command") { + command = value(); + gui = false; + } else if (arg == "--wait") + wait = true; + else if (arg == "--frames") { + const auto text = value(); + require(!text.empty() && text.find_first_not_of("0123456789") == std::string::npos, + "cli.frames", "Frame count must be positive"); + frames = std::stoull(text); + require(frames > 0 && frames <= 10000000, "cli.frames", "Frame count out of range"); + } else if (arg == "--capture") + capture = value(); + else + throw Error("cli.option", "Unknown option: " + arg); + } + require(!project.empty(), "cli.project", "Use --project PATH to select a project"); + require(!(mcp && !command.empty()), "cli.mode", "Choose MCP or a single command"); + if (mcp && !explicit_gui) + gui = false; + Session session({std::filesystem::absolute(project), std::filesystem::absolute(engine), + executable_directory(argv[0])}); + if (!new_name.empty()) + session.scaffold(new_name, dimension); + const auto settings = session.project(); + if (scene.empty()) + scene = settings.value("start_scene", std::string()); + if (!scene.empty() && + std::filesystem::exists(project_path(session.config().project_root, scene))) + session.authoring().open(scene); + if (!command.empty()) { + const auto request = Json::parse(command); + auto result = session.commands().call(request.at("name"), + request.value("arguments", Json::object())); + if (wait && result.contains("job")) { + const auto id = result.at("job"); + const auto started = std::chrono::steady_clock::now(); + for (;;) { + session.poll(); + result = session.commands().call("faset_job", {{"id", id}}); + const auto state = result.value("state", std::string()); + if (state == "succeeded" || state == "failed" || state == "cancelled" || + state == "conflict") + break; + require(std::chrono::steady_clock::now() - started < std::chrono::minutes(30), + "job.timeout", "Command wait exceeded 30 minutes"); + std::this_thread::sleep_for(std::chrono::milliseconds(20)); + } + } + std::cout << result.dump(2) << '\n'; + const auto state = result.value("state", std::string()); + return state == "failed" || state == "cancelled" || state == "conflict" ? 1 : 0; + } + if (gui) { +#ifdef FASET_HAS_EDITOR_UI + return run_editor_ui(session, mcp, frames, capture); +#else + throw Error("editor.gui_unavailable", + "This build has no graphical editor; use --mcp or --command, or build with " + "FASET_BUILD_EDITOR=ON"); +#endif + } + require(mcp, "cli.mode", "Headless mode requires --mcp or --command"); + std::signal(SIGINT, interrupt); + std::signal(SIGTERM, interrupt); + McpServer server(session.commands()); + StdioTransport transport; + while (!interrupted && !transport.closed()) { + for (const auto& line : transport.poll()) { + try { + const auto reply = server.handle(Json::parse(line)); + if (reply) + transport.send(*reply); + } catch (const Json::exception&) { + transport.send(server.parse_error()); + } + } + session.poll(); + std::this_thread::sleep_for(std::chrono::milliseconds(5)); + } + return 0; + } catch (const Error& error) { + std::cerr << error.json().dump() << '\n'; + return 1; + } catch (const std::exception& error) { + std::cerr << Json{{"code", "editor.failure"}, {"message", error.what()}}.dump() << '\n'; + return 1; + } +} diff --git a/apps/player_main.cpp b/apps/player_main.cpp new file mode 100644 index 0000000..ec5c60d --- /dev/null +++ b/apps/player_main.cpp @@ -0,0 +1,296 @@ +#include "Gameplay.hpp" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#if defined(_WIN32) +#define NOMINMAX +#include +#endif + +namespace { +std::filesystem::path executableDirectory(const char* argument) { +#if defined(_WIN32) + std::wstring path(32768, L'\0'); + const auto length = GetModuleFileNameW(nullptr, path.data(), static_cast(path.size())); + if (length == 0 || length >= path.size()) + throw std::runtime_error("Cannot locate Player executable"); + path.resize(length); + return std::filesystem::path(path).parent_path(); +#else + std::error_code error; + auto executable = std::filesystem::read_symlink("/proc/self/exe", error); + return error ? std::filesystem::absolute(argument).parent_path() : executable.parent_path(); +#endif +} +std::uint64_t count(const std::string& value) { + if (value.empty() || value.find_first_not_of("0123456789") != std::string::npos) + throw std::invalid_argument("Frame count must be a positive integer"); + auto result = std::stoull(value); + if (result == 0 || result > 10000000) + throw std::invalid_argument("Frame count out of range"); + return result; +} +faset::runtime::RuntimeConfig simulationConfig(const nlohmann::json& scene) { + faset::runtime::RuntimeConfig config; + if (!scene.contains("simulation")) + return config; + const auto& settings = scene.at("simulation"); + if (!settings.is_object()) + throw std::invalid_argument("simulation must be an object"); + config.fixedDelta = settings.value("fixed_delta", config.fixedDelta); + auto boundedInteger = [&](const char* key, int fallback, int maximum) { + if (!settings.contains(key)) + return fallback; + const auto& value = settings.at(key); + if (!value.is_number_integer()) + throw std::invalid_argument(std::string(key) + " must be an integer"); + // Check before narrowing, so very large unsigned values cannot wrap into + // a valid configuration on a platform with a narrower unsigned type. + const auto numeric = value.get(); + if (numeric < 1 || numeric > maximum) + throw std::invalid_argument(std::string(key) + " is out of range"); + return value.get(); + }; + config.maxCatchUpTicks = static_cast( + boundedInteger("max_catch_up_ticks", static_cast(config.maxCatchUpTicks), 1024)); + config.physicsSubsteps = boundedInteger("physics_substeps", config.physicsSubsteps, 128); + if (settings.contains("gravity")) { + const auto& gravity = settings.at("gravity"); + if (!gravity.is_array() || gravity.size() != 3) + throw std::invalid_argument("gravity must contain three numbers"); + config.gravity = gravity.get(); + } + return config; +} +void validatePackagedShaders(const std::filesystem::path& directory) { + for (const auto* name : {"vertexMain.spv", "fragmentMain.spv", "shadowMain.spv"}) { + const auto path = directory / "shaders" / name; + if (!std::filesystem::is_regular_file(path)) + throw std::runtime_error("Packaged shader is missing: " + path.string()); + const auto bytes = faset::read_text(path); + if (bytes.size() < 20 || bytes.size() % 4 != 0 || + static_cast(bytes[0]) != 0x03 || + static_cast(bytes[1]) != 0x02 || + static_cast(bytes[2]) != 0x23 || + static_cast(bytes[3]) != 0x07) + throw std::runtime_error("Packaged shader is not a SPIR-V module: " + path.string()); + } +} +} // namespace +int main(int argc, char** argv) { + try { + std::filesystem::path scenePath, assetsPath, capturePath, controlPath; + bool headless = false, validateOnly = false; + std::uint64_t maximumFrames = 0; + std::set options; + for (int i = 1; i < argc; ++i) { + const std::string arg = argv[i]; + if (arg == "--help") { + std::cout << "faset_player [--scene PATH] [--assets CACHE] [--frames N] " + "[--headless] [--capture PATH.ppm] [--validate] [--control PATH]\n" + "No --scene: open scene.fscene beside the executable. CACHE contains " + "assets//.\n" + "Headless uses offscreen Vulkan; --frames uses the configured fixed " + "simulation delta.\n" + "--validate checks scene/resources on CPU without gameplay callbacks " + "or Vulkan initialization.\n" + "--control is an optional editor mailbox for pause/resume/step/stop, " + "without world queries.\n" + "Keys: A/D horizontal, W/S vertical, Space jump, E interact, P pause, " + "N single-step, Escape quit.\n"; + return 0; + } + if (!options.insert(arg).second) + throw std::invalid_argument("Repeated option: " + arg); + auto value = [&]() -> std::string { + if (i + 1 >= argc) + throw std::invalid_argument("Missing value for " + arg); + return argv[++i]; + }; + if (arg == "--scene") + scenePath = value(); + else if (arg == "--assets") + assetsPath = value(); + else if (arg == "--capture") + capturePath = value(); + else if (arg == "--control") + controlPath = value(); + else if (arg == "--frames") + maximumFrames = count(value()); + else if (arg == "--headless") + headless = true; + else if (arg == "--validate") + validateOnly = true; + else + throw std::invalid_argument("Unknown option: " + arg); + } + if (scenePath.empty()) + scenePath = executableDirectory(argv[0]) / "scene.fscene"; + scenePath = std::filesystem::absolute(scenePath).lexically_normal(); + if (assetsPath.empty()) + assetsPath = scenePath.parent_path(); + if (!std::filesystem::is_directory(assetsPath)) + throw std::invalid_argument("Asset cache directory does not exist: " + + assetsPath.string()); + if (headless && maximumFrames == 0) + maximumFrames = 1; + const auto document = faset::player::readScene(scenePath); + const auto config = simulationConfig(document); + const auto executableRoot = executableDirectory(argv[0]); + if (scenePath.extension() == ".fscene" && + std::filesystem::equivalent(scenePath.parent_path(), executableRoot)) + validatePackagedShaders(executableRoot); + if (validateOnly) { + if (!capturePath.empty() || !controlPath.empty()) + throw std::invalid_argument("--validate cannot capture or control a running game"); + faset::runtime::Runtime validator(config); + validator.load(document); + faset::player::SceneView view(assetsPath); + view.build(document, 16.0f / 9.0f); + for (const auto& diagnostic : view.diagnostics()) { + if (diagnostic.starts_with("error:")) + throw std::runtime_error(diagnostic); + std::cerr << diagnostic << '\n'; + } + std::cout << nlohmann::json{{"validated", true}, + {"dimension", document.value("dimension", 3)}} + .dump() + << '\n'; + return 0; + } + faset::runtime::Runtime world(config); + faset::gameplay::registerGameplay(world); + world.load(document); + faset::player::SceneView view(assetsPath); + faset::render::Renderer renderer( + {1280, 720, document.value("name", std::string("Faset Player")), headless, true}); + std::set held; + bool stop = false; + std::uint64_t frames = 0; + std::size_t logCursor = 0; + std::set reported; + std::uint64_t controlSequence = 0; + std::string previousControl; + auto previous = std::chrono::steady_clock::now(); + while (!stop && !renderer.should_close() && + (maximumFrames == 0 || frames < maximumFrames)) { + faset::runtime::InputState input; + bool singleStep = false; + if (!controlPath.empty() && std::filesystem::is_regular_file(controlPath)) { + try { + if (std::filesystem::file_size(controlPath) > 65536) + throw std::runtime_error("control message exceeds 64 KiB"); + auto content = faset::read_text(controlPath); + if (content != previousControl) { + previousControl = content; + const auto message = nlohmann::json::parse(content); + const auto& sequence = message.at("sequence"); + if (!(sequence.is_number_unsigned() || + (sequence.is_number_integer() && sequence.get() >= 0))) + throw std::invalid_argument( + "control sequence must be a nonnegative integer"); + const auto value = sequence.get(); + if (value > controlSequence) { + const auto command = message.at("command").get(); + if (command == "pause") + world.setPaused(true); + else if (command == "resume") + world.setPaused(false); + else if (command == "step") { + world.setPaused(true); + singleStep = true; + } else if (command == "stop") + stop = true; + else + throw std::invalid_argument("unsupported control command"); + controlSequence = value; + } + } + } catch (const std::exception& error) { + const std::string message = + std::string("Player control ignored: ") + error.what(); + if (reported.insert(message).second) + std::cerr << message << '\n'; + } + } + for (const auto& event : renderer.poll_events()) { + using Type = faset::render::Event::Type; + if (event.type == Type::Quit) + stop = true; + if (event.type == Type::FocusLost) + held.clear(); + std::string key = event.key; + std::transform(key.begin(), key.end(), key.begin(), + [](unsigned char c) { return static_cast(std::toupper(c)); }); + if (event.type == Type::KeyUp) + held.erase(key); + if (event.type == Type::KeyDown) { + held.insert(key); + if (key == "ESCAPE") + stop = true; + if (!event.repeat) { + if (key == "SPACE") + input.jumpPressed = true; + if (key == "E") + input.interactPressed = true; + if (key == "P") + world.setPaused(!world.paused()); + if (key == "N") + singleStep = true; + } + } + } + if (stop) + break; + input.horizontal = float(held.contains("D") || held.contains("RIGHT")) - + float(held.contains("A") || held.contains("LEFT")); + input.vertical = float(held.contains("W") || held.contains("UP")) - + float(held.contains("S") || held.contains("DOWN")); + const auto now = std::chrono::steady_clock::now(); + const double elapsed = maximumFrames + ? config.fixedDelta + : std::chrono::duration(now - previous).count(); + previous = now; + if (singleStep && world.paused()) + world.singleStep(input); + else + world.advance(elapsed, input); + auto snapshot = view.build(world.snapshotJson(), static_cast(renderer.width()) / + std::max(1u, renderer.height())); + for (const auto& diagnostic : view.diagnostics()) { + if (diagnostic.starts_with("error:")) + throw std::runtime_error(diagnostic); + if (reported.insert(diagnostic).second) + std::cerr << diagnostic << '\n'; + } + while (logCursor < world.diagnostics().size()) + std::cerr << world.diagnostics()[logCursor++] << '\n'; + renderer.render(snapshot); + ++frames; + } + if (!capturePath.empty()) { + if (frames == 0) + throw std::runtime_error("No frame was rendered for capture"); + renderer.capture(capturePath); + } + const auto stats = renderer.stats(); + std::cout << nlohmann::json{{"frames", frames}, + {"ticks", world.snapshot().tick}, + {"dimension", document.value("dimension", 3)}, + {"device", stats.device}, + {"validation_errors", stats.validation_errors}} + .dump() + << '\n'; + return stats.validation_errors == 0 ? 0 : 2; + } catch (const std::exception& error) { + std::cerr << "Player failed: " << error.what() << '\n'; + return 1; + } +} diff --git a/apps/schema_exporter_main.cpp b/apps/schema_exporter_main.cpp new file mode 100644 index 0000000..396816c --- /dev/null +++ b/apps/schema_exporter_main.cpp @@ -0,0 +1,35 @@ +#include "Gameplay.hpp" +#include +#include +#include + +int main(int argc, char** argv) { + try { + std::filesystem::path output; + for (int i = 1; i < argc; ++i) { + const std::string argument = argv[i]; + if (argument == "--help") { + std::cout << "faset_schema_exporter [--output PATH]\nExports declarative gameplay " + "schemas without creating a world.\n"; + return 0; + } + if (argument == "--output" && i + 1 < argc && output.empty()) + output = argv[++i]; + else + throw std::invalid_argument("Unknown, repeated or incomplete argument: " + + argument); + } + const auto types = faset::gameplay::schema(); + if (!types.is_array()) + throw std::runtime_error("Gameplay schema() must return a type array"); + const nlohmann::json manifest{{"format", "faset.schema"}, {"version", 1}, {"types", types}}; + if (output.empty()) + std::cout << manifest.dump(2) << '\n'; + else + faset::atomic_write_json(output, manifest); + return 0; + } catch (const std::exception& error) { + std::cerr << "Schema export failed: " << error.what() << '\n'; + return 1; + } +} diff --git a/assets/fonts/NOTICE.md b/assets/fonts/NOTICE.md new file mode 100644 index 0000000..41c351b --- /dev/null +++ b/assets/fonts/NOTICE.md @@ -0,0 +1,8 @@ +# Noto Sans + +The Faset Editor bundles Noto Sans under the SIL Open Font License 1.1. +The unmodified font and complete license are `NotoSans.ttf` and `OFL.txt`. + +Source: [google/fonts, Noto Sans](https://github.com/google/fonts/tree/a54f7446f84a1125ef6bf08baa46f3639e8905e0/ofl/notosans). +The source path, exact commit and SHA-256 are recorded in `source.json`. +This font is an Editor asset; exported Players do not require it. diff --git a/assets/fonts/NotoSans.ttf b/assets/fonts/NotoSans.ttf new file mode 100644 index 0000000000000000000000000000000000000000..75575046c015ff623a848096a15779867ba71453 GIT binary patch literal 2049096 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 z

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

e$xgDQgCU*h?mBk#=nZ`fRh0`vZx0N- zan&`=16{%g`-75X4|(A65?X`%mp_y}UfiW3)WB5N#!Q9SRq5O|=eOz+yNQ{mI-$nX z(BSPh*V`wfPh9a?>DPuLoyXsvUobsC&pv2avi6t5)k~o(yZ=uRI?Bd$_2r!*+_guO zBIjsW;@Bap_wue~YshVjWJtt0b-ZylRvM_(ssu%Z?%?6qL%B=+wQX9bqpqWXZxd7A1;~v^AIIB;f_gs0qIig7WfzV7vN!p+flxencecIyY9jz zK}Zd|E%eq~p+BJT!iq|u3~zFSKs`a#a2^_nv92j`K9WhY3Cs-H{>&%>Ait+?${RT+ zTyX!8W)?L4Q6Aby{xfd!<5#pL*7E)ErO!y z{KbWH>N7KjG&+FOowi9-yo$jyoWh30voJCPn!&a9Sb+|P;Zbaum(mEB*f0Iz<@pJZ z^wxy*=2lz+@P{R)n_xO@-LFY6OYc9-wo5ngpFK$Z{~C+Z53jfzh@m_ogTYr$6^p1C zz+15QP_bV4)r;R;9It+J^v$IcFK+zx=x?weKmM5{J;=1u3I3CfWc-iiAFMnV0Ky4I zKu>p!)5U8t3=ZkfGC2@nL$CZfv@2bI7hHfD9k$loT5nBefhO6Qo@I9b1GIsCc@2g7 z*7Ay4g`!>%jTip2-~&jq#6>WaIH#xceB-BgTV^H>?l)Se1%u_p;ym6xsnhv?KfUhc zKL5jPJ8*mf`TI~X)~y9B0%1lvzPxjyNqPisye3Tjozg3@si$?oCwzRRODMpEdui&~@$x@MBCl_J{kzeJ9-^70nZ~?IPf8zSVi&*?x1-rq`l^jDKYYiFInsHB z?K|Z*w@Ak`TUuzH$qh<(zRI2?euOV8(JKEkBoZ~LN9#z7K?)4o{9wzU>jUuyk`xleK!89(l)FBXnSFGeEF z5gC5)!FTDn;w6%<)Ec}l2x23uQwwN^^JtD7v0J(WiOQH+Ku3%$AK};$Jn~-nFAPim z2I2`QUX7YV>Y{^*_e7)@ss0|R8rh4SNsAw&0r+>g3VaIIEL-0gClB@)HtPN6fqf&T zuC9f~s@4L|p54ZRh7EOwhRiAHfhb#H7l~rUhW&lv10yAxw2?H8wKdw*9BnBO71C3} zIm?%zLC&lJn#?nmWbOOYIknufT5H#K?d|YQ*B8|pb7~8nwRt0B8TO2b1d!ctvl>BB zf8LgL3|pamh0-L^2swG4$5rdkf};#!tfY;}_D~GZlsqP@zR8nqCi;LoDRRiW;)p@_ z;j~+L(%~=6EHdgH87bymjeE#pZYvx*XS6JM<&MI}EK|D2*f{1hH*W7rH>Tz}v-4|$ zF7KFU+E7|xv>Ve6#il~HiS@Vd95JbraU+aEDdrkeQflW9jhuCNG*vyIOeq=I*|~5* zt0>sUHhS7;n=CcE=KUiTxmE41s`0MeoX!Xa=U;hMm<7Z1)LlG8dL)93JVmmo=u#*QS;^^r z=k*7+^_P4<*Hcu}Z^-Vi1socmq$0ZN8;l<=u2ab?eT??x0KpMtyzgYJ!Gd7toW$*O z8)gD_|E|%h4J9SxO}nn^t(?4Y%)h0i$QC|{(~Fs8>qai>;s=t^ubmz~vgpgn9>|m- z28-yzTyzVOs;BCfpVLq_8qp7Oe#U7}C}U+ObxY{p)7G)Kr*y!SXA0!kb=mD9Z$&Ua zul=M>UD$YVe$#o4+*Ec)gMp|!OEZLnOXP@x4FLg#PSGf3C&o{7tRo7Dx|hIzgmc2- z<>xu)$zJJ3$S+UtfmQ@I0<{7^?8o;FPmCPH{Y%n8(jb1(8}kUSK|#aG4MQL4#+=~Yf5Q31Zm z6~}ju9(`x=!G{*!x&HcZ44c@4(rs*B>dzmhY?OGbq+p4wT4qA)?Bib^xg>JgrN5ln zt;+>eSY8%b`SP2=W5w;a`xtaKW|Hoee#5Dk1rcqIQNZVba|gPZ5ec~@qkmX(-O){tKe%-H zWt$$ndg!5to_mgEG1c+o(uY5Vl;*P}cE=kB6XVP{CM^EE{MyfjwAYXuITfERfQ986T9^o%Z`L$mi?l)S2~ySc_j($jbN~_54mC=n`gd9R-;n&J zBHFmQb!m6BCDb$ry@c9)m=$N6XCuraooH;x(R1CT4+Eb^C&)^WEAz>f!80pI_xl9x z@Z?D4WXtGu#OLvhmV@>l>Enmqwb&+l{_}@bmDXHZ1qfW?NKJHz0Wm@r4*8&BpqCWY z1|u0Ao3?j3Tm0jVmS~{2#npp!0Gw1iGzR4j*BL8AmDIV0#=GxS=+oH@s_jFy$><*s z)^?z8RISPmmLP-G03eJi_6f<6{QANs;7pH3A~o)&f_i9NNZ!}yC!cc$o9sURgu6nx z_6k*=o;nMO%M~j)pRh#ujs~EJ3urTy4PPR#E!aETFKSx; zP}#6^q;ja!TE2T^`!z#qlfNrj)i0{^@^q=5kzK*+;Rd^ceQj2FHhRle@8}s#Y5LSr zts#8F);3?ZJzZ_pnN1@HMoUK^hnx3a1U{RCXp1d^4PJ_>)jq|kvwVbo0<{`=;*GPD2kCwks8?1mq?<)O*M1_8z-PP6PN_oae`rq zQ7ls#$G?(u9R;X~heh0X#qI;kRcGAGTuEst2YVgq-~{6F6g>xs$M5i$YkdL`+js<@ z$8$=9d{yhCP2k71IAzLIRrp}Iw6t%j(G9(?t)whelUp2`_1hZ^(WtS`{L3Beyt0uq zddAKfjv407)6LD1hWuo;^jmC|FI(F3-$LuK(uE9cTpJQlG0Htdbd*6-%77%m z0zt@VS!ycs8;w3&No!HrNK;mI_T=RMF1*~gr`57>pdmA3AU&&WD%2S%RV$wtOdo&z zHuDo4Hf(f+&>iQEAd8FwF5rI5pj?-DYaDY#*tF2Ibtw8fwN|H1);QZB9W`nB+5$(m zTBX$+QrRUVV2{GN{&UXW<_gYLtCjsqbxm)PW#OV53Gi7BwY~>~$;Dt++gWV{XTdi1 z_Do=^CGusYSp~{9h+@c4=M-6tS!x#Sla|54KlAO=Yeg~0grdIFZ(N8?4{p?;n56Xt z@~zn$!o{KeLsczSYpY{sK4x}w?Y=6Mo<5wOe)c&mMGg#M?ij&K(8o{K#|08MLxd92 zt9?d;&)U!;{T9}Ueaf_Oc3q}sC@pJh>+{?y;e8A73^0hM*my}f=cb8p@nY}Rp|}l1 zWLqt z41&2kH90YsAkm@^v-D?ADb2KKolCRCn$}6PiNST!Z28THnBva$(hLTmcm;X{SELO{ zfFel;F9!&eryrU$0B6{j2ojL7vBNJaUOKeUvu${a;l1J=fCARkx^)t+x8P`jT=+hg zRpoVOE?*s^5^Q}wSA5w*E+8OH#;>84NO3sF4C z$S0y)>c1fl1nuDlE6$xRjn^tx3U&y@yZC#ESQ$i^_!w{f2L7C4HyCfdhn}PL%ceuwTqW*7`tR+?ev{{?BO$-m%m@XYp8!$6NW(0zRT2U1$GVI z^G?t$9l}G@Igp@PoJ!3ioYGh~#O88S-q`=VnE8KpTxM(HS(=3t*xH~Xes z_sUDWZW%v{O8-Kx`=`Xb9UuohiL?N5{upzEuW>c!#f+7=sY2P?eMmZleA-kSpND|`#R-Md=!+7WGTNx!$g%hvK< zAI3?#)%A3DG{qAGReB)lQ9e%6m`rrDD~}%rg8D(Cid>qg!b^jOQwgPsDim!D8XBmy zd=D&2la|HjXEQG?2Lz$Cd=G5WcFk&O;aNoABXA4fj)e{3{S1FE*Y+9AHa?HlcIRq2 z)JEl~?R5G!N9^PC_anJcqG#ltx zD@|13r9lNlLTRd-mrmOL;#z4!#g^+Hjjg+rU<}ykG?nfL-2=Se->06SZeVERc{5hl z2OLBECF%)bh+}Pl@$u6Fxa@FR5Hm06q+om;itxztb0jBa$4)o98H`5(rbzl1kGp2URPdGoKz%_FQ(K+o^{P^!ee}3+{KV$lFe!;mO zN2IlJdx^k?fX;{YCA(W#@T&dZvp4OEKDxA}E$kfMI@hq+Ot89xj9D8?gUwiTw9&J; zan_Bsg=%4(m19^1Fg~DcQTT#OD&ilA;j9L=coH{7OK5D3~Zk$?NXc;t`N7{Nf zdkZ^v4Rl7o(l$|E&{A3DH+{Ro*XV!ikKyeV&f*I9ObAw*mAR#h^O`+n4Hj!n{w-*q zZh7{?|Lr7)S3>(-QFS7|4E>Pfr4a20Kb?=d5jVeUoq|x&UhkbUdwQxot;L#bPnT!Y zf&Fu(O%<6crkH#SD34tu?X2}b1AT$^8*Z)XtumR)^YbdqS6p`aRfeJ*jYs>O^z!!2 zn>WwQ>6W%*jv!q`H#~4Y%$0n`N6k zSwVv@vTd%izpfy^cA#cqwtb?azqxVJS((>8F8p`paBc5ox+1xvyT;+MW;O+W`^Lh8 zv1Xvo>9c8jZOs&Ko7-%#Wus3{OxmyDegld034P*5H186Ti5q4o9|b+%6shr6*lH|{ z4L@$zD=7uXWYYqmf4cZ{2pK= z6E!FlInsR)T=clTrZAIe;A?W2S831Wh+ zTe#OPN>T;rUKm{B!xv_pk;#Ts*jMNCM^2k=nDYKok(!2oN{y=(G|5QM(-zpXlU3Sm z*i&ac5~y!(quF*&bh9564~-1#pz=u@gIq_j z=2jIGZe_jZsrPszrmC(gcdsY+3!k*MnjUUzX$yRT&#I}q*TZs7VR-#jyamH1V{Sb! zARTkn&e`LGDiqmshv2xrEb@T!ReCku`|lU=TBBl-Fe3DJ7!GT zgF189XQ#$5?rqrIj;4rT4r1%ki8|!or!~d-fP;-J7qrcH%$(mAJiMuKwxpnNLse+T zJ+;)-W50u0>}?A{d+@x8@$);g^_>|xp4q_6UT3fp&7`22(?R$gGy{69Q7OLUd_vyK z^?qOd)Q;(fY2UAe<6$X8G=C|!jvfo6mTc701_}XbVSOzzT9ecJ``@Uo_xL7F)!kJ{ z?aRAcF!e}(474=2-?+9gj0C~P0e?Z{DpUrh6Qe8l>O*M7nQ+1>1YC{WX;#NtyrZ23 z)uofI!NJOCaP!i({fm*(zEHvcW9>@-8?Wm8`+iB2HobBmZSFKj(<4oDwN2YJZPKQ9 zJ4esyTnsYpUAS!sU9;~aY%jzn-tD-I{xB`lb$D%7bs0*kx{eQmi z_e+{ij~RFWD75|Mm-oK!``-KBN6WGF;?=1$m!cC*o#zP8Y8{6DdS_Q6(CrvaX9fqW z^tC&6x{l?((PfpqA~+O|&a{DLHA55m7r_lp1nUA|42=HMz!d;n&*-e`c zc4y!|u-GEN>%*34eSOpt)_A>jd(@3yjbC4{o;OD8J1&~d|6=zNGtDq#{^df`(V3TJ zGEI}o)TF7_1zU~A)}XHXm?h{`*&>Fw9{kad*7qd+0l*_=!zOFt;B|9%-`3zMkqKUs zJPK1nNvZ6Tw%F{NEulVga4(8wo5HEq_KB8jZ(Qn*1;+80J`ifJa`mC*hKYdiot8s1uh|WynSeK$17L`OotQ&yXYp&^o#!*3_jYs?lp*&o2 zV!qJU(O55QD!17i3@RKe{aIU}{|OHRx+Zja5T@Tbb_w3-?wGzsi4f86TOD`ZDF z@Iz%YrwzR9G&hCiPPwL2?ar@Hy|(-pPWw*4nxut!K0+l?(jU6m$a zG6ghMx?qd(Hs~$2+FFx2)XRVT<&`bA3-{(?zJw7}=Q-Uaoc4BQPJ3lXPjRVUIn@gD ze|O4FD=;O>q~aD*zsQte+!;mL4>GBU%!$f4kfqeePzoLSR__oH-&Q1puOVp1T;}9n z8PV(}RfI`UVgasVBC>IhpDiC98XlI%%G;WK(Q-qr%cBkJtaWqeZn2}c^b8O6Hks@F z2Xu|j+A2$nmyiTL35tv^P{_^V9=lDDhZ@O&!^x!>h?El?5>~B~`@N{=!<7)Cxoc0-)8?ibc zbahIfTDKb@9Ap?dC8Ky|-7*IMS}t)@awyXqFq!>#+1n-VkQBMYueaWk3pvo4vZ>Pp z`n1W+`U|n;T24iEe!SJ1@}D~8#uWL%y#;>2Cd%H1_LM~NOO=(M7x}>iY~1uIoEP}^ z0jM%)NQ6&e{NT@L`SS!+9|l#>SC*5W&x!8?hbOp-!{3K0GmF{8Y-lEn!DZ0O4SERv zJ4w2WbQqx|P{2h=_=gxSSd93%x6M-?S2i|#tu+l5l?}R{fs3+;0l8CHnC5*}61?}y zP-;ZUG}bQR1z%G|Y`4N>GOGmvj_sEJLg$s((mvjKMQp{Ao5`U83oVobj=%+Rp=<`S z9kEL?J1}%x6&I>tGvJdl?l5SViJBP}x}9EzUVsMaf9yRaqUw5;Y&L)4T5G@U6ftxl z{P84O$8o@#B#j`-9VOdpU)v-0om&ES{&oo7QssJJ3q%8Tl!S3&4Rzb-F$m%=qVAq8 zbrlv{hq`U_sv_zfw5O%0+Xe_IQ`@5M_ALRsU^~ohsX=XnIUG?zFX>IFKDSXA-<0F& zO0dXgPpMptti$GMsYyk=(p{;PbfbPE45tYqDC)L2W@D!W`||COeL4!!7q>pKoHR&k zP-3%1ZO+?D@xJ@CwS>8K_&*J;XC3yLr0NWkM|C6iHwE;R*dIS_;Lq7^7f!9;d~%CD zDDWY!)ev7HtpZ6`C8w{}EzLQ)@%>R0|%hsofxE_;o$I#@|jb$Js;hvH6= z*EYeNoFGu%0uQzvOaN(*n8quVdJ35wA{fpsqz>&pJ4N)j)qkOUL z#DY_x^3^RF^0p}5(t?|pZ;4t_l!!|F@c#ff$M8K{0=_M#x0EFE(|--dw_)Tb7yT(; zUl#JjmVBK3<93I5OL=2kj3XXL@Rwrze+M{W{JyOLKWn?Qy`=Z*Z^C3Y zmqJc)-k&%nhyUhwyKowE%F5y?Zh&8sT>d{Ti{FN&Q!eYO?e^$21ecYMoa%l^l1ndf zh|?4aPDSXkTc>Hx-IiLNQo320JmsE=rrrNfi!1EeX)f*^+wI*c#hsP+ZMAcdcR2s% z@(%QHF7JSUb9v|Ul3F?~_<1p2;^QO_5g%8u(fy>ggA>WT^lc$c-zq!KJVj;p7W$Sj zAU-d9T9Ovlzdu;^!%g2GEW4@XeK<13@uB5^V(oo$WQybCIV|o)c%WR1??btMbnSgo zuKD{=uBXJer>U-Q;ccw#lYA7C@lb2GFgl*k^XH3rjt~*ZI-RsCJinJepTctk!a03q zc#l6v{tpB+6wMW`ck^wF%X`x^zJ*QXnaM&$ z-S8YL>c$ajEAWcCD6GvbAzR3zrV>wSA-o(Aun%ki;BqRr8}Ik@BW$9(wSoYOT z-ybX!W2MFMN#>>iuFd61)LV#9vCz#*7PFshSnWfb7ct(5`1}{QEo&@p!c%+`aAYwkU4dAiHtt%jJFhzazR3(u`{L!7^`-404?h<^{ouU1~o!L!y z26uo8K^NY}9e9874xoN>VK?y{R!+Q6p$n8<>Er4O-5HFA=VEv+-5Clirst2Z{t>4Z z|DY=w?Is0eZ@QaEWRxK=Nfu%6+<=<%kX^a>+k+c-YUN4FwM1&WhW#U^;nVYdL4@7r z)0A&h%8#ABVdngOg|4ghwPM%Rs9CDt=d7}Ba$QdD!&)vI66B_48?_=9u|P&bQu378 z6EXBOh132WFBgzb{e^RTcN5tR<;Z0$TmW?lRw1@fY9u4lE204WU*?Kl`%kws*YiR*IjDsCx$%76w)x z$(g*ykv+?rGmoCPfB#v}_XBPf%Dx~+7x2M;fjfOA=r8TI8bS6ug}d>bbC0qsj}U#N z5U6&*?WCYPgwyz_3K}AoBybVKqeQt!QUEEOM=To+L6kT2Wjg_Iol=_`AD@5jIhjyy znobR#kw_ex$_)>Xb`4n5Dnp|oBP|G z4YZB~d(NNG>>G7W47~HEJ(-ACD}6(q>7~&4XpgVc zfzFAO$?jz2XTS^WK)k4s)KijdlM);y^B-W3Ogr z(kg&ywtM-!_QhKc9gkjq_4IJ_&c3V0RGnv}*_-+AcJA%kd&R`?U|U!H)st!9Wd|11 zip3ZxHcuLJt92M??17PUlJiCQyUxnd+1NcWgZAiq*sK3|GVlkFDE3o8Fqv(Wh=arB zDvi3Q_+K&5RLsOtDE^S#9cbFwHgR5$qi;`N`;4ox>Fo55t9CR^-leLoo2*u6Z&(;O zHWo0~jU&GAz&m!G^WkNTPx|}kWs6drom3gvVBlHwYt(rk`Q)|ofS@mDHqn|mmLp6sY@VTD>oaCA!Xl>Fpl zO0lT11XwY?l2UkCiOPiU#M1ls`Z*8IE_~#8^__R7u9&@a-KCp;;Nr_axMSju z+xK0WTzLi)f$$^wg$j+Bkk?iSuaAKsmIm0T-gRBC7FO#g>Jmdpi&I z{CJ9D?1lPdd#Vp(5h4*|k4%K%I#eQp9fb$^m>X#?(+v>88VL4*@}mDA%Rj+BJWQlF zW!+7rcX*f%>Yl4pAiD~K$*6qS=t>2ry32djhmKvi52sZq8(M8ZYd9(+Pa=jyEY}j5 zP-Bk!xp=0jnByFm>RzCE1*#$riSQ>{1Z_YAcf?W(NVWA>=EE`NP!X)d_?oM^6Pq9Z)s zWvpoor<qkIGMN(%qe^uVq1Bj(9J&F+|5og}p4Oi1Z(*q$%oOfX6r zfMD?~u?Z~juZc_T9=$Bk9N3xe8E>BLKXCZSr3aS0W5bTta|RAwnb^D7mhnc<6rOE% z^ftJ=W=t1;K@FdAda$?-*m>o+4RbqYD9tG`>V<)t00oGjpyBuxBLPz-v( zfkXo46@$a&*x0Ei|oF#KXH72XrSQ(Z*(6YJO6K{=0AL? zH|r>&39(6ySqyhpDW9Fre^94g`0#}nd}yh%LPJCW5*TXK zuHnTI1Ext@RtRq!+TR}QjHl}7LG2alaMIa3)700W?wvoTYMRS@APr?CmH%(y%^&Lm zYBalUn$3QoKRqG^%4| zldtNd_&)LaV<@TJP`dX@CHgW@`8Y8X9YuGVH0DaBwX()m{~^|R_8U`+i}e}Xl@?#4 z@QhqOB(OTiSMtZ$>_q+zWS#$wYqIfPhmF9aJi{7Lcqh-HC{T3Zj1Y+&cO?qnQtmnS z_}jWhk+%qfTw%6Ue*DPuublmb-nsg?u)?W#y)*wubyQbrbErQ1i~P6#9Q#+{!nQsq zW~sw1{R1|Q?lvu)SUm>aJv1~A@$ujQ+m-*sK>k78p+DoO+l4$Gbwm=QOeU`!qvYAG zh)znFlqm8|p?wnf^P@1e--Ebgnc}}pXY0nfErFeUmz%4lZP z(Zp>dqSA_GtBf@c=TUYI+Aj*iuCwwtP!~vh&k3bsT(0nhWR{grS2xEx&FpTpew;C- zhP`<^y8M8kQaQ#t@CXIFk;~)UgHT8Y#hoWR&hyAO_7GP*$$*V=kX&xVaTKdAuk*){ zB}*ZEDlm2F#MEUI{_MNX9=X8pIGhl16V2%A8&-Z3IxsfAzpZWm*x13)x=QAumQYLU z{)v1!`^(Uf-O+YYrlhbr=c{VrEx_&Jg+$hyc25nLQ0wZOk4JW=JY8pxL}wlKNgr4GocdqizuO7iA`&u zf}@*BC_HJzqk)D%Oc#YfOGT9beAjihf%B$!J!PHpCy4 z%4&vFj^W~UpVmb+CZDnQs^z6?QYf>jiRykRJAf;ne^IKf8DH+%a~}5T!0P)^IEPXt zLC4Bvyx2fNXHh71=zBnN1~9>1fBfBxi^mo&?hK|IpUVIH+_ZN*dH4|Xe^vO#q1MGr z*LZ79{>$v*>|m&~KK}-8W(cJD58(ZfQAObfk)fLi$>34EsHP;Lv%1XTZc|&ft$)hX zn2U8CYjhv(nY<{~u_x7?v1bN@lWwbTQFyjxrYqRr;n$#}na2~gI@GgjQ~N@H=V;7i z^tCsJx{T@xtr1|f0u1!`p-5G10#`^;+*jm660zcpvJ{A)r5D=*qfvjnvtVU1M_t63DgFlg(WLo!;g!q9#Y}kVc0a zjA$0v7$GLJ^GQrzeG?k>y&&uj#q>C-Iz&NjK#C|=VIk`gl<0-*yR@m>Au_UfeM{Eg zn(j6wnv5E&!LJuqpuMi-h_4MQD~Zb;NrkNuXU>cc3pF+`Fd*shBo(Y_MKP35r+7PL zr=i`kXl3A>IRVA&B{BEKWRX{wTcbhC_=G3=zymD-eXyqM1kXygG#plY`@^g==(*^s zO#U0;kW&8l{aMULia9DOpaAa1D@OTaD~H##Zua0y!c~?v{d#KUW)AP`usN*IB`v)+ z#F!)qC1Hv{r@cF2YO1MhH92e#JP`5%#@eVkINUNm;T(`|gxkGaf{}2POB2`w9T^hg zB*O=Z0T5dV8w6x=9(KWC=Es8RC8wjts8V@OjO`G#?5h3Fsa(t9O9#f!OJdGBFyk9>wV-H8+B6^r#o$^2 zT_glxgT8>A$yn9Mq-{~%5^R~tMy)=p!BbP)?&!~W29_^YrLLMssm$!;LSuCAwfF95 za#bnDDyoP2_J8KSi&B_}4r~(K#Xx&WiPWO>D$2QF?V8`BEZTMYcBkI1s?b+e)YT|H zNOn5ZM{~5=mGTj}T&b?ke=<)sc3}d81mWi88;jJC-PSRqfqd_-u@#n z;ebrK8YkU4Sw=3^0wvJ+X$7gc@bJ0$*97yx2ZlbG z>Hf!|2Qr`oQYj3mMqdG1MHSwQb0g-!i-&{`jti0AV)nKqO|h{9S9T4a+xHCnr~E&B zYcf0&+JB(q{I=G!RlR2>#}7q>r-!G%k#-IyveOpS$e>laL1TUnIH95!%me5bRXR4Y z7j6%5PF>VHa6#rpc7OicFD84IA}y1V8ZnU`5*g7|Iq6m=?Ufh^`LP& z3~$Bo|AOIRvgATH&Uc|QvRKUnSVgfJ&h-n57ESh_@m*oZ^hmJFt#01goBUk<_w3d$ zMyC?i`p$*^<`y;DgwI&5Gbb#uCRf5$Yj1NlcbIw~8SVd&P#+p-3Fcz9YD1mDVyc<0 zQ3DRlkE&`bB!o%oGv7>uxSKJYA>!g>`N2t&_brAEmP7CPDLbAIy!7SQY{tHh(6BdD z-#03(G=rN=wG8E7l@EE1+w1~|dJ^a?SgnfV z1DTv06&dmmy7xLvor8^mv~PT3F~=@^!M+E)IwL9Ll$hp8ClU1Y81Uj3dLyZtENOWz$ebQnDXbS1NGZ@SJ@N&wa9Y;SDAJ`yzfao*eR3 zJm*>;ZoX(;C)J0v^cZV;AO4x7|6rip{#^clSQUP(V94C+@5@l73-&HK7sU@C8|D}2 zJn18{fPZ_T43f!zOy=Tl82bF3(3lFJFAFb-p9_EF--qc*Zsea2^Y1SUN2JdIJmx#F zI)K88RFgbJ&&yhcYU#OJ_!r@)#pe^!bKskOj+RVe>UbYkuEIF7zvJUTcjM!{Sr|w5 zI3GuRK7sGjyckF3;Lm5oanQV!p5q_nrWVqMu+Fk``8vhIN`-VG1sluJ+YH#=$=`0F zQP|k(^Yr%W5AZxl4rawGc#gMuhgq)H@VCjCO=JH9ADhf`Yffyuy_d#@&Ik7_K?1`W zfBOUcZE{Q+xXXK99QzO@EQxQwjw4bBp$oWVAoi32S<;fY_&cKUh#jp{9t9!)p9x(< zgHC6)ep}zrpvTXzt@G=?K0N#mbA7$ZR9|l{{9JkW2G_1!a_wd$SV(2t29~XyykFl4 z&b=pld1aYRK>E;Tj@|->kg=^oPP>~2_ksIHP;6M~QF2+7%Myx6$?u!tiFKN~)Mr(7 zbeoa^phyRlJw`u)vWM59>mKW{Tczy?Yp*Fq7$I)uwJni$L;|lHQsF7V+X8i~TLO6g z$p{o)-V(_4wrKQ#;MrkK?!)F%#uoD8pzw<5{Hw6pU(?dA?WymyG<4SY>B6nmw{DBn z+fD5uU5&=q(BRY5=tAwL8~zI9QllpVdf=}BdJ7yg<*DG_i0c95(1BJ1a@%y^tVmv=>wmCUl`zf%LEdlHCQ(~u3 zf04@UmAwOqLV-EfUJxo!hYW4L|4n*cYolG{{HBBs>Mgnzu+T#jCy!j2CrLQxM4`8 z92uUResK6YjY%?QjzE$P@T^7Xu8{<{lb33)qy$3IPr$wm`GM3q$ydiUBQl~fU2M0# zym}~+s=erF_W_^paChfm^`n0e)x^3pfxL)IFK$h_MuwWYeOlL$;0`nmuY7H|cU+^H z(HmWk;k3qA)fDKvZ08ksjJEFXT|TI9O1G*rvrUkQNPc=Zmx$oTC27u&&HDx=6ykf%lJC*xQfQ)&jbB8w6~4{YErO0K$|MU8 z@U@8b9P@zDE@X-;hmXe5miFcu83nN0#PH3l^5*IMoY7mU7Wu?Jk{1b6?-)Q1h>hm5f${@c8ZfmQk-s19qbJ5`{3o| z!O$nh-9s~;U02Tp-2K9H(Q|eV-hAD~;a|$Wc)%XEPIev1<{$Gc9K9sfIpP%&B;3aj zfhhhDmVK8mm>f^MpDLBE0D=a~Zre=!NB`AB{QdRfKlNozmArp1Ho1|;Q5|P}CGY6+33dWMhBRT$vm@gh8HDh%NV7%sj~@Qd#sXJSQ3QRN}{>2eU>pt9h7#9s;f`1mmi z56gUfHQ;$Szv37d?_VMq`TKOq_i^~e_m8s#e}5N$pT-y8KVEi%zkiZag>mlT@2^*? zX#Ay;_X&QkgaOX;O5UgONeLtPX?`kt4PIt z@&eFq+{kwirWj6gd68Wx#kg&p#!mXeIh;ZSilY$RV^rw>nh21@I zesXbgab&59Zog@0hwxnDlI4{_;mPIY_?g-Kg7EYnN1Fu#Kw|Yi?wXH*lEOBChLO~> zTZ~&J<22Me@HC2dAtHv|fzASrnA>HsNib`##U0Wg+^9yqS=h_vHI-HB3R$_feK>aL ziqe>vd8Ja@9O|(2rv1Bz%zljmm+ZGvbPW4SXIn!IL5%(61uZA92ASOP z10q0yD$}o644LI?gHt7)&Sh}9 z%L_h$(*-Cne15+@+2m|C%r|s4wei9i z_1DG*?Dm1!wb#c-TC3|4J34#z^t(p(?wHxLXJ*G><(jBNd~a$ZOc;WE9W8gWa%JGL{#l{kMz|pU$j&1IOEsVze-f3ySgtCk{Bv zP$wvCloNk8S@ttd97JY8$%vfzB!`3B~_6kO{qS-v;DE z+n`xk-UxDDy%m;=A^_bIE&{Mg*1~UzC<4$e;UWNT$+I~1h4fKTm2{E!<78#{qyUhU z({JgV7ZgjjcRS>ls+TK&JSEmeE%UDhsc@7F$|bAY2D!3Q)iR&j2CGDS;#~U>L-5DT z_HwL>A^4Sq{>uTz#2c3`)&=yOGy18YSbe~A#{ZG*fh=S;Hw2Xu7tzLNm=9)I!e4m+W=Jyn8Y}N z0wigI-6N(?EN0F`__4SG0A9BGS>amXn>u7dZD44-xX~Q-hx|)} z%zfeJmMG!Px1N*@u2gI^K~ZqpXVDOaM)!zgE72-S637a1f>N_W3Jn%Qe4>TT!sEq0 zc;aLiZxR{5*8Q%X{g_Yb5~q|&!WSK(O}gFvIREG%Tex7W9(S0qQ}(sD@>}$_;~`}T za{30ASP3Rc5)>H&P&#@k|JEYwWH?oMwESGTWg3@X1$?+9Y;#BLOF%6`T_OR z@M(+kCV>oRwkTpE9C;0@8+*oEYpcUu9_Gxy#xBVJ+#hpSRoFsKy`!$ib;2_gZSi-r z_hkn1=P7-uX3U_#3>0?*=O%kU^hw06>3CchR5oZy+%Q4`6jWFIOR%b$+Q*`cEyIz9 zzKkgm*SkE2g=gD#_jpG#J!VWfP#cW(d!ngoV_mM^j&Z9o?t6gm(s6NtPa1bQq;JVZ z=UcMvmY$TUBaCtP2yTq)MtL#w!T0b{lYJO<0Hc!Yu}nZ5F)mpn1;lZ0GiB9qon%9f z61Q9GL`vo{9N4kro435v(c7{vJ?Wl%!~~^}PqOb!9So+ME7s>F%}(xHOH5KhANdYH zrcfy9m?}l`w9e0|68?Rr)KA9_PEH;^*&he7g&6F96g5_`qx36GVV{NYPS+f(WazQ5 zuAtD<&!(R}Tw1cGc)rCtRYde(5~_tbbX^B06ttV$)cBJ5nTa)SQ%B|{9GGswy+x^* zygVSZ2M~?)nbiTN1WsUnf?uwv5>YGw?l6xwQ=p?xW39STZ)vse*s(Y>)3)oMdCac9 zqm{+cXFUJUllkvt7n%{*_w`kE*_&{iTPSYLbkcxOKBWP5{H|i#p_v#hzS=sc&gjyO zjm?jZIR|8RqiAS9p)4PkE9$&XHa7hH^TYYicjSDs`)v)}+VZ+#F}BUB9UNlxbg|QtwOcj{!c? z+b+c=@)S}d$YNd!9)~X>8p{b%DcBJKbcpElF@0*RxA@My1QcD0!0SP!|*)lg*79oBwL5BZ8eTsM`w#=KBtmv+WS~)c=%^B*^Eq% zIH#uk%Yyl!J#53Mbib%6sf?2)Xt?Et6k4HW(w-VA+x3;ZJXw^$IX&R^Je0SiFsFvEWi5D@8#T0-F*%pV$zxZe)d+ECV>@ zfqf{~ZEi;|i*YK~os9Bw-TS7_9FMmQE>+I%W#^9DeOmWWqO>SCvlokUi}_m%n3?xP zp_xTiSaRG%ArU7HQeuf6i|5WBf`BEj9WrYwwDNMTvC7v`B{xrpy9VuI64!0F-g>bw!8#@&Ws3v;Fcg@A9Pq`=zpY;dqSSjNYl>L8U$jdD22;Hi^Qoe5MSnR}QE z#o(b7(e_aw1qoM$YX*{3B(YLZUOfI!!)NylUO3#GZmzC3tne{J3UEYRfvs-W%S{hqg^xi-w z-jTAIEV^ck!`W?d?uw%4asFa5ep*Q)CLTs?|C*>CVP}j)23@}XK<93kW47<&^IUOfYa+JX)4em`a%Dq3y*r0k zGG_=lTz*ZxdO~ej7z{)lmF2a`aBIIyuN|t>`+O}vX>*%#H;hus1rdOPXentyl24i- zqr(O^$bVrIhmOWWwuGnS==A($$^NV7Q#+6!-P<=dJ`uELcg6+xOgb8?k;|>ork1gm z%+3wo-ZbaQ^pNy{Mi7Wo4^c-U6McfMN&uxkC?d=v;6aCD00-dv;25Kv$wE ztxfy%-ouqfUAbJLH&!0r`z?n%6@`&jr_&mLI~;SRQf~J3*9ucwI1^C%IX^|j}=DB;QuAcT*wjta|MYAewQ%1~<$T6=5jE9EL{O>dpe{bjYmSXXB> z32+i+1({N>|44YCInvu3wY7KHKVj4|CKm?f3cGKYu1TwD*3KGjb@@k4&1SO+@tV}s zXJ*w&m4JB7gA!^@u6)`dF^7;ni6m7`H04Rpwag`Zdonh(p4I!+4PG6RRoQa>qy6dD z`95Y?slbqMufmbO0vR2Nqj5Ty()s0#nHzy907uNtBfsA6-rhp87oVr!P4jg3(LBP1 z*|#Y{ErC=?E4l&l0;CqamUl|FL4Ds_>I4aq=;du4|p1esdZ<8>8C% z#hPeT!*177mM$XO*ri~`ums|M3)ARfIOS^-ZP|Y7bdX=X_tI??~tf`^hUf*u7tYqr^6}kL>vJ0!!=30HV zwocq#){7b7?#I1e3s5FI+N;P3oAU-VzM9$q2?VnATVIwE!lZL?KECPZ9KS>eBl@4< zox%*1u)$51?C?oVQooEN{^*Ni=k=y9JF%`wY97Ueep2k8ig{*`in;?kgLoTJ1rV=} zXku8qM3Uc`C*mrW7U$xL$-y~u*h@*^ux6_}dYrvG_2mtFRC|x$N{I7Fv{;D(<-A~EnCJe(e}RVoMNN^erwPg@`zt=oVDTuKznBmqhkcYu2? z%C1|r(I8kH_F6}U%5U)WG@k6g$gQdI?4gt06*L#fsRzeP!vn4mT20&PLAgSMX7@SF zz+}SCbMwE21p~dLr)%5Wt66;I752%RNK~DFj&o#6B>+bj$o<1LM_CJCZ=jG6;#aVW zA(00GgZLSv6C{Qal!#0uGqLv2l%4I*|6yf?)#M+tPlv_Quw!jQ0kJUbI8sBMiIKZU zJ~k3}xTH$3qv6GVF&BB?Ihec?TI2UIxka*%fJ1UU6@`?sAR@xv zdF;It7Bq$PcKWKyRlZJd-|m*NdoP$dzpE$Q(YDJJw0HC*&K2B~cN~n(rQG@^o2^L? zvG%|nQzOZ9$9L=+?Y!~Erlft>j`4GopwlF1JqQXxrMsy3x=0F8T_7f+Ac0PvqT!yT z2!P;c@14GEp#S*J*{RD1`Y+$Lb7$|Q*E`v}vuDD)dqHq2hmOz8T$WY7@`^Hh+02g1 zvWg$%f2`=3?d_S1D3l#@J&T7`*wQ-CcIroO5DjL$+zG~~eI-0h*12n|YMeD|hLT>D zWF#33F#F0Y2W=g;;xI&fx!tW$HRa@Cg2TC-En14EBr8!^x!r6$Ktdfr@RJbv8 z{T(Y`wb^UOpj<*E4TbI&n* zYn!kA(~yS<{sqM$z%;{ z`}2By^ReGRrM7rkKWbkayV-36)GReMeG~l05=s|GrjqU#BU(I z-6i43QOJ`d>WenY8yCSN$3Tv8aIw)YltQrgM>^K6h57qX@}suJ8Ze%)$2{J+LzrD# z(8|Yi10yzcaI@9vtvaG!#?_k{SuoAmAY6yydLjm;lJY+RhVOu`nJ2a9nne$Lh`pdF z7gO2uU*isS77vFoSRvIPgO!(Z<6@pC(8MZAQsgPIGxV5fKhLEFJ0EQ2=NOFKm9N9k zLq=ry!V+MQvXXQGP*;v|XhtewcI@Qzsg>bj*05=w6oq1ntxpT27HFpEd0ZLs^3eT* zu@GlQWJIhL@o?sl`-b1N=f-wW>Gg#3H#c}f=H3fby%$b)OsDHdvc^kirw+C5h(-2f zYO*8N%v9^tg}uNCm7X&Ly`(pgK*ag1C_E7S#Ln6TqC-GDyFN7N4df2>v}IaN^Pvvk zK-gNLuGiJrYiqrN+qt|ncFkgky=SSHwdcRLxFayKKN0G*tK{Wl<>i=*6qL7sFmi*z zt02Z$D&Y`g;ivarRH3bv$z^J7#YKC+DVQOf^cdqEYIP)L%s+)Mv9hYwRhd#Skv!tH z%fM=7DB4sQM}~1qMugo+QC(Sq0y)acD&_t|cQ1`9>r@!OqOz)d-~K&Hs-`1U)m4lw zzW2zl3{75VRh84%WMHkB*ltV4bk&UkzlOrlP0_GU9qnkc)H`C1!S#mK*agE5b7d_o>)F6|*$IK&1m~`DoB**c) ziZ>lYepJw7NL~Sk(((#UX~;DaOYuN^P_D)MJgTTx{7qr_oz~8QrdZmU>pf7Zt-Q6> zX)rc))F;*U8fmKdu)8nlO*mj4e!yX@HMfKyd5Vb(P+@uEg0T7Z_7P{vrljp}|^2lOu^2PkO+5InOE*MZ$ zRp@-WF0ET*8JKEopK55EZw>kSPS{c%@r<{z%3RYqKdd;9nPR`Q6iB%1c9fuJ?3@#S$0vCZuF6I-F>cd+4_Vn8Q z*`=uDV(=!L40?Z;w`I`Ukp5k0-(80;x_`;f9SWYYE9T}eA8~1GCTr_JW2MSYkgs^` z)hR;xOeJn);hAkh`5tey)O)@4md17Eo0dLY(mG?G*KYSVI-LN5q%1OnX>mh9F}a*Y z*1LisSt?_S0-(|j@fddh5>2if+MTX0_nDWd28M<*H(rs>B>HfdEy;*0WK)vWIFMNw z_J`U6pZK3f9PzusT~L7D=SA^;3F7HboU%31t z7|Yud(fxz{gFCa<;KcaOzP?GXZ&Gj%Ts?=@-AjW_Q5dIcy23E(j(UBq-dsytN1%02 zHnT`pKMJ&*!C8begrw(!eNL2ZX=*N0a3;*9I}RMlH3Xz!DAe!U!c;p}-)=BPB%7Jp zeB%~oTY33jv8X2@KLF&zv_JoEGUA5oL_l~;cEyE578!&0n)n6z7< zAtbWU7oj?dzD^Nqx`I~}`xprHx~;wK&4@N&-egd1tnryWx~q_ANP!0hc?HagODS~- z4{hV{=mzJ9PL*~tB3Om%5T_5h00tMS;p8j;V-gQjITNc+ACkO) z^X$6(&r$QHV_o%A*2Nt8pQ_dzf#3fL0=P2kJ%Dm{zqsA9CjdyCoIC(y6Z@oO6A@2< zbOZ>%g2}QJKH+00*)M-8IwynVY%jum3-QYIWqDu0i+Yk}lK?FRzG&tw^`=tD`A21W zz}|);-+h#BMwvC-bRp6)9M}?Y*-0|Sy0jX?tEk076cz4-(D4$-=z6$;>-8c?exi_3 z!!gdrOGJ{B7l9op5l`+dx`nY1`3pp01^WT}GHRUM4Lb-5Eui89j0d9ffM8|1fRf%1 z(g>##aRv`Kfhe(aV^M+^&-xRuzvYQCbc#2vMHu!(5n%{@S3qeQG5)Yp`Dn;X6}j3- z^C&MrDXuV@cI0a9=0e<|)>)f>mg^=^bcA|P?pE$(mvnDQ+2+Q(HNYt?x0GIhT96k4 ziqK;vs%~A_B*Fat5_Rq&ZBxzrLl7kk3hB6_LaHBj(N%qG1Y_k_3ORchl|dsE!Vn$> z3cJdN3c6~k{so~#3QJhSC-It-;}>u~2(P4@7>xylKJY-RH9XN+RW)#7ZY_*KE^FMK z;9(5Chg`t}Y@7lYf`K8IzE4#Imsdb*vRVfM2w5n^G#I>^dM}S@@HaWaBRqz|ZMIR3 z={m%iQ3cYT_4l&GvP)r8SXlwT($O%i#r}|)LAb{3uBo+ZQD?ThmqONWn%}#(X)@uA z=}hXNv8DOx+H!3qejT3~hl6?-<{!k%riJF>HZDrL4@l}vef4Et<0 zzXMTm0F(k?&cZcBLImjvur8ChN5UVM{rIt5Lp5=A@#wOP{n=i)@SNGKYj&vGhI)US z1jJsas?^mwQ4Q!yjk&tHk(c}1GzNB(LVSsbM*&Mkk&6=@^)eT@xJW6lAkqle2@%93 zCxN6kt{}*(num_bP}kK%>=ggkmHxq2&KR57IdX7lVAs&}P`30B+4^Y?asgnf-&HaLCWrcCG!CJF|k65Z%v4fzS8lEr{z^=SjJ@P zcw@=fI&HPSTv2~VQ!-KMsA%x5&2e|5v0Mnq6}T|8Uk5Nv4JAZK)?u<6DN3xviLTv? z183MHna=m$wqrTqX%!A!cir2S!REH`y=U8u)&{Iu$(-y>jDt!QtWAbx${;6~hGLWi zWq6obu2jlV99XWXkoTqcC)>*_E8x?_FUN`R0mCf z_%8m#Mz?d%A5 zcG&9c$v|5AzNpF=L~Zc4!uvw1v!f$Xc)x-@!)j1h&4BTX928y#y1o<<<(cm3_4-UP zaNHhmHrG9n78+|K?s~tbHd?F8bTnsqeQ!O6K^+7>45%hoNHN5k0Q8;oKzAoFSj zF_X{RD>Uwk>a)!q86C#a`0L#f0B;ejtQ?C~VCDW;!k{#<^56XC$tMNtQOl+N1xoNJ zc}0gRjV6QA^5m1h`He6*wcx+haujdq1UIXc)zBb1umvy(-MQ9t{kwJv?*IPpfBGl9 zQG+*R;u{QIv&o_+6JL?lNUsFgiL%SVnPeCQeEafg;m!P;jB4ctguP|2p@M({#Vu$9 z*Zzh`j==+~(Xz`S2H=|{I9)#7Q~2WQxol?j?*%H)Qnpe@U&X7htv-vL##i6^{<etoqZnftUbB0_~aXS=PtZ+6Q2AXCbY9U zc#g+ti3|!I6Mp`4R@Xxl2+6WP%9MEZVRTmlbH~5$VWYTLJYkRs5$F)EHA(uA{x^%T z`jD&1ti7pspwd__Qy41;dT-Vno7}3p>YD26y7x3YZJl{#8%H;%siI z(^LnvT7Qj(f-R?W`W}0W-xG1S*XNRsPP5(+ws^c6zsucbVV8&6RjT$%wZ*8d*H)X|^-ZnSs$gZ6 zL0hBKR9BhZfT$V(5OsmA0y_j@MM=lfbL-{lg@yDLZ%gmn-_O4K;FVWC_@V2r!|NKn zUL*XPGt<&L1e=TGWWL{>G#T_ArY65F?(1reo3g^MwQ7Hj+Uv2kd#hgfXMLozAx;*3 z)TTkK&8O(}Ab158R+#oFrV!2>SeY*Q6tspuMMom~{HX!<^??s>`T~R+@r9uQ7TE9x zsrQ999vxu+zU~ErfUGnTl*#||Qv(CSc^rU`06aB6++>Y$O%6Pj|FfXZ|6rixQ-DXj z18%pr8!^Xa8RIy6{nPI|$u@Z{HsiJ{o)c zq|Zn&j=dhcU-;bm+5J@er+s9i-sdIO`1Z-}4Yf{*#9YW7?7YK zr&3FIbRlyAk+$V{cjcE4Km6-^DmB{5N{xm*`xO}DR`7#5iV?(pLMt(-OuRCyA>u`* zoN#OY*^f>yGX=Z)d;j{c-^)+D-SRN3hq?C-f8v9`08K=Ix2yxoLl_!&mJ`BtDJMh~ zCF^ZTz&8jZDxHwir;sI|@JcaDhD1Cr>xiARbFnuPm~b_C&gkfyG1Tvhr}swKoG>*S zp6~@GI@%_B^rpmUBs|`_veyy|bPtxZsYoz5=pWmgV>iae0y3F99kr+jbPY|dO>I5r z4#)Q|=@6l=v2^%69ai_y&)TxSsnN$-|@(j&;{={Ap9Hc_9Lg;k7sCh|76e#&@C_WjSop)zF z?o8Y6i@W+RpKadhaa+^uKf_C@z30}day3<%t9Q*@oz-fxHPrEZ7OOI2Rh4v3z^Nci z(~^|HIQ@bJXRqJ$(5J4wXV0NM6MaXIFwNqXy@L6c8xQTxA3qZVz#hs6sNw!2G578Nlak}0lvZ}x^g_jh(al)L4YuA@f|VU+7J*e`PbJ^Z2EgJ+&`XfJLW;9>Ux z95GoxnyeSrEc2nJ0Q&Dvx%@b3L1{zWa3w=<;EfTlt z<&M40j=*3`GPN_?or?~-ed$1A*==o(X-x?)Gcz)l(>_ z6C7?0#EPB^Lf~qmjA}&l97~elbfW0Y<&S@uZto+CAxo{f#&M z`V*RNAG7^B(KCAQh&YXK1HK@}^?-&zD?|h@V*26n_Mo7WK{I>V2ZV=?&$IITbN7`~ zfZt*EKKQY7RYs#Ke;IpcmC00-e^MHY{JRupgcXwB&iHW96`5yt7h^J3xqp|O$?|_h zXhZ(HYG0$8{SC%yw#Cf(W56_SfshiM+z$tPk{AIeUO&mNA_gvz9f|d(5A-{`E}q+U zQPMTAKh-tj@#MO8&v-_afsr%&c3zduT)ngJ@Q8mH?JKAU{Jzwl4uI*wP5Te=rqQ7i z?Un^&pQx(v+y3pgjJq-8j!y;W=iF(V%QM?Cdr?>K#mcIhoT`>zHeF3tqs?5kd*-Sk z0Ix063w?rI1m4Sm7ik)4*aAB30mumB@nVHgIbu8ZlZnPn&-+cU~%eQ7$lnRIh$(e8`O)hvp0%q&VG3 z&=eLS>6oGBBTw2(251P_{zTC_sx&D<&aoCHtnIjnWX|>SDUB?=a7|jH?)3LHp4or% zdvuykU&?bvpD%4;9o04G?DO`S^WUzj?pW6KUO4XUw+6af9j==%@eWx1$yS@2y|=37 zhnm*<9i#bwtFHQ?x}_eA21HSm`nwwZr4ga^Nw8*uX+0+qf#X|7+@@9#t7H{$VWe0b z7oC@y!GlqDNZ2_MoeVTh#4=|&9ES&n&P}1`L+X%S*O_Izr-mGZvFL!)naO{yXGoF% zOMPc$&p9Kp{fnG+BsvqF>8ls#uS$2uJsp;jBZo3ep|*v=?4C9@Iog)-;S_Y?c>NZ) zfZB@k9;qTh0%#nW1U|)+l7Tc9QF3LP|A8~{Jx^1pGjVXR_l&MsyVtwW5si1ue>vTY zI#lVtKK4vFYtW8%cJFL%-r3zXqSNQva=Esip0?bdx?-M4Lr*N$g%gs5uupdgG=~S> zc%&=i!Es@IxGc;3nk;u+EI4sP_|3p&p>NXdV>KiS6g}V(V2;yTAw`#ruH3R`v=f(& z)zIaltA=}pD@KG8U;GNzUd0vn0;7Prir9omuzz>nnZX0QBMWzTH@BzkU^BZWS|`J( zRxtb}U5h8whEWi50!dSfHl#vg@IHc$aM=VB2}jwdtzr9FXFoJQf7@YJo*7Q|^}JH$ z>1iFET6yIMKVbGJ06>?0px&*XA=VFuWv$P)6+5|gD3CrZzE zR}&Fr=;t)FKfKVN&h*TGsdF*fvDm}r@{jfoSp%Z$q{Gy-=N|+RUNnf6R*^c^5a-g zVD)xkRCqU;vQJ)6fqNI$#*ITpqcF;sxUhAY{lG~H1M9LDFem;&4H6y(77^R;!Sjbu zF4>p9v~a9KT`S1twOZw|g?|A9dde6NYcw5k1M69N1>Ys{@1OBqsu4loErx*=f1@xk z(VQr|DKax}U*4rqsT54k6cts9In4Gl+%4W( zM1BR-tS$dtjSptY>c(K3iK3}lo1r=2P%0gP7DN7ffCV_?-Am6gpYBmlHiZ-GkBGNAoLamU5@u z+S2U_jkTbeg}S~a;R@=~_t4-JCjJ39q9T$v4FSgqWL5J~!E7iLslcC=C|Xa9nQl6z zo4+);9MX7uT3Y*D^%0*X(yBw9j%a$Jwa%6Bhljik@t`FhHMqP7RKclOLuV|kOV_pZ zcw8Y%m7#9HVr!m^HzeXAeYzIc(bZ<5FeVFm$Kd2cBC?YQ>+$&tf-tE;=DxrSWC-TyKjPSdhP0)>{Xl-Sa*pOK-nrqIJMMDxY(-;_bKb@DzrVFHLluP ztE$$ZsZ?lmD%Q=OiCucOZ*Evwo>Nw6+gt1xzGo7&stjhDzZJeEs&kC8#UYMS)FH-) zBz3U!^NHkVW1szkP+2L!U@gS%W{#V0W`CF8!Q$nX24%I`pu8ULh*cQsjl$ESN(X}) z4OA4exk_jJ{Uh1lAF=MwfBfU0&)@JaA0Ouvp<6=t-}3LEASnQHBL+}I*nquX6m}&d z0*%2WQYDW~bn^K;Pt7j2HQPfCvty6Er>7;J9AEBh@8}nv4kdlz3Ypv#bR|>l6aUcY z_Bh_r`anygy9ugR4JLUIlgQwgu<IqC( zK|%CnuUoGKu_vy(`1(7}y1H-A&hgaVz3fltoX0+K?C9?4{HJEI<%E*~d>c9oE7e&B z(1BX^wI`qa8b0S3#Jhg{9u(h&>4mFFWGVB1{mCc44iVT9x*w>{@4}m8runGwoifC> zF$%$zgao=#MQ4wAp%O6-QeXh>Qpl2dwZ`K|b*mtX{;s-N> zXT)o&L#n#qL_9LtqL9B$g8hRM>^KhOJu-j+vJWO-P2&H|@wKn9Pki>Xc(Wd+&aX(2 zgJftZ4j5^EUwJH%!2g-UQO#zn@!$N%(2!~MTV;>K??vaN3@l{5awDrVS5}#7%z1!E$4F()2EQ*>*5np7Fo!4cCO$SNYLAkaZ%tonW#d^z#C zJA}JtyD3}g0et=P8gH{H{}zUM7-c+mF{L5cSd)LJG~XvNA{`jghR6e{!GK(bW1r0Y z309SO<_!d0k>Bc&A?5lVMtQI{YkzJ1w*f6NI1USUoyk%Os6lUJ;%G|wCtAX5wxL>f zFu&_}u9PAFeozBC8qW&f#Vsa_KtZ06Bz`g9ixgpyVD@Zy-%xH}D70@RyDyx-b8K>I zWMmRrBzs*fU%w#(p=}B?<_lV9LWHxMa%dHy2XHf~~xGhd39g z`wu#1LZ)ViuQ6$8cDq{)-Hm>Giy5)sz1`h?y|9g2-03z~JF+&D!D!SPG@FCgXf&9t zt8}!x+S2Y&v@O)p5o(J94!TrF0Y{bO;3Pc>(TxRh5p#ZFX{To<8%rKfwhgAcg{KF4 zJbk`L{~vR20v=gatqo_NQNusjvMjt}c8 zg3YkaLUfpgEthq#sG&=+a;#`o8dX)=sN0!fbFKQ|^@U2&>$AoWUtvZZur&{gw zm=LS+N$HCPSsa zss`B}8=a1}2m$CMSsj~!gG6o>Kbs}1A>QGvZ*^Krc zwCbr3cd@#7hFZ0TT}gVG#dowLxFlrL%6e3 z+tojm$@W2%!6SqS_e0RTQyhwrtiwv97+2Cvlrc|&htPn__TqI@C{(9(n$HE2fFa7& zGCh~|yXrb@Mq7V#5T4DHyS2yl42#E_V~)Cx=C(nL!PD+)?r4zmUcawZ^^+E7FdgfO z3K|+7tG|g4Pp#A8^z^qjXVX=>s8-j~Vr?{9LpKHE(Y7=Bun9O}llR@hj>6Mr(yWlD3Eyk*OJfufs9mYm39^Xi9koCnqMu?a_!kZ0isX)jC?G z`-exg+E|soJ*3w-%N?~#GgI5!a$Ud^jQOhuGN7Zg?C!G5;AK6f)%QfEzS?4`Mg)(r zS9%CobZ;~oO*J*9V%W|iRyP?!|i+*xsa@YZ(@U*dU4YJ;Z7uB4wy2LN>SJB zw+2#GDr2{BsI%|CzT@+y;`iXEGvWOx8weY1Iw!s`(`k(NE;I&J9~Qr&8Ye3kN<%Uq zAgeV_g!YO`Q`B9gZ}Z3=vYwt-&iskv$c7W?d;*?gx^1rlz(Oh1~UFsLrz(&#CK)bNUlZ{ zds1TAy>xi7H6N)DnM|$q?lyZYVQQ^0)ue?(lZ)Mx-pY!oM%R!IbZ09n!WuZ+peH@d zP6!7`!R5@O)ROj{RNmiXYxi^}db|_DfndIaXvucugZxD&JHZ}CU)NPP7}CJqlk9{) zpYELS_9W7sarSU*A{d;AQCBcTG!sYB4Vf!)Wrk!%LGh%CCT3M+zfb38X8Hq(8j%T^ zXoXM{Z%&0-YbF|r2!|H7%rDlPbxpeK*!RMg#0}T`$6bFx3!49#Y zn=;b|xh3XJwi2lnjNORQ%lZP@FzuAqI(ui&e}BjC>+bv*YH+YFcDaz}HPDevfkeUw zGF!oBdwI{`v(JP=13jN*JEBe}`*gM|foq+?M5scnNu!1&L~al?V5^X}5tDb?>pdjv{U>}EMn=QlAS^)bc#Nq;HeE! zC)Zuqldmv}qG;CSd#*#Nfrl&|21DHZko1r|-mDkvh-lm(eq?oEgSi5n9P9U+j-al} zRH3Owjt0NOow8NcR;X-R0|J{uy~$*6lwAQ-JRzh~X#p?bRH;IOs=1GZWCv^<5Gu(>wAQ(V>(rfqEb%tX-RSrw6KG;y#p6xV+$AYm$BJ66f z>tqghU#l+@sMdSk){wKlGGwqeRo67u)~Aw=cz;uCwk_Oc);337(N6I3D(tT-gniIQ zn@J5P|At@Opopzcj|+Y?cs}B6v97sR|Gp}-v0SIpAeOq>^nq$yZH1v+W05}oZ}w|% zwO`e98^YvShrM19LQHhHrEfax1r`*<7h{ipGe%)o@wK~<)M!PPB^1Y%F6?edu;ZCV zITFf~v5?@J7)lP~iS22Y@~&oD}~VU%L}6|B~wPzK&fA z8a8dxG7ynR1z7g>S6TLZHmrKWrTm9@4)n?(-SG03u6w@hVb?D?KEc6>l@I;QFMBIA zLRkRl&LR~DVBfoz>qgoEK)a(p)7Cex`RDfC+%*$P1XK0NeA~K3y|ckf zXmKNvAwr20)}BG6dOKq95a$m1?WCJg)8ts;kt?<@$1q73mfnfqIP|hc&f*wr_BMdi!WzL33nPJ1*~y zG!F?E3qnIf*D$#EnW9QTG^$hp9=9Jj2vA4W{=;X{W(Mgug7m^Y9V{9eEm>by$VcKB ztdPy*%dBt1IcEcqpr#5tzB~?d4H#~UVEnsj=up ziPc`eAtXy2+TK-F{uW2-&8fawogBJ;+yebgm zJvMIl*>1jN`xSjQw-o?_6C(abSYm9PMN>PwcbttR*T#VzuqduQjZq|6;SQ{j4V_qD zC-Su$E;Z@w9xtrhMeLs9x&=Kl%!_v&SEgLYxdbg-Q2Xn33jaWmF9om}7g3iT5d>Ig zIXMIZLjrvxIh*#;rad&TlKB%KJkS*wYcE2^Y}h|bzoD&6+nNc}xL>6p$y{F8IiCj+ zFT?fnEQsilLvoV5El6z&dBu{_V6Dj#zGP#=giZ1G^7zPzgim$OHF2mFdnQro4O^NV z;GbTPR#%FN-<{AmHC8!&l^rTqLq+8UT2oCC313yIX=v!kX$>CxIv~EQ!KBhvm77}I z`t*921($-@+V4T|0xpDs10mc48sf>UUBFj#}}cO_#q^8nHN;U`R3!2w>_I)>Bba z5%qFh54!Mm7Ax=|b`wYR_#DC2Wk*zEXDq5w0XYPM9fvLM-t*$O6+=?8cr*loRhVFz zL2~Eaby~AlY0wh19LK%Si*M1{bwn5>kFC{qw)7Wx^1eh%DLYbC@&2Lgqbl&cuHov+ z_YOgdaI9j0OAt&X1yXR~rz{=iI`6u)!zV}$c@sh*gOX-rTM}C-hb90#yY^59&2<3J z3ogJN@3GN97XYJ&wMd>RxTX%un4Pnu)~dEj8L~6qUW(L7`VDmDL(r(lL%)oJ%3fQ zr>+oB1H{^Wk4QiN!F;{|6;_*j_f*r!LNdFf*X8QnksUpdQ4Ka-nU~(NZ8kX-3QZ+v zw?SpAS-VfXh6nH0bI=GDXSjA*a5)yPXyV*N*BVJ(P@;YcY*yy89^vg%t4H3s8UBUE z*D)UzxXI-SaqyJ~-^iEB#tVe(r>BCS1ZiY7k)avoJOGeXxbCnH&}jeTUpYi0M|s?U z(uj)y*dTJyBc0wZeCAZDId7&d3#7zr)nF!J!u)|SDo#$(8Evc<{*Im+plhms+R2y2A}NUt0n-NxAR z=%_O_pB(Cz)^ZwBB?m^ngRhaH&{(Q*bSynI)HA@V|A(-E>P3FJ2$izJ!3M2huu!Se zDcDl5DCCQ}!ouq3nftU*I@C4k^RI!Y1B3{qk|Pzirp!+e+-gOMRhV!x%~v018Oo^h zEgr|VfP|9m57-vJb0h+Co;kZ?M*5npq4NBJvO2r`&I0Use`{A$1>i-?9nLe_*{dwogzxuT(-ao`|^BMstuL7cG&zFn{-CCT&-i*CWrt0=C@xqPE?`i%l*j+7(u zv(k&>8EfTXC!gB)w zgiO34<(Seau@G4`ufZ+_a^6WS1dH)?aqNv;b@b zHH<1ms-n2b%VWd-P*6<^i=Iq?MVP^7O9;Ee>Ww-J*nlOVgOcw{>%?4kC1FV_z<`1b zL5NE!Sq{0@ylDY%h`W>5?cTz={Zavp4Ogi(=k2=ZO(pwgV@RG9xl!IHCN%RRBrXL) zAS7?|T+r1wGRLOb-|xSzbnf-H-?9Iz_shU$FMor?gd)pEe((ckV&#uNj!mc}Pvt?U z6k@k&qB-gr`xwEjlnj~l7zN@%*_O_}zNA`;$%BRv!M;9QaN(Rr8;qYh;L+rfX*>kD z#M_Ro&387}|4Gw=1vIJQN`w$`#Ty!oDtoN2t$m78v}BV!Ma!PVzFlFbqspn#x}}c~ zt<0P;m439YJJvVZ;5W65rb^SbY~3Y2b)$0ApNSLGbk8N;7E+}37r}gL;AO*EP9`%g zD+#3Yc?-h2G`SJ)gW{a!?lv+aAY;a5Aa$ld()FdORZgATg_GNNg+dq?-mj7Ah3-aC z?hGX}A)Vt$K5~LKSi?4+XXNNxuEWyE%2p2$97R&25}=}!vuY?%2GWlUAT{f$KGs!@ z(hM8@3eH_ANDUe8vcd#L*+++VKE^VAFm$@)L*M#{WAma{a&)~5JcVT@FQj}JCCRpw zAvR;UZP5-`Kbf&UqwT$HTS;b&4=baJ7166wvtP}P!2pVd-U?C(@(V0Zo@~y;$OLz4 zCo)u5QXA#tRLR0%zo6D*4W~?&(Yc;aL!p(X8g!gGZ$>e*#@$6U3PiJJ*@K`{HZWjB zis!kFzUN}#Y2jKH*ACW)^LCJlAlE>@kD^?&!wY>~;lV&t>#mNTm5x-jIpsniY<<#R zLgzP-F?Sl!0FZ9bpTIAS)rkRK_dS5-D6^~P98t?DTdN;dth@Np0tC}5u?jmjS1 zcs~L9#D-;Q%;6 z&YfEdZ_D;{4>xQcX(jL;L5LsCKPbJ-F8EM$$z4zE|PEsO#QcwkG_f7gPrb<*+{txxoKr|7@@2ZPCRl- z%i&a9JEW!%3?#GDLJX7aoL)a>K8#fF`P;`v}J*O)WLt65KiS6 z%5C*l9!}Mr8_Z^M=sQJnxzRM@tmQba6y#;WTTmST{~XyC%17%u;K~o0k{unfhOo&L zVvgCxt_ft&2$xs(bZ2{YnrKBOwn!7gK6_Co&sI-sNC8fQ6LQ1B8TJXRTiKM!z3zo^ z|E9CUV5|w55^hmr|jWIqodo^JL2&KLsQIAiKru8y|ccqwbl`-tZLO(wFR6$ zjZhJ4Y@_RWTErl~qM#M5pUX=o-WvbWa;B%JD`j!(X)qh=mxWI0x6Dy%GWVu6s-Rfz z@gm}qq6N_2Gg&>y4Lf2j!dPIp_`M)9{384;U z@8;na6yUsW9Dt2Uw(OAY6d_v$R3u-Z3&8-av8uMR*3sGXy(j!YMf#{jesILPmVE$# zMX!0q)AzImHCRifb0CRP_!P)fZ6>{ zt)Zf}#;%`5MmoZ2y3OD03Q)??)|m0s2y75zztq| z0lRi5co&SoVDrV$IS8l?hj%g`q*BlH$}nPfzrEU_DK}SIEa;;WItM(l?#}=AhmGaP zUaPiw*f9jQ$z#htiWYGE^%kWO@61V~X=OVtmI|v{+ zg6*oXtROvMpCh{Dr~wUp7YHd!%VDqV;BtOsWoZJDb|2_y7r!ZXw70jb9#_ZM!?R0E zv$IS7iBDtir2Za@Mq{YijbZ&Pma7H9c5c)xo43h94g&dMA}*g_$&-#{A$>C#Nkjt-zxnro)+3Tt-6_r+FYbQtFF?d@}2frf-#`*>o0Lj$Bt~mnY zsWO|ZPL0Gvi>&O65LPfvV38G#F`JfHBK2lvRar|GSX_8sSy0m1C5!9!E{Y)3qGAfs zgT1v>cD1yi&sYfHnZ-~&avfq(zop8eDK~1XjiN?X+gdNj?bSOG$LGCGVHiEeu)i3; zrxK6)=>~-cOXU_UGrIQ8vr{7**U7t5!>)^M2CVL#cVL`3=0@6bwc(I{BoXcIZjVe>g~E=(K>H9~ z(m*yyTqxLExWToNZ?Kt>@uAUdFcc1C*zNJ5{`3>y@djF32p0j;itUiMD(0zhY*}YJ zk~{}Bw(T_Oi|-98k9=qJMr%|CgYG$lfpCEe}c;ICOMl@@RsNSZKz zf6F?)o}=vdT!pA3e<3y_YEdd$SAL0b_%|^kG$6;s3e|q9Hs#C&AlIY*K7=!@G+3*v zP0hwvkf)8e(H`|WY%L~aaNTLvS5((=uxbz;0nrWUTLCW^%eNrhlp_q10My?a9t*cl zC4D_sTc59^x4GNzyY(?)um5(jsjIcM->V};tYoAmWbxeIrm(l&*mgR2BpijM7Uxwuo;Nd}S~?V_Qs@{kH5LJeS?(U%~TX<@t+cKd16*vy@f7P+ofzB0LGEXA#fg zq$`xi^P~Lv-nC<;JO_{-us7O5~)83&f)$1La{&Z<^AF1 zLHAX>o;3Pn;{D;}@qD`2pOW&R`%X@G8vQ9LkLPEu62|^s^atf}yTnE219%=bEC$3{ z0#h3C@(2Uwh&u?k!$E@pYS;t$yun#f*;wuIC4KGLrrLo0*=={9c!Ye(M$Qq%mMQ#v0|^r)7BAV#IVPJkPwKFl z0`+kJT;tx{;lCN&ExNO+Ix@A{1s3#e=WGw;uujI5=R5fGy=!9|%FmTezVbX@KV!J|x?X;+ zY>Gd}=45{s-+_9leqtsM^7^LA&MPn*y!R`m9Uq(8MXc!3vWE(+25%GV4Dz?8%f7?k zqWcfmijU&?xbpl1WrP$*={9Z^m+%~hJoIL=>_^2`Ou|R-Jdfw)Z1N~ERAS86^4h^R zI3tr8;0&HSI3t@-YWEiz*|mJEczH0aJ2{oam>ryv@$z`Sr$9aGe-m2e<;%`0nUOS#va@yBMOUi24RM~&L@;j7X#Pjvi z^!!|Ujzn8y0Klbvj|dv{b#Co(nxD0A;(1p11)fhT&p-6a^VpdrTYFRv=!-Vkjo@T3 zL#Qhop}@wV9L7sNn-N`xo85@_HQFz*XKD`XI)K z9rdFve2-jVud74G-gPjLSN@(b3tg5(!m|2^xlFb8HxOeH4=KbzYP~iwA{hL{X^9wK zUKW0N+U8e3D%2{=;|Q0N=swBEvKRSc!axan@n;w^$SeNbQ(PWL_z?5*SOymqmxrD& z4_+S65n@C2L!OnC$6~#;D7Q<>+PYwM-=)xHom%OjNSYyNryy3vZvZ?aN1fD^#*fwo&8<)z1YBQZKl<4 zF5I{;k=%RJ!r33*u^|hQBIEs#@&8|RgH8@NzK(8W3bC2p$EU{6>64Dgk(n*S>G`~{ z^K{*iJg37>gAt5pa#E?#4G;Ws1GE;vg-$geB`k3Rdn_cWJN4{*zdRAO1%2)sq^E9E zIa-^o0l(Xb)YU#2|ET_BW+#V0`tiRqMYlT~#8w^nl7Fv0a@wgbu96j67kOAWs+{ImpCxu}smA%`SDT8BO0U#++HsfFVA>+2 zWdCb4(Wv5rSc&F+=+%a9qZTaP^)HRnMosuN#wo{DReem>jvsinf!d%f|7+v4QGI@u zxubFV?FQ}ntXCVS4chbRhe=TqLR?8e>^oNmel80cXl?EM5WS#0|5H&Y$wH5phcV!n zCFMyd@$z{7mty(dT!=wwAR$)vR6&R#j*ZGgT=M5{SA^26u$v1pULL~gJpOzf!X8&n z3gsc}Kek?;D+yGdlmwJVeUs3^$w(o;N18LWLrMbPBMmxUP+>}1!&`6SD#G(n5lUKv zittq~0s-pF{=s{LTN9k>uku#t`8~WhP-#kf69?7*5S~QqygaCbCJn0SIa2iEIWLdr zFh=9FD%byMY$Q7wA>fczL}T&j4V@K6>vA`&or=APo9O&<@-3Kp6u&JGP(hF$Q?0L> zE`<}by594r1LNIx&yh@W%+omD9~q9=vxf$|_66#_OVPIO#>Sy+-%^`cZ%(9f4$Nds z>kRlExozzg2Hn=0y849M-5#_X{T;bbW-e?qP1V@yqD`K5pUs}kE8V#V*$SvT1CTeb z)}0dT7jDeRCi!(AG{qbK@Dx1}k+*46^x(>-U_;@olRF_bAY<`KL4+Hl4hz!(nMoP# zp!=G+@c{nkg2qxhE8IZydS~TN`f$6cyROsW?5yiG$J(mG%G5midS|A_o=lka#&)N( z-KaMwlJ>V2C1m5jI6)AY)Ipp?Urz^Ld!D{}y3YN_>zJ%vr|;KCUVF}zt+l>Ii6LOi zZP==`^@#D%)}z1E)+5FwGaxOrZWrI;@T~CXU*ubyp!F8S9e8gE&&%0#-(_e`i=(rP zvnyU2wdME*ufYb#ZBDp~(}T!vu=BIZCiwFiJVy#m(6g*OuTjd6m6iu&{hPSiV`gov zv^<`V@aHR_r=)(+^B$%C&JE@BWsBVWwgQ93RmvFvBXk;#v#_7s3TrF+h$*|%qpw3> zUg*AT_w~1|?A+Bq=iBxwdj8)0MZ<5shLO^u zx+@!GzWH@f>Dr7AdU{p`~iLbo!(n$lSQU-2bp#|!|tI~4nVPlVa--eInY_5SeWEnQ_GT$(~G&U;q z1o=6Ia4V&01H){C=T#8XZ|CeG%WI!zCwT304gz8;E6Q^iQK&o)_mr!^N4W~P(F4XH zJlEklTbkrz z*-5ptd>z&9!&q8*UwLWt3A!Ma1~dE*K9*FP#u9E}UjA5Vc`&_woay<&3`@%6d6YjV zhft|)uwa;|=B#-U)DUY1(_6cwjF>Z@6ETM8@|?_+{gt=Nd&{3wZ_C-tVWK7iK9ELI zBp;b7D4P$HM;Pk?`D5=Cd@M)LAt>Hbc0VTL4{Mi|Jt^D+qh6WD7zY+Og3oZ%@dG*M z(WB1XCD#kj^f-?ksq0wp7}YqZv9iSXDbvrgPzg#&F8+1?)Z66 z!n`NSAK_~?TEF}p$oCWFYj46IFThIH(3|9lbsMd_pWA)CuPHHnzH!orl2I}!qa=4;8L8bE(A_jv7y@~;gpzSzA6TOZ zh*cW>eRtleOn`9Hji~(=OwxszBtE_VxW;JR^ZcIcg=_DC;j+ifO-w7qj;E_FgZXzwOA8ZL4n<-kweai>OE*fKvFf z;Qf)ObNB8y7CQ6qH1k54nZ1kU#Vzu3E)7GY`;Y}UsouTxZ2r-EI1?@**|yww!lqHhS0)=x)iVt9^Q{pdu>|=YLHg7 zxi;PH6x8~7AV-vVqW(}r$ZiRUTZ3B$qT9#ADzRHt9v;Q*)v;W7z?TV!eG!mRA8~?& zM&R6Z!e`IXCP`QLe~)qb+t-A+^q|ox0Q7K#K{QIO^3kQRKRUfqOceP+Uln2SInTgp z00yc4gQ%aQrU68~SSJ)9G91hE=p*ye=}^=9WwE+qO@z`$R$!cS+s^*O4?rHzG2W}a7|KKkZN4HFzp9ABJ zuRV$Y#1|peqogx=VOl`)bR}#J-AB9liE}Sn_fuvInnI+F=6(Uy4-#MKMuTQ$t|&B{v>B@#_1ygUI3uXe@Bl*@np2pgNN#B7x=DLo&b%}jK7n@4q(vv+lnW&5Dkt{-^Y1;DJ z#(0ybC6LhTbOB*N(k6CXIX-eQV=|6bnY5EP@7iUQyvsyg?n9PuI@a&nd-*73b zy!~z4-xbT`J(I(MGmdv1ym6^9KPOB~Uep*4gi`kLd1aN+Mr}fXT?98dIj6^z^LR{z zGSY2MLjNx8UB;8fr16sz>Bk43Z}p7xEED|<{Bdy3(7SJ>b72Wz%>CVX*L2`l&jQ~4 zu95#XjR=qDhfJ#jdv z-S&}lkAHZ(%`$DQ9l3hj;|;T_?2*W!~zx(>Ee- zA(GG(eVfg0O&rok6OX9au08L%x^e&H;_ii4=65en>}z<#JN8`i_WCEzRM(iR4r{8a zv=vB1{&#Sx7x0B&Oeftp&$?<;UCkDc+eLr_I*5{btn*y4tJF-dNY}{t5R)EJzMj$p zS_>vcBtW8~*2wSDwoD(*l&hm#EQ8~n71FoZl@*%$Y{b=*v^#ufCx-SW%PZ1LHADIC zN^IK8D#|@$$;=T?%X!++LJn7-au!#eS(U49v^TZYR+)7(rdn@4V-42Ofz6`M8S0Qq zv#x;{l`=)!Fh%tgm&p|IY=kWh5|84}6#yV4Q{sXe^7-zL9bQl4Xb7UXWi*o8f8D_F zb$fETzLi+p${^enR`X=FO<4VkV9-tL^}^_=X6Ic;&Uo+MO5cUr{3Wxqm*xqgX$Gym zfJtgVmJgBVo1@W!GoLdV(1F1L1!h+Dpe;EbQhoI+n$T$6#@_d!y-{`DHJZJ%UuOBR zB@)PaqqbbmoN(vH=XBB|IFi}e-DSTM&%{wqFTGH99D5@MF=D{fm?6MA7 zVP7ryIYUD0EwadmtmpBr*f9n4PB*)2_J;kb)czZ0C$B${q2IaVTiYWG=MD{>w-AXe zoY#BD{N&c&`4Ob|3=eCmK;Z@Yos2A=H{5^T)>z^9Zg$`B(BR~If9eed+#piD_KNTT zMuZYh+GrIac>~s~Ij+G;oH!v;Py)}WRM4GT&WX^9+4Qjc63@`}eKsUd#x)O-wJcf2 z*-hi&hAykooV3)}H3$5y#_6H@Zlk5w(Gsd?^3;26m0j$-efyx+s4A)|EA*ABU8^r) z<=?K?CM&887CS(h8~o1Jq_(n0TU}$*naovMtE0gbOkqwbMb2*A;Y7GK^a9$`*wu~C z{rJb*#y&CjG?D-z^W)k}u=vnHyM}C8NMXlB+_u6@L%`4#t5VilxCloZN7*+xZ7Db5 z4zkZqNRxJvX>0W<_ci0A?DO7SW6MxuqCK0)WICe3hNh&`(=;3z9cyj$M-fcCni4wd zLe@%ar9ZYq+9Lf#Z|JKr1>GKG%xP+Fuo@%wy59CcLMv+G!R$DfT`!4k!hhpaBZUBR za+AnFBOf8xX#)9i>+7feqn!4ioF5Dtyp4^qI(NfxYi=BnuXF#&reC`ktTA=mAM@Lw zrCTD7#=f*GopDd~zE*!=`)LA?>cSo^7h&YWzbUy9E*uNxDhPZ`Nqboc|Ee!qFS_7B zTqxUJcBJg0vTJc^;yq;_ExWhu%Url%D&#Y#vQ@ZkLk2i`_2)Q(6yNppTQl-My(OR3 zC7*H2xYz{lHWfdYJ})g_G`E0^(>?#b&S21KYijOMe!p+izw^q!waV{5)hM6XLxoS$ zwS`ZG->kdvsqkBRd*M^zH@ma&sqkCSa!Lv<;kR^f^Aq;T!V_tr@ad6FB;KL?n~f+R zkPuMrWbw&!%7fGO8haSZD#fo+nzTZ49cYhaz~g$p%et2|f|ZZsi*^2NblWIXOaH{L zTY&~hFPFUp(;_LJeEWk1l)St+fv;uy@e;l0kba9_z#>{(RT`!9seHaK;KM>V8s)nq z9A?vIH^#qHibbhcGmmtQ0tX48KDs>tADE0fDF{!_B4IWD(KQU!B?@szx;W{z1`<5- zK}KFr6c=C6H07?MqYu96s^k?%=EsIs!ppn2-+nv$^7Mn}9?2c)hY4_|aVRr2a(wzY zYNgfLgDy0y7UZ_{e)O@k8;A3U-&>z(8W zj?846eBih_3J|!-a?QlN*f1@|9Q96#`oj9#)4&Ts$J2iKf(al=9LXlE?2fxPXFT+tRS~i<40R^U^C12#(VN{!ycsV@6f9 zmI3UX^xNs^g!3lpMgXoBF5jx1Ics%%Wu>vV=_`k&U(ZT^`_k+zTg*wnhrqn6WvJyx z(l-=x-5{5O=H!|bYEerO&r5JG*`$AL2Js>q^UQS$@Gc+7gOh};OX?&?(QyG@$H=}c z9by+tcd#EzH?eEJ^rayoH9NHWxb!#dP5;^m`9n6n0t<%po%OtT4?Lh`zLP*X1^c}h zT9XZ06Hj)@!D^tC;3Tnbdn*_`IRK209f@tpnbd~SQG?plx0u>}{qXROd-`{_$94=X z@APXoJDMVn9UnR8oDXlG9=>K}iV+G~LwOX?LW%o7iwLPWSmS83@hgaA~ceV^jJ=&IRF@^eZv# zTpSbRCtWH9y`q~S#FH@56%DL7zam}*TF>W_BfVKug{fLpsSKuyi+26jf$f%Lt;JKL zt8U4-YAt$QldD$n_ar-)>e@>)K>h>c%7o^O!=J7na_JG^_zV8p*SBi)N4jA)& zqyNPd?8wOYR==7Bdgeoe7tM?x8~048+jorgZ4I|ma@Lx%JR4xog8_oZ zwBKuI_)d6OwMY6N`uR%o{-pGF{6N`&a5dA5WZ8qI2Du%Kni5rt>BkdIR!VwpZ4&P! zLS^3YX3wLE$1W|rE4=tv{4r}%oyxjV2;#c>uWs&^mCIF4N4sdIP% z_Tdql*ofqZvh4LVH}f~=@#ZZOEOrfZC9^UZgyQBx$kCivUUB-Y2@HOEPWR*mq z{2FB+46yGaPVaF#wwQ5w%y0E4k=%tHd{1((pndp_+3xeL=lS6C0%YPEyOoVoLA5t& zx7z8O-74Lg+?#w4yZK?ujUE*3Mk9f>2)lIc34xs5Wv_gf2u7sP*Wg5^C^pJ1UF>G5 z7CYu~)Oo#i4o~6toeJITsO<8iu6LAuj=h;Zg05qwd9AJ<0lfds(nr|#)zQ(bM@K>E zT-noQUqX*y3qfMOIF01f>;?J*du!njW{mb(jw25CR+f<-D`V2-!bF)`)DXL6fV+pr zN9GFY^1A5*C;HXu(aU$&3lklq5o>>43fYs^{wYkb>*VrA9HYr$j00Q$i32l^5$B%E zM^TqGGTPCas_RGXZ=m}E!ZVbVu%OV%?6BidraPmFS48veod-LFD|Kd9eOso^Oetc@ zggxwP;phCN4SHemrSbL*Uiu1usnf|{+P5|!oPgMpO-_oT4#73t>$e&A5odq)S%Io8U4x_vger%##|9w*rqKWk2E?#Q?E zJ2GgI?o5<3hyaki9fI>5P!LcoL0I>SQ&2uP!f^mag19Z`NjUwKvwd4H>|XKDcI}wo zOhon~?Z8DdT77oD_0ZfioQOQzr_k^`LTaE|M1&Q#Py95JNI0N^#;}laj*crshFL7} zJC{b|gB2>Fp^uD=SEMW2L+(^%ref}WN^H+Zm1z49=`CjMQnkx%iV6QUl6F~Z8`C2f z6=DSozyHVB;IeAXp62RPQN$7Ri$uX4R6GL~w*ok}9}CG!p$AE}uVQX!ovMcvlD@5k z8|~DZtyM82Qu2w@=@FTxw{DI&`m5E|0BDb9k68x7q>g|wzl-|^OEguU$Dx!OI^x)=(e@COBqwy$dSH3-pcI603>M32PJl*7c zl{&XX-TX2O{AJUOi2b}*ynhEqN3SW&LE$%Tp0&S={|+VqyPmyhRRR1143cIDd9Yg% z$d06cR0{*hvs>k?X>74nl-F3SS|1FAU1S|Qa zH{5d$<+g;%Ahw`yM#A5K(mQ}*2lt&Hf7|X~{qf+FuA|fQV+YT` zIZk-IqB>e{U0>4#kh7!?0S*mf?RQ9MsH|mDoD`$)j z((YbVk|u0DzxpQX$XoR1Z&Pw7yt^b>!k=YS?Zbz^PF?!mv2)}+2~TaxjvzqkE)!?b zLwi{>UohAksW?=l!hgUj!70l~T8zc^Gv8pS>!NM!<-%oS>4G=if0&J&d3166GV9bw zX8ZcLMd-Tm3=2p_LY;=rHtacs9^K7|CU`FNA=iHx&UD!K!ey z=dB_+2We3n;lkm={gqeTeDK{(SxS1=!RRl(((n@_auh}r<_zq8{a?v{a;kL z`=aqtPqx`pat)aUKGW`tw7KQ1GAe#K^$-_iw0Uq8V+a%x#U$2m66c+`5vF6SVERqR zZ%6+4i@kqfWvef*SU$`?_Os;ABsV);%f_XTnWf9f^v9-WX0REdNeVhFO%al~q((n# z^y4Ns64#?f_W0MrU!D3qyLZPUsvk)CsMR9BK;fFS1?ifRj>4@P`mov3;8@2 zJ6kIkzYQAu`0&Z{hEz=Y(^{#YvukwMRJK> z6jlKQmC)nMIPBS$P_}W)wwe~>@)g>~wp_?iTcM_{+*oVUux4Y6Y4L)d?7qJns;BkF z(DKmX{i5nw_QV_RIi3(z{Y>;soO|cq-wLX(EB5WZq!SeFT>~l&1`*qitq;sP5vAkl z;>U2zm2mC)P-IUYLh1IE6?XOtyJo%bCyf`IlJ2Er1_P)OcE3&}YljdHb2L^jnp$*gTf`-r1z`{wOhaR zCE>Ew>#=-q;AeQc*L)ZRqBz+k3NHwUmu98kFSAGT((3)}+fp3oLIQguBgU6eJ2Xx; z3UdXhV8bAxYeh?kxAhEl?dn=t$sSFgaSRQznry~uk?zK*{M6#ux%};7%Vcx`M=w?- z>r#-I>$VqEXq?IRb`LcyFR$BNX70bA5oY#MA8aEpJ+p3fc|lqQnHH#$jUcm0mKH`0 zAj{}GZbg;_`ZkgWI1W|qdvzhh5qxcZ0$^e(7`8# zPZ#PFcb?+!GxT>^W(mJRH`R20pjoDaF8rNaR#@liWh*qvVEC)#NZGrV6KO;cx8srn zft1C_5jUaIVECg|!vC52Dl#s1QsmNxMS3Bu$f$3Sba?+98eD znFG6fYi{k^*O@rBoY)x*?hP;Iw{GqIKUINFf6ugcTlQk%N#G^EQ;4nP`u27jZSywA z#87Uq|HE}|69VU@4)z48uL4aHymYlSE*H-3S+%ElY4x+kI ztgaT-I-P3nm%`&uKfM|kzP*oPYiFp@xZVN4QtWx4)g)X4(L22uG4nzGKJMOm1c@Ph}&1H z#hcSzqnA#qGAqeio5dG%OE2ubTZbfgs&bQAbIq>bHKmhTZEq|y7poX5Z;boQb&iQ~ z_N??1vln=htw958kW9Jd6d6ADq2aF<%yb0-UQ}IpXA$(sqh$E((U`D1+PCD)vYF1@ zyEQ4B>5!MHedoZ^E|}@GWTlf&I*OHU+Ys&*KA4S;_(PK&zQKyreV;%O|n8n=HkeC8SSWBR(N9ddGS$$AwOn3tkQ-wBP zQR(UNy8ShnrV%X20kmMI6=H^CLlXjwvQ^(X zkw_*oi_@Mt_WqEy&D|CroEb#$sI)f}PPK*xXZ!tw1aKB(m4LDT2G^JrQ>}cU$K>M! zo7{6nZ}RMg!~3=_pV(z(m6?OXgZopn`TYE{EI4w))u7c;qS9amarp$k1+Il1#QxI} ztTrK}sNEsm0ZDswrET$HjT)zAM<$BUqCDz(esZ$Xy-*j&2p$C~tr}(=dQ$1Ry94fm0Mtn*$pfyycdb zJ}ts=lve*(QCn~5&=~Z>vbMDOu?b&x%E#_&=<1A_I2l(sQc1hkl+M~Q_V`kLK=?LR z9!42l)+4y-5yaL%RFjBmQp0@NLS}=s28Rl>h@A?8G;uFvZXpL0ov{!SYb&f<2!ea( z_A%qm2Od*ZRh6ssRjRpP3GX@W9p^LSPdz1kTQaba-V-nxgI@hpJ*T}5E)Z$r%OIHm z6KG-h{Vq-$-;#8ri!Z@AF%^(1{PNfpflBEQoS^$`?W1X!X;=EMSbgiSW((A5&p4}= zC}`-+d&66M*<(`2%!z&$f4V>q)&{=BE6^%m8!?$_W0K5}M`#~`jdFA7^`|S%H7XHT zB0jlOTH8M>JwJD3y(zR3we@saY9cWUdto*8)Ke_Dxf$ADb;NIYGa`3dpc!TCMKiG= zhd%{l52<3&Ytp1br;c!C3 zSc49I6Bp_cysoC%EUZO%v5G?~H?A&ByKvN=Tj^`;u-am^o|xBYos^!NrKy%XU1iXG zYUk>&lyOzh{W_T27OBw8Yb$CKp~QbbC45tgt@r+G1)841LM+4|_$dAW3(;7%g|&f9 z#Pkyi4E7Ew0Mzx3-Znj}V)LcmHo-SDv-*>hy=^cItXJgq+STff6|r(w8I=CcdP^(2 z{HGmHjc=|?EFnrm$8oBSolKfiqxAF5BvP&H=~Iyj1rKDxkVu-Km()N6zFCo93h`V= zx2i4?!h4U6 zZUnLZSKq;6W#+US_HYNwkBroxZjWL%p=*gBLwi2hq-i$K6XKwOKUbHRJns+?GzqF| z&}(wO(JQ(Hi4 zZ#FtBw2d`^e*Xl!_ms_I$%-z>ty&n^qL?I-UCL1rFqb6LWm$Xb=29pHv*UD>^sH?WzRRb*j?`W?ty72>4dNYJ6g`&{ zw3&Ug<7~hVT-)*Jj^R&SeKQh&Zn=CuF!r|NM{b{3{Z_}}*||d<$1j;X+;Q$3vR4VF zrCaye@A&{bCBTh{wU8Dc1`$S_o+02Vacff6Ycz;B=oR2?dTolt8{NL{5qr!h4c4=V z8r_D^zZPjPxq_*Yq(9qUD?J-#jTUduuk*MW(l!H$e$5}Px#b^>`*p2Wg)k=_Ug zud)J)LCxs2#!6sdabxC-sl0EbGcgm4)(_6K4em)s=F@Ly-~RmK_=Bk}bM4t4Pjh#z z&lXwi>fF00^)}V)&Fp~m9?ryH#Pw2&LIZb%g5qXHmp5b+o6P(p#n#qV)^>eBSEGk` zFlz4-{(IGf?-XQ2sv#Att?fuPvadtkGC&~Qg8t)X_hxah!JQ6)B>S!v$s{~#9oo}Z z-)2Pm$NxRLeXwJ;v*F^0oPDX` zew-jRWA}_>Oe?Ss0(>1{>e5zxMtPG3BBY-QWFViU&Rt!QEQ7t;N? zT)!}WcKh~$_)KTRXkA}wXh8ZshM6LQa-1oV8JTnyjUwT#dsjr2sH(I(4No1AF8j0i zfV8K1Fl%MDj?PAQ-)ifx@p>3KDjlwH{g+?M?~qk)>*}dUCA3lG`CgN03@^3@|JL$x49+w+&%XQzK-dLr>`|W;(g)JE{$qhrLIl2u~^vG5a>up z$gY}z7Tt)}VU1(l-mDw|Fbe#XP_UkY&&VEq=9$3OY>rv1*%EaiTK{uv1B=!xDo!#S`x^U*K_n(!R@Go4wZSq(a%c2U6ehX~OLTV@3 zLgbrvvN;?P%19xl7!&w$m)&&qEn~s?%jV}Voew%wfseCG<_@->fBx*Dj@TjL`#V2; z_WX_elF5BH&G#NzZkk>_K6=ga8{av4_43j+NSa=@V=cxWMHej;8$_`!^3AMuC#4AG zfL&|!>h*eWP4`lC+fa?#n3;Qs8IU0BNl};+gz%2B)i;RmKIrObkS->bFM}@BLFIFk zc~?OYm&Xj6Ebj>Vfr}h`Ol`P{MIAyM4Yv#I?%ER09Gx0D+S8I9^Lkp%HuE*?-uFj4 z46T*X0e5e&tFNQMH^hG0JhI#~b~uB9Oirg-D((KD)8WzQ^9@bb#wKafHyZDo^j0`q zbK&Tqhf}o%s-BdoD!3Pv@s-U@h@eFdQTaL#%+lU^7Ie7?UCQO71ZQKLR@h=`J= zibVDG$VC0gHN4z2e&(rYvNbfbd%a`vz6oDNeQO`5iEy9G*e9?_p+Qg-1`dCpSdqR? zHaOu@3TNE0)+K5=%^M-;5z)qNsq6DZ;$FBo;I+7FYQl9LgRYrb2W&n)1A+A~+dmiCrt{1EZ^Vh_~%>MQg9To;Orj2d7*Gr&s|ePd>(&fMfy5i=7Ko zDrwPjIJ}CavB}0@y&Tqn1)`2DaVd)xJD#e8}*%c~8s&AQ){_qW9&fYibmCnUPe5NKh+05RC z`@#SW6}Dk6aJq)#g}#|vxOI)rqa|JA5mwkmj2#VRcH~;p$L6D30)fS@W4DjDEnT&c zJ{a)0=2+L{B+L6JjtnkeGg4DEZKy6@%$qb&C>KL(Uj`dMD3KgG$(wLbpi~K3Q_&A~?m<&RL(v+*M!tO(#xP4{UuKQ=s?$?g? zGgnVruxfjL+rgQwD(Nq_eU|<8bwVVuJtulk?0>yjNb*6J!lx-Y3gQc7 zCR;p=Fxg|nO=!$?=K2vt7+X=iRl?&F!RDHJ96pSJoF8t>QU{d}J*RuTPz$(Uof|_= zrwWi`Mo}F8kv-hjG&<(mv;TrK5AGe^8J*1yZVR>6kFUh14ySfZt?bHOrG+oarRhUmdH$Ee6dPZwLD5@UkVB(c-|**&;V2j8SMN?#UumEosu$85ziQI zCGoCE5}IZO;~~q<< z{@*7ps(tN3VN4jtCo}C1FOFq&JX=>|PO_`9H~!msw=!Gy#P*eoySgr3*?uA`4SA<~ zdZ)b0xO(ji+|%NT|R&P(!l<7YX9Jw=co38GJFYIP)3nfadR5lr<<y4)~%D z_0dnRKKpvD#iDC$QECGEaLV6u=(nrHd6m{`ZL(<8Ztf9tD)b`izxD7R4M!1b-6xfL zhl~H<*9cF7(S%r9kv3tMRxtbs!y9H#fLKQFi)6;yofy3Yt_iz7qp==;>?7%$ul1H= znE`*#B@=I2dVFqde(n{w&dmfTpl$A1jP^zv#f{g;TPy2`&$twh=# zHCxJqG%`o_IJ2QZfuMFDcnre00Nct{4d1A@@64Zzx&;Q--mvNCuI0Xs=b4F@Of~#> z?RozxsmiAsKE~R^n||aYrv1Y(i1am6Nou)SLN7Zrb4}3%jKGZj`2Xht6YwP<2HbP0 zkc8*=Z~h+(dkn<5r$ z{O3;OP3>%RXU(1cj-_*E?yiA{W(N8i&6HGI?gZj;Y38FPB&+@^1-{UZe3GAKV1rGm z;nD47HB>hL7t`nH9b3bTqMyL52ay$?t~ksnpGOHlG(W-GM5p^=!Y65y`C|dQ67?Kx z`cmJWOQKf>BaQjpQnR^5!*MydLc9nOk#64Un<2j(0bX>IKsd2^$RA&u_1Nb3*{n;O z{)Q*FW(|}v(5*gW>*izVqe}B<)%uv;{3z@DN655}@ZlZpA3>&d(qP~GKSFQEv^CCF zyJx_naQ1HU0j<($G(`2fmeRj8 zTcTNvuQTf4X{P27&xIHrzL^rq{M6Ng*(Zy0?370Zj+)!z= zV)9S^!wU<9!yrS$!yBLBUf5{Fqtt`yuiP#0fvI~wLoTBAj{zT+xkNBSo2j*JyJ#<$ zj#gX8#x>ocQrkj)Pcb)LRNZ-JGQdK_p>wfOXwW{q@J2@0px!%(YyIS{4$bUXr0QtGI}%0``vbX`|V^Y*G+pJ zma?C3u*~ zM77H{iYYar5Hc#hq)=nwgIws;G|hWh3U?u!d)kq4yEC>@I@wcjx3st&Hj9fWPfcmv zvy?u6U-xn*v%K4zvRG1{OremmI-OShtzmSAdl7;FF6F35&jR*p+Xf>{{VIjZVyAAM zXX`eR3ir4it;yGd#)ZjKg^Nm0++%Eyl?hKQq0~>Qw284qaxksj+UJcwoIL?=DU%xx z=2o{+!Ildf5@tij+*b8llkOeJaE@%edVQoLhUBl%3?9d!xST8rO4>_~1}11|Ux z5{W+B7b(rgTwTver9)zAC_&ye(APTGOWg^-XX#M5g1YE@g&$9_I^7z0nn<{}z@|zs zqIQ^vC^drACr}@uXqpMsd23!&qM~3##ttHGiR$%vSF+zXHs#LUd1r*vKfCwh9O=G% zwy+XTEXPZeq1fKB(r@_hbju|DGC8(}6r!HXPY&|mPN&FEO8*phtW^dtEEAn}+GJ=Q zOQ-t-ea{a9qzPyk8psRq%nvYE7bs8M4o??K4(h57g*OR4@w3tM(k@p=XW%WQad2WK z7MbbF97{zn=$U^-x%0$>@2*^Karf!W^4YKTBimWL&u=tO8jQKMN@ba9?RsbvU*;^> zMC!mP5SsdCFrO4Sbz`7{4~h=?vb#5HimH)v%Nv2q^UNOpgPS$KmpMSVwguB&XAn{OV4L$ z8PM?N3*y0t){G2M}l^rMXe2WfNddLsHh!?K=ah}v-yJXP-|I@ z4;0QE!VRq$>}^LJ?pdBAj@9)ZXIoz?KM}e1+njSsJ_ z@k*@GiZ!+~Z$Y|7AlkXsh+yJ#_#RQth_$U{?S}@7GttwR2IoNXr&BrRskKkAvcDC( z&b+R`Kq@Ugm3=bK*-e=!u$*q$7?xv#yHptnwqqai^;*%|z`wRc(b%9;qRm$#ox5Tv zx;es0vAqA+!+mrm$Rl~$4$+n1=+g-s zFkv}WP7s78h!pue4Z%4Ro>AV%XfntF{GLdMfGrli*plszW=D5oQhIfr&=_Ooz5DsU zBgsq+G5Ehvxx)I>;Jdv4gSIxSqtiy_SSFbIyhJcmfliaG%qNt#rFzNB%?>Q1HocF1 z%kY^iUS^7fY|U}HsDHUx>im9feVP<}sv7v9y!^j|kAb*GQs4#r^1y7=D?hlO|B^P^ zokBQ@!lt$Rt*RZM{q@1Kf!36=ks}+Id5g#vF)EfAf_7*x^#m_Lmf(fv9iHcp11mri zIh5A|LgONUz|u#p3Sh(Fk6TFz$U6U?dr!|vz}?;3%YXYNDG4|hShLk*0ZHOSFYWQS ze+)gh|MVV@em?zql6^^!%;BjvM;Rz&1MO3P=9$ud=gu%$+BJ9Rj1v}O$|V2+wRRTh zeFf8+pw@iBgV>>4J>>O(lNxH(pKDqWLeG792x!?q|LSgNK6m%@Y^<@b;CIDc3MNwX zyUN2Bd=9@WO1-#CyUszNp6~0koPz{WbHf*LqTSG_Yesk`mBFwrC|FeD26cr8wvgM3 znTqJJR3gU>HWe1xKS*@wcvr{qslskob0LhBn)ZB1VQA!tr+aTPKj85Uw2e*r2FR$x z>9W}!4tf7Ib8}bs`&^EIyCdK(`jIxlr08553XNplPy;7vncK_Df%RO-OEqku%uEp00VRs{unQkq-+}oB* zdoRS$5=`RFfTRIZE)+C+MaAHx9pX@fy_BSUxo#|e8H7(|RF11yqaOxsuFC?q?zW#Ny*A80M z!KCRvQPYSuXc*bI@_@{sPVenLdK&y`UkDUi{a|fZ2!WrN~}$Fhx%8uy*C{2?V2#yD(gcRQ0KEjN#n@y zmHCmRrm( zbvUSrH9*G~$&n9mBB^=02XSBrdb_7u#LB^i+Y1#Z>7O4OtiG|Q=SE#h>rLHq^WLkw zQ@-IBUm(fwY?toP(Tn!&JH|$C=AOgII$TLnJ_6hh)z&R|p3(ebFFOzJGqDJXb^8oK z2frF5@3cCU{JG{u`U8=?yCdk!B^>;r0J*~w3h)n|Yo-L}wE>Rj7MfbAhE&u=Z_5zp z3q7%R%$D}PdF_Tv*V}u_#RChRWokUs8E*c~k9#wTRIDEaDTLdkHZ0dpyYrxI!)ZQe z6j!OsnG86Fc%5WVc;m2Yvc-0&|W z@a*e5lYRhqmB5UDV%4Rc8X%mHMF}w^5V5T8%2v;nBBI9&k_S>VlH2qijnbuY#oW#E zB~g>SNrvlNq)2HJEiB)$G}fd-4i|~MsZq4NXF=B7BqJgu(~^%Yyxm$Heoi7D5{d1_ zn2!V%9;A+FlsQ3Hn)xR<3;!EWZ$WQP#@tP$mH&|`5%nvS`N1G**?4l#p$OJ3XXJ_U zM{2x*Gey8yD};eQVAEiieOsEVV634uiV_4lS$(Lm-WTmoXr!1CSOpPl;$5-zEB6eJ z%=B};3m{SC!QrnD^EZM*8U03?+pGA6=&4_*;!1PCbn8tA5ANNoUq6;w#`uk=&O`zZ zSie4e*_pt9@Ln$bvUAzf)kTiH+)Su(Ps250CvmZe7=30#l+h|idS-1Di)Ci@!-vFw z5H<1NaJRQ0T`|IMfdE?Qo<9Kb0vIKNeqE!QptW1Z5P`ow%)Kms}QE+EVaKxSJbr1GBlX_xo4^fA<^F}(Bdc4v3>lb_X_qYt9BKdK0 zcjxRbwPIAEYCASQb46ct`pT&*K74UuD7N=4N6Ra{9%x{N&2NBPy0yXS1KFvPRPp9}{nV}hoQbM2C zoGS-58;$$Y%jUpllV>J>I(gi0o^3LW=W;|C`u5ee`C`{%|3XzM(dBz~4u(+J11oT1 zZyB}+Xl`Mc?#UlGnz`00P+M>ZdY?|O6}Fc~UfX+X-%(vW)6!&2B@As7v4uf}#MoBh zKFiM$11A#Cip3m^h5VD8WyO~;W9I=y?w9ORfVvUE4Wd5vKrO#1bIJC>MV^TcJ|p>o zFnj(j&&?h2cew93bo2Gsb`9jZ-dNk4mg(_ix3BTZM;;-xI6>-Tm_Kp|aR15u5(f)e zhjCpl$Q;xKXor=bp?Tc^NAVq=K+N0*fy>C{B3<6#Xoqv*cahL3hPU5&D%OlwWzoAl z+%I9EjKcjtPJTd5Y^Pe?ys6RF|BgGCl1HM4 z2g_>%et%`9bK*o7F(*=Ki{H`-U-CFVot$f*I<&etbA+NAsNgN2LdePuaTlZwkg0pH z(SyZM_?nH4|A9@qN$FO{2SOCf^oh=a0S*a61atJppF~a6JdF-h&?DWVMqnh zJAf|8#e&^mh7>1Mu&-}5h4IYO*X6pbb@eB|KDhQEaX&gU;u$Ek4S2_T?ihCu?8GF8G_H~Plpe#iKfkkf_SIJj8y9@oU1=wM9xjr9~d3jwLyG9i@CCd&nF;t1p^=G<*SXSbuK)l72pfUH))9E(DGs0WjXWn}% zogC!<%Ke6s9Oal zUhhDrwPLsR{tX6!&Ei%2)~_yVn}?e;iKR-fS{Th(yyOu{GHj;lat)oM{JLKXBo3)-RRKw>?1XTXS~Xy$Go>L*!qmAxR{A zyZ2`PrDBnk<|J_GCneW1_mUz^9uuHJ(neU>Kquy~TfY+AN<1`ny7q_r)y5^GkBGu0M@<2ATw3 za3He~OyzYZOpj3gN|fpY7!NK?DBy9<>3jvJx%c9s@HjioZG&EKe-^IRwqEj?b4-!* zoqEoZ1&N(=a`suHk|Tl|sZGeoEatUjI4t6r5|_NTu6}_4P@b|QD4H&Y)29{wOi%dm z`a*HAGEJU=eQo%{u2)_;eqoWn5Eiwze!;E=HFUui_vrQ?AS?VQh6fh+BMzWs~XMOKB1vKxrGbo5#}QJkjGmXSk{W$0X~ghlk! zs-nmQ6(*fTjC`mqgDSCQvg^Q=S6n<)tyUNNoE6TS^d)^_si=n&SzP?efG6?#n{U2l z_`KD97acpG>7J!Y1qAVBLrAS5rqU9IVCX1pA!D$DUImQ?N<6uvv{(*meS>Y;inrQl zaw}9pYw!Mi=LKV9C(6;8t0uXJ+|zsatweiP+hP-KQ~P8RFq7i>qxgE@m2=~_U4O(6 zFOK|cH^5vD+yRFeGo5x$GrgWNL(T!d*xL| z>NiFYx&;zkkk-A&dAh3MTlh^8-A{hOd0^PdHgqvF2NiI)(|=HYByhm9+_~&b&m7NZ z0(ncy88)^UwdO{Z-LrL1ml{9AJ>BD()I5s4CRZ}sQXn+xoD6PzeNkLo-^ zyHt^p(B8j2(~iywF%bOCpDNIZbl#Go27nvM`R@v`h=>yNB<{Iv9t zMA0M`H_4^#@8`NUzIyMy-AztsvH ztF?}FZnZMV3q6E>wcP`Su+SR$-Bv62-}P29HqLqgj$$3PR^TpaXV4X9fg+x@@g^_d z8V^KWXbmcofBpo;8<6<7ZOu`%_0DvR`UpXE;obnqvm9{&T8E?NKmaEKgc2Y($evFR z?B67Bdi*=zd7S@t=;Ax>y_YLh-#_@JDtVs&JNA_Iz~D45z-gJ%3hV}X68-9Mr3EFW z&J=6zY#9{fyidr$A;c|GNx{&lY8=}CEW9;ry` zDnw^yxzh9T*4F4p_>Ek;HS;y#PXg`@zvcR2EpFIhb=tx0L9?kqMg~i}T9;P>10MHS z>*D2|m22i=vjK;zkNg9H1&1$FE60`1Bd=bVyKz*ftEzPX8|#`aZ%J5QoNkxUN;jOf zlF`F-1K{vNr%`LAg!3V`U8g@ia#VPlPMRJ-+J{ULM#%|^yZ{|cXeHcT0(lt|hUO=D z%Fz#PoVohi)&KbLt#96QXl-`r*bx%ge|;ZUdgCoej`DNoql4yJ2TH1!umS~jGYHLg z&EzWTB4Qlr>OwE*?AQ_XbmYiCdr89^Z$f9o=U;H-=%;(B3pbk#a!>|kt91Efbc#;B zHUcM=?MEx4VdOSU8Ict`@n?h#{ppv#{1g9~8pa6yk=qzJ577P;QC4b~V#{qX-UVf> zm5j&fD4^Hm?QCqJb<|B;>9gENhEGLf~aI_o$?bkMqzH-C9 zxf{n&%uB0jU+=x(M3e08RV;*!zyNogZO`~Mbjm_2-87+f>u@x2m14%* z)F=k}0ZSN7hm8muW0od?T{tx8c{2tP<*+Aaiy?~#)_w5t5jcaCG zd?{Pi$TGwu>PFVEDa;2J7?!|NrZpP_y}du_?agS&r`5Tfnjh9=&;y=D00w2Aub@3B zqOZjUZ~hgnaRx2cO2)qfxNQC&tz|Zv&^q!p3N5f>;${d%TV;xnzD8}#vFTuju`;c#0t0io-)&C ze~M>EpxV?&oc=f!7C*na)&NROS*C1TS*KzOi~>e4P3FW{=G}0p6iKo8?kTWL z`X=HYD0W;=VM9jVPoYbX%0JMb8b>&*t$Rp_kPmWXp-FFO`s{%p{rKR=dmx?gPb*Aj z#SdQKzd)L^Kc?HY>7%cr!y756fLL<;7P`C#T>>-o6m_)k+~hxi_m#sOO&(51yoc@4 zYv^lWuz;CB{|H@KGoyck?;Miq!j_9J$h~5-Q=P(Xn2ej}dD>w{*VbWbRs|y=)a9=C zjVWPhOo{ak;qNbOKiHVt?H~xx@wWq-_?EmAW5O#MA#}6~AV#AV0LeS~4`c%i^OpzT zF+BXFx3fSLKN~NuKU6y(Z^b)iybDaH;v>sg2!(+u{SZ62x6Tlbh(0>@Q4z;YUil&J zgY3{8Hl(9+-c6pA$1-OAE`TIOzFX_jj~;PziXIWMDqx%lVJ-KNnM9!O3I9 zBSOclv+pYX!GMPU0(!|PT>hYr3<<#H{0z9S2T*YU7~8_~(Mq?TwUW^j6z#Bo9EPp6 z(*1*!L8r61M%!65-zoPC8gZZS>p(a>&!uf7?+K}!1QJT zOlispgjULqSSuO7f`UnCrN9$fM=soIWpqO5A;eTD;aSRHgw}{{yWe^bGBVR}2V+O< zX+{m`(=rs)y$(VX4XJz@>)!gljKZGw7eur(9i=0R| zwFfV%CdM3Ow@Tf%-j^J*^7pG$g#!#2n3_nB1>PwDE{oJGH4xEl6hJf$!cDjF@6Zq` zkVYa{1XbpD$e7G?j459=+alGn3do&L3e9$>lH`B$qaXc-|1X8jp_;p_v-7g0&hcPi zywe;|DFa|;BCh(r>X)jVm_TfszhQVdzt#^!i9|;3k;rPq*kbac74!p&2+jZM9vIh!n2WX7!dTrj%WA#d!UrWzCe3&l=CchwSu02zvK0W2&D9PK}v50k*(QJUSi3lN4s{#KrJtbt03>nEcXUVX>(vc zp6_#Z#!?kuZm~T%>$9VPbGp;n8Ho>u?oN+JrOKu$tv()g_#J9pq?ACAszE)V(MCfK zzg43RcVfnD4s0Fo5!Ue-U5C(0*TGuJsFSWE0&yPmt+zH@b>d9Vjxeb-0*15wEM4=j z*qR4``>j}W5C8yQIE9QdNjzWk#$p_VE}mSoGM!%TjSkrCeSyMY_oDMcWm~kXvT*UC z`87Q$i+5Giqmibjv1Uaop2@Xe>-LY2@OP3UM=lwqUiXl}$)~XAGW^CqQxS}O>I3s& zyralU_@~hwkATyz<~`zh4OsEWcz z0r+4fz=yRqTy+tJj{=a`Zl#d;MGX=!aB9p8N=`D8@1kmpSkH+LMtWItd)#2HB4xwyD7Ae?4`41t&C6$ zJ%q&DJy1d|v_|ChRufwE$3uF(qJv?#XOQ zD6vrUsoA+;a-wGUGUPLkm|?~jH~q&B5L{|Pb~D(xs3ECU6^nNzNcL<{p>_aao|6s# zzCBMSG79sY9-|^2-3CbORC}X^n{c|ASBvP|-(J1CSuK_5wCTAv631Z~5`IU_q(7GBN)pM63%LpAf2kheR&pI9ZcqZQt#4bErgx{7(wmp54pz zBPUmgmUrK=j~p{b0%}blsOO!83O&tXwOY~%t(jTkd4tMI~G z*S_+x)theG|H-c%`0Z~=h!}tJ6aFdw@fz^J6KFy$B7%b~0H`NF{_^6NS6>hN3IDF2 z|AegZe$^gOJpTC6 zV4ed++VC9t0(%WoF^F27@C65qA*(fLGzP8Kkdf?nhxPif+Z9338s5t^{FQr=yudaE zSM=;g6}dYzIX%~D$mI+h59Qiu)~!7Iqa|bf&xsfHA>K%m zlN*yrGmeGe!58shGv$J`m;`Q#Sqz_Wfq?KXE$RNxrJ1P<`yAK3Wo5B-seg#ZjuTU$ zXS(&kh2#ALxgH0xVoaDjL`WyV#?}i7eqbcSA3^a#?OO83-y_oxH~Z?x#lN_55ue1* zqOUg?%fmtPF=SjC-uN_fQVe?sOD66j^azpxP4%60(bUZmYAsEpXC_g)O1j#dUZkU| zfALuw|B9^;(|Q>h-~cVTR!dvA;}mYEx2v62^%vKUOPi6kPTZ_(x@7S>nUa=)YnEKO z_@(7ni<_WG5gE;Hw|ulo*DMw{s~eARWvpxIu6k+0x|a65QHO8^@+iRaB$C^Co15J} zFOu7l`}~95W=m&}o2R*?kW3SMcps34+C@C5)QuPJqpl3z%@7yB%%K1a{@Wmv^xnn? zM?dPXLuz;e{DRygtICUQuEFlkxH%U^;T0ht^~s0F7J~D$T?ZVlA=R52)iS@`WLFF6 zsJ{~EiFJ;F(qPByV~JR%Oxig^!*h?=Pu|Zjz3iworxKq#+t5h7h&$WokT?eNI?7+6 z4h_wf$X2u!eh!s(M@}a}0FI+-K(XKHEX5P^L3?Da*ng;KP7EY^Kqgq-Yg2hRJaKXN zm)b}2W>YZbcO|VR&A86gI^7ZN$%M4#NXqBS*{zy6g}O1d2!PY%dY1s;@Y|?cOLp?6 z;K|7sCW8rsPp^WLQq_MK`K2kJH}M_>97_geO`Z{KA}o{Kjp#!JjJE+(f#%5RE%>E@ z2-Z(Gp&;&G`pwe5<)zi7zN;6OPImKJ@+tBOV&b3X$L?P}uz%mjK0R}Jcke5v$li>;vzQSyI=o0q(5oS%#_^j(oE*SRqoE|RAp+aGB}3hE-alZQjk#BDO~%oE4(eC zb9-N4v8rGEB{+(ZZ2M}CRWP`~$}+orb=lXyuM`}0dQCY;q^H#!-&1iFEKAmQcV#JI zj`u_yS+mzU8Z7PW_xT2n4CLp1zB&26_aC2r^-8wISkW3nqeuIeZX9aS|L8{s^U#e; zeMd(_25rUIl3jWA^z7>n6kPa$q5diC#0kv0g{tFvwgX#UrS;2mU(KTv7w6i0{TWkG z4;Jrg9}ON`x~$_>ulnZK=H^?cizr>4FEvW4jZJ~+%GJrGzJtfddWNzE6Hh%YaBxL2 zY>QIZaZpR7hNvG+>M}{O*{78N6Yl>25udksS;uwPOLxsjr;4lO;U(l%;~zPtPgHqj zRG5-Z3pzHlB%&~{usV5E{1o^DI`tu|NUk%Cyc;7yt=wN@+vj} z=id0m*2GyEPthmf31?6+G=|HK!@|tG}@FWAh3xbl{PEhiAs;bE0>9J@0CxS-1{m-k-g&mF|h&# z9zcl|642Z4ko-oLjPRdge{Vk_cetI+3a8ttpj(2?zXfB^YChDX4V0B&3=d>3vr2?3 zEsRn@StJxK!VqixpV#*iOF|@9$i;(?R>b%{F@XvaSt8|;Y2fGO^(ndCO#@oN zQn>G9V_I;+VK=3Y6M0%235ih|GlGDJO1G${1<1)fI1Jq2{nPiS_YA7s@$T5eT<ks1sdwY&=dFE7oA||C?nOy_yyKVTp2ztowW)L>t;fK1 z$WixuHwMP4sNcvL;fGRyPxB`Jhvx(%7I{uUQZM~$xpyIHBpr_BAg4$N?2rk;s5NyI zuHM|cmM>IjRg$K~CW%Tbhd*>7VQ?!HCWX(}@{wgidc4Ip+s40fCmcOJ&P&@Dvoi6B zSkg7fft10mevP{UAO%x5!vanhMgOkO?O!AZmo|QO_cN^C%}E>#>Vv)dehcyTY z_0up956}w{3Y+AO{5LnA)_7D(lhOrGB(YT5C`KO1%?4N|Wa7pEvf5x!g;X*FH>Te9 z#Nx5rjzHWwIdsLLg~;?;t8h}pNQ#3cQ&wX1gpl7C1QnxDQHGvV$}oK*@gV<&J^cTj zB1ee{m7|aayp6lq&@~+7CqY&|4QZ;4eA+iqHg3ET-BOl9Gepx=6fiRE;3P~41uLPt z8M^@kE}M5GK;XW6j{M*stCy)Hht8HIe6C)yQ@mpm4om`;R1|5Y2_tH9u!<8g0UA^f z!ZdC{>(im;j>3+w$ZNOLRAX|VFxlbv;Bbu9vsGt~-fyb`fBoWb&W?k$xQeEp{}&!Fb=;#Y<|TOz1#1wpw@Rh|C?5!h*9)-tAiajS zFX!qy+S9ojbH*kjy))6F*1$l)({s^tR^wcYJ3QK!sTQ5)ba|$I7~DPIe;xPu&SGv8!zkjW)y(P) zg!EVXdI%XMq*5$&5~4Sb>y0bBdRG(@<>E-+a!P)Nnr~dgDE9EXI9~=zMv%F*cIAj& z6y!c+wP8(LW{865yGw;5$tv5yLZnX`tQ!N$pmOgH#kpDUWPK>WJo?WPY#K zW45?uoXl+tq~-FwTxrznjjei}Qm<6Bs#M&C8#hjTi73l&d(Ve=PxQR`ZMSxCG+PG@ zSKM8gH{}A<%Mg@@B{rm@h>>2P?U*}P>Foa8(g(<&o_X-#0sm-+Iiga#^wIQ-O}qX|I+aY4F8(`ut=34= zp1dp7!7nV4{Y$~HZ+h^t)<7_x*QlCRTEE>F2lc#>yL#gSZBHc9Piy5VHoMrQL7MB% zXSI1_%W(KWIH^(Vkz}{0-Tz~*`NwUkn8Vg=ZBn|v+MWxvdyu7hVq)XQxXWReh)QA! z2tL>!_g5@}(i7(Lji}<&Fi@LSaLrFF^<9)daQ;%In%~z$MM(5Rv9FG72+yGk&3<%u z3?eYLt(K#^?iFZc)Rl4)K`_?(_Q!V>twE*QXGnJRT#z|PJJ0PYFA;utB`J|iiY4Xh zJ~{&bzeLelHkkPL(h)Ypq8BjXC{qnUw9gK83jG@7$wdtGpWqkuI<1L(f`Y!d5m+LQ zJ;ZS?=+hlIU)xQ0K%mNJC?~PaP-xh-lc`Ezm8bJIny|azadLu?hTD_F`zXMMB^^fjujX98#D>OCF8!slo&SQB^ zaH4H@;WZNXmx(I4C#_r zcxkptwAYdu;<=x(=T3PKr^&Y&A>V{QE4Yzh@u5US&>zoe^2y4A{+4ju6YJJzlfQ-) z@6Y5F{4cJq?hfq2jTCb9%HPxk)0M+(bZXkjJE|T0VRu)eT$ReH&8I$^h?>-B%@x7s z^D<-hk|qB3mmT-7Jw5!DXB}HG`g{mp%b*+EMxQOC0keJzCZ8G=1%C;~5ml8dSv%T7 zBVK24S9@j~p1PRE7>5sV>LIdV4P?f=%tOb6s&}T z2sWMt8yBLXU?pJN9Aeg#XLj$k79#PYTe%>&wEEl$mxk;i#z<#4lQ%{ti;kGZ*y;(! zG;Q+vfk0oiH8RjYo{4nj+dSUBv3=b=NB8cEwT|=$T8Cm4Q`qLn7aXDXR#Pks6syM| zlur?}w=NKcY`QSzY^5;R-W0Ygl+nYI<8Iqsa^+V0yzLfeOTD8*++RJ^x96HZt*W9>o_8=gnzLK%cfCX3qDb%QI(VK^ zQBi68uGzD2vM22IhJm0sM%?-ExNo5bkTY0tsA%i+F@XevNZUs}af4rLGUgols_(Y* zjwDw{enr;$x^8}bsh3=l$jc-HvPREnSLf(>ZY2DkwC|HC41v2Hks6y%Z>q8RAkt_io-$T~4G{he>Cpuj?fF&;t3v;7>jMS@buMOsD;y9N;V)zs1zy z1I%r5*9%jJI(xe92J;3-5R5mtUEjTM=fdYd|9W(eN&oy#ah%9T9G@0SDg>LHpe~t1FcM)2z5-2P#)yX?jgY|bv0~}iz{q(;F8Xf^ z3vY~&;<3?*!NG~KfdP5%HH(WUd&{qw_dc=l)E|9&U)ei+^x(n6hYub+N*9CCUc^2K zq1wXDdjUodDv}DPq-I!yJh2rgEadDVe?np)lkvZBOkSv`nL=`)Zk9AiSKU2{3_Wrr z1ahbJf9EVe_0@7oE$`>=q^W`ikxfd(^72q*08I7RDVlZ?;!)j8nF^xRYJ_BnQ1^dy z;IXCg2Pc}yW&A&Hb4oO7sYs&MNa?nG>s!6OL_Mtvx9T;qs1`lq#2FBe*OBPH$R_=I=HI)+g{ZDP&ENI9o9>BZUCpGVaAhNx;pe{AvRCq% zc>FUGS7++oGu>Y3-YPfrW~Q7aV} z`Vdh|`M)jTZtXJumOnf;zx2T3{Et!+wOVGl&M2(ysewNrXe8WASNZ$jBZV1VU%rj5 z6i1#wcz0ktH`Q?%ob)Kp2>uHSyDhi3Q5%k9?*z@AfHVrCMyaydqjAT)O;$w{a^Rp8 z`z@f{;=h&ZV462xr=9!&%uiy+A|@{M4H_)cGM{<$)>|JXH@Zp%%Lt8dZGd0FQ*1z(gKNXRR4AY&xiQ+^ zWaQ6$kJ_qKYMWZzdf12%0z-~1d_yD_!vNXCMw3azVUyXN%)0#eX>a*-w)8qO@U{AM&s=xuhp!)9~X?Lc7~@zV#2 zKo4SsnrwFF#sotbY&Afx!fB~ZcUY7tcm1TzWVTw(Cff(_!DhpUU->HQ-Nn^`VEOXh z)0cJgLxIVz@Gyz8t;ha8zO z*E|3?!M1j4az%mNZ<)Ea_^;r=^FU_bKw;h&T#B}Ky4d|{zd=_vaK z64ub(%)avrh3=lqxzwl0$M-%cev}_skRJI50&8E?sKzw9WE=tUkw`G8GE}wt(Y{1i zvsgKh8Qmo(%0?pMf8E7DMAO+l!-`Z6VZ#oCa_K3FAc9KG*qfje=d+^vhnl{PMCQ5H zsmQ`YbWht1N+P6=cH&nqmzar>l|shhczWZv&pO?6vtQe7tO5*T1eLcO7tihPF`oclL zAP}(Ijjcw5xee4iQT-etoo{~so}uEg^~DIenZHr%GMn8}PU^Dy6HW50Txrnhj8VO| zS=X$Hs#GAkMv(S5VcNKbpngd;lPQynwzs#&qCsEbt@MKjeDm#HyOAzTZ8ZN$4FymC3}yo3BY~_n z*2zQWvM;!to{51i1C0hL?R-(dFiF10>ogq!!9Zi&>|zss83WCilHIO?_Y>rc4VFUWhuF^kT_VL-9rUMifi^Q z1f<|VXBNZ?_8N=c zr&8Ip9`6EiEG+Q9a&|u_qgI)CoICi$6C1yMp8r~AG|Eggmx|xZI6mbo5fIySjnJNz zyGTwatp7)>FaGoF3`cbHPNMn(i0aj6<2@I>l$=r`H^@=J^K|nJXgb`XcbaFi+vb@( zBt@i|cPV?i#(g0}3rDmg)BI(#zYWi)6}HaEXy_GU?dOQd+Tm)R8+qV^$u@b<8^-t) zzwtS=e!$`29EE@9?2dO7X{1#HrqH(~h0(Nc`7_+1)ugch%uP@8180}Q1~(f%cP=5U z4N^*wCEdoI4RQ(#HzF+WI3-y0iist80Xm7;w>4`EXFBqhNk@04Z%?Z0#8~x2cYJrJ zr`^-K@9h`|gAymJy4B>s-Cnv!K1qWB=ly zv?^?EkIprysOs%aW_sO2qp2S6KN0Gk0UOCqY7`2sR-w@FpFHQ+T;QBvC(ik8@|@q2 z_n!0X$#Z^7Lg|rkWH>#%g#VQW21=#={-Q>y)M!*H)!DxyEocAk#j}5PuGcpHe)jjy zF%w|>2f1V9ZK4pOltu`wH#qvukQ?90?T3g3CaTB5XJ!_#7hk9*d-_fuf8XlRK;P)< zYA6wFUBL^+_>IYUJRfVZJB;X~fTmUSAqT5qAyPn&Q+g_`3>{qeCtD-?@pRvf ziG=XJ3EU57kkBi9DE^GUK_=S2^n)M33F7+``~%?XNJhx*Vh<>&n+F^VASy#M2P>rF zFR?vHe*GZ-jbZYd;o7asJ4k{SH{`#M?$_}4J$M@nq}@aJk!6|tBui{g*5ICqyes5& z2X?{Dk%;-rG4K_Z&SJcogX1N+(bnCWP;7jdP86(();))-DK+oZFM10i8N`9C7KDqY zV1}PTF*VntjjWeD7K=?A!%IurnEsigxS|PaCa-x;W0H;Qtj=nAtKgp@X&_DffAbei z9m}6ilMv~42s=d$+4br?vzuL;U&V7UzP!|+jcG!H!G5&V;Ax~Wvbz^P{&BA5iIG3z zB`V-_zyeAwHh?D0VMNVdGHg8!aJ-D%_nw7^#>m(h_pxeqW0L#WeZR+#&@UH9zq)Ne z3UI{2$?jPi(nVb7(@-%U2~_ycHhBUbIr$2d<&q|sRq{RPqYMZ5t8izJOWvA_4A;T} zHM}}S*$hp>KnaXsaup2DtQ-rj((}2(b`8lk#0$Y9@XGd!_jTATwsNP*qAm5eD>;?k ztWcR6)yb&5$>VC2T8(N|VJ;~aJA4+cu342#d3L>ZT^#SUG`>q0X^c)^HadNNP8V=D z>6@J{vsf04x)i2HeX}p6Bh9uJTe-^>?FmX+e;UGhcTDBCJbTC6I8JS?yfx8j4R)tW^6R{DvV9DpGnn{-pc@pr0FtxpK zbC;O<3?gcTcA*lHNA(dyPHolu+BxDXCkumal@@Vx+#AJCzgp?FOVmfp;kBycC$Q^NqHr*XtB#CS4s#mtBV8P=Brhj0lo26 zx2_zD5K?M)7OhQg+5J+7Mc*RRHU`3Wm$9)i;INL)Ek#{Dof(g~*{0XGG^%^@Mr)HI zly#T}6HVSoutn5tHrRK~v{bHYP36q=_SB6Xw{zcxwmr-wI+n$a>O@<{Y-}yX0qW3J z%R>h55&;C;u&F`tdzwU~DXlpoMlMl>Dd5cHbaI71n`&O~p2U!u4fN?}}y} z)>5fWuZwt_ltUA$rf6H6(O-%*HX3b>G0oMIW^clqolVA%-$)YquBhO|wk$w_;# zzc0{YmU3KEy4(>oIbZ{k>IwyoQ4=q>U_mXLe-n)Yg)eS+4Hm@aRj=o4ruSHMYw2za zs{yq^v1ehsvCo3~09l#kT&pR_RFbAEH(|LzY`ADbe4v&X*aGpN9`6;XXvBmH6$gy^ zFR9(FZgHD6rd&#+cG(-vCV7iV<;iul7~@W7&}j<=6dJizZx7h59=Wo$9E=R-6#DkD zv@fU?E0hYKyeYqw(YAUl0kvDEdP6@ab0)2Ul2oL%8CtqZKhalQud~_ZMu#C0wGvL+ z)Mzucw5aWEffk2crEl_d9hw+D++%METa4jwtVJ6Rxf*q{7KhRj@JH;1WLT~Yxnlzn z$3Vss2&$YKi$dJe5)TrMq3QZJ!#n)as~S6Em6AruSx~j3rI03<%B`}27N5%Oh}v4S z<~Vi5R&2hJvxrz;CaMnzH{(M6Y$_mAUnmN52CfhTKmEu~Q(izS3RcFFU`DI~9!%hW zOnGyoS!Go>t6K{WoegQ{9i~(zVs4xp^kx*zNpoAq9V|AdQcAz4aa1ps2a~~+C!KO7 zQpmkybu^~B{Hpeq%P*42J5$Ogz1(h8nbc05QyuIX9d!+iYNX0uVr?yY>>i0&sc$;J zS)y%}t7Oqks5cuhAfi^}N@fhlZ`ntltB5_z)CVcllQjStt~!tveY;JyQjMk4uyKIT`nJqc?PPU-rdpU+IZzD@{Y(% zXZvJSq3CI9YRh*POHXmO%viR6z0IhfMM=>>PZWt0E5F5*%$sWR1os7ct$o%hK^Lu8 zW!XN^bV^TFmg3Q=g1^IVHHED4Qf1)tkKFJY(skKP`*P6PS#lL8!qLU*z{BKFV5FmM zBHAo3H#HV=#YEw|^luFhDv=1E=CHPP9kOl2zrwRv)LmYw#q7Q-UCk z^9zha6>dhKxjV8Yr#$WT+uSCFRVOvX{9TJ<5mU4yB6j7x#x`I1qCIwXz9Zzf`9^yp zYDuH3V=|R1hKe2f_IK1IRRX;WGYHl4Xy zBT;&!jRsGn#w;#<7F43zwg|_VenI&p<^KS%(Lhf)v-sgz_6z%X0<$7O_-zdP+PJoTnGt!CD(|p4pZe7 zILhn?V_lxh0$=F_~33dkS8oSuA(L`iOGFnNqi1>Fu9d?^USf z{Wl!z@p)`}*8+{&rt&M+`xR29E!^sFl!w!CM`vH;a7{#U<00h}I#BOkF(XN0Ep*+3Dm|ySh43q=GT@kHIFK!a|&BWBXJ(u;w8F#3lhwwympZs;qy zx?3&!Kq-@w>rt}E?KWD6VsgD)6z%M?9K0U_vL9QE9;DFjrhq6$F> zb|5O>@8_!bKXXN;Lf&4f&>#r-S{=)Cs~h)ls}Oy0*hMP<@7o2Ph{BSRMlWT+bz%t! zZ_&zH%-T!oHa)QaKj?PNSwkT6j7o4PTmf~9r$q{*n4-~Yk||mg&54vZwS!#lK7|}K zn&SShslJGNzH2AJ?(B)5MzG_(-KP-jj`rghSdAi!MImqY_}nH=BlBmw~iSKK@3WH6rq2{@HrSFTy8+&;EVu3LL2UP7*?2huypwPhmGbHr+h zc^e%g{U)W+8jiS;3oKu5rR*DeU@fu``v|i*{X@o<_=`xMh8NP!L~tQANooqXR&*hP zoMGlg?Bry_`*0)0HDq9`8w6#rHn{8CD=gt-0EJTxY&&@`n@}>8jIR8D%&H8q)Uc2!fmr~IwZ{${H@18tK6ZqFrkZPnb zA_!(~;NDI&y#JZ|ciTTT-kd}Alt+-?#ssrLn8wpd z1S4mi!O;Lw5EU72%_tDf8Jac1=LK*BOb>vE!JT)FzWIV@P>PXUr${tmJ#m!$n~?kZiw{QxFMCw zvGF;3cjSiMyRVO6YIMo8O0*Jp)+TJRhr&!)G>Qs|>I6U}m9g~;lVOXml%M$8mtvG8 zTr=_!r)!-7AsXQxUfpuKWklOF2Xl@y}{Yr9y`i7==qF4lxh4Evos? zd5i%(6(kq(4{%NV9b}nz43qP!=pvurxF?U_*dbsh_s!ayM&=ZxXG9ueSqPc&^qGPl zqOgboE#&|AjaS{a|MRc?dgWD>(LL3R(xd0Sie!5G5V?8lo38%qaXPzuyqwLqanDfp zo|V;hOpU^WMs`VPC@vs@ND{j6{p2(J|6#4%!+A#ca9jivHmZM%@Qz@xp>`ooN~0{N4XuDZsDe+fl6@jYlJzN7Muz+eOffkHs# zQvrRT9A-dnfiGULsb7{CQv(-Ol#b4W-KmmS*^&x){l2(FAF}GbX-~qCL@_>F-e=e9 zJB+^Gtka#fhsV2vew(d5KnR>T0^Q+&PZ1tiIO(={X}J%LTZT*S@{z$NRW1q*gNm8v zVkF{llyq`U%5Aq4vaMND+y07KOPX|Qjoe_A7bcdH`Ml26HWUto5)(Y6S zFRqGD7E!E8E|bfMUR9GmrVyV!-T=QpNcCVAZ7<~xRJNevBL1UJI8AE!J=;O$%5BDK;`$>okjr$;T`AsEI(t<|!_-9BSdH)lr@_QFiB zG7vOt9TKgCQyT4BRZ~@@XckQ9z*^a?i}{U=020RB}Vi3AUG*JlGZtD13$9 z5^MrynWN-!^ml~>RxQ3BwCE&5N`X1oMQj1h1n^2^*m;O^f_y~d8dS(1%Y;Bd1_F~8 z6}rR)Yy`Fi2e78EQW=mwExNuuoDF--k%Y2Q7xfqR&CMsfuRiM2h+Et~mq{cxyIf{T zOGkH?9UfWjhn!k%sx6~y_WE6hMqPWiwb|0sWA%nD!PZc-ItgDMsb=?;)$*dxnKhUU z(w6G~$JuwlNmAAM_p6@np3XVv9H)Ca_e}Sso}6bV@66^LSzt-KBo|ab5D*jr(|Q6T z$f*PYG2rJsR6tN!1wBrXAb2W=C_!Or{@+*CJu^%AA9oAWU0wC+z28f}^nRgF*W4Ts zd*O}ZimaR4EgNc$mHh^DL`>vTvCq}E^McOVPw%(DnPOn9Khr2Hjm?ZZEi=1zge&8L z%9KuHncBW3WF4BG=+vr`eLk6gFjE|G4o?hMG{%;lkN_x`2;l*y*1Gy3oK3A_0FJnvaUxnDx_hGtNsnLB&|x@oS>h7-3g$M=Pe97K*>> zeI_mAXIB^3=X$*@`-dv)I}8nqu|d69*EXN%-?}2@?=8e_^ANoTWj%Ti&hBkdZ_9hf?OY)7*rED8iOZJ{{FVEv(6{i@gsp%CPl#7i=eF6fk20m z_l(Lfyu4yE!~Vw)yeQ-p6<{1VGQlxsG*s-3o$Gwn?VY(EdG(Hexx*BmRQlRN7DG0* zuHpp_X^@JJc3)AIZdj~de6Xt+A%&&Jow-)>qH*@fNV2Syw{JU?@svY^uzk!m93*cb z9Fh++;KD&V_?T5lC=!u?PI1C_jgO(&qZsm0HW7jr*rt~co*tVzXKY~0RbLFdlTDkN zMDc}9EnOzdR!7bp1UTln;oLwpB|EsW^ZecImG=cU3xvTVa`Vq3izXqzN{~n(@G2~MF>l1 z(}^~rmIO)wf-6$q5S=a}X&FD)IJW^22x8dbzEdo6oDD6-p$5iTStn~KU%Km#U56XS znIrN8}y7+T&I?u zCuuB`JK0_#3C0}eFrNR>5I2XY&lk9L#)3WK;^v={B%C?d*=xYcajtYB3a#hN`-P1n zv17iuJQ-)0;#`42dbHUoRf2iz8GS$#3H!P;GP8pH3Yn8?8fg`EJp^UL%Mn0PoxiP8)PC;U{hCfZ$Q}4J>Mx5HmBwm3O|KKlv2!4Tis_@hozDP`!g338u)0s%Ww* z2AZ>cj`BL+3#A=$xiq0}^m@g`OS*9sXKvj!E|ICU&ap|q$u+s5sXP+b+N_zTAUG1_ z4hb0ZN?9Z%=^C?n4w`{22aLRVMK%}}a4$8!1tW^V<3`ko_(>FU01h^W5)_mZVSM%Uk}f2SEe)nG z^~Uu1sm*f^Ut=Ka3ItU~WtY-lcKSE9M#IUo9t&5KGJ_~PT^Q4qhv%Dp`LuOhlB)K# zh1@^zR?9}M+h=S}H~Eb^_FP{= zpyS%`^k9>&X*_+S&=$#-JH2iLxu7_m@C|t)@!pBCvQpWIxhXEUk{xx2(~oQ6pDq|DiQWS@<*#37V9}>;G81 z?1m?tP%Jm=DkrCHSV_-9ofKM`UhEq!XKV}Xndh3y=aJ0_fWhwMeJ$!By8oO9!fdq` ztU2}`AtTo2I(=Pp3FPUj^uX%tA+B|+eSQ8ifWkbZk6;DsqqDtq?{;+}5Dm>YkG)%1 zK3%B56)eA?2H~~}$9aWL>Uo`q<<8}}@KA`g?kBnVj+x$(@ciKJFU*JgnhY_creN>g zRoeffk4>D?>ppy-GHw#* z)!ag{+?_#Not|QER3TLKcIrjOx#U96@KmYN)u*z-uvq5l$!C!yRn?vd<^39K*f_lO z(rCDOV8=$&zD==kBwEcR;xu?MLI^Ql#>a>oW+4?5L4|{lGmEV$VT%;H58|D~;=g4l z)9GTmG}SSzFm#vNbMt-EUHS&ojLhGg&h}|Us%qzfU7aPa!5tfkjROQj>nB#Mx?P}J zNf=kxUB^}yIi@&4tK)i4NaOq>%AtZT5^m(PJ=l$9vY# z3`M&P`nI2ElgV5*Wla1k+|+PenAsKRO1N7Ka(PlN^ZLBLxrvEcpU2}%w6#?_+A6W4 zoxt`b1K^Mihf5721WVBjd<3o>R^K&HxV%ODX5`RQ*k5C7v0`~1M#xMreVu4%e!uo{ zYlEuKqHWYQh;$}-D1-CWiF8Z1tGXVELP)-yU8ZUNlHOi+liS)rI)&nfK+@Md7@cm{ z?AU+W<}LdG56$~Bj%7m=r1w&6&WSO_HM#65s^G9=%}-ejzZf2?Kt)0G4?-3Io(CEc z(QB{C^xN!M{QM(Z3#H&l*csoH?pSAVZ|liV#*$;1!bpUW)3aOp5~CHJxjg1=>JE)f zE+S-OQ>&AGNjyP4k7x?}V7X$@cN)#fR3fc03>b7x(`~t-Q`#JbNTg`*qY2Y_FC->D zlv+219niY`NAeM}1mzIuw3*8lhjA?yvt}ynOQ0&IJgPZtEK-IPu)kz)2=q2d&0jNZ zL0GXL5nn=W2zv~V?T|F|X>ri5R4RkLl}}ncn$xes0g71qX-7b-beLW^G9-e3%Rz;f z8XeOa&0+*?pog#;re?Bc@B1PbL~6s}B^eQ&^lfUzFvyaY9#6(5^XtxNZ#^*L zFNWkqCh=t1dzt2?pELgAo*|V})iod28V2;*uA_6a7xwj7(gAnc`KKb3UE0^>Wt zCBRgQ_w+DjjhIP(&Cp&0xlO%)gU!~Z95 z&x39KqK2-929L+#7m2FSShSE!KPYDpT#^J84hMp%;sUJ0=v4Ig#zqn1)iBL{1VN@o3_Dv%)1axCpUj11&9Hr#_(b8bZcI?BnN-p3@VH z4t6z7l^3?zl3ihK%eutU5sTjDw?hblZVZ}vauY~biOwr*Ie8+*p>r&0%JTu}m0oh% z28!HP$U0PsGz0n`g-RE+=zTG>Id5`?4F-#%QQ0ULsg(MF1zeXUXK{w~CL8WbWeuN& zTcAs!LDXbd!l{x=BvOr4sdXwFRZ5Xk?SgWt;Nb77RBn}2C1;=J=qyF@M{xy~P|rai z@$*;%SRU(e$HA8ok3{8!Opixv ze#{e%q|p^tg?gMko*ThVTZg&>|Snnhdp)QX90t-V!dktZm%NOknPJ$D}fCH4=zyaFQ*4pRdGdA|XD5FgOil&e0oS7KuN}gpn?d;+Aj`M>;Ee7MOTgt&&?CO`*(K z)Z!xP;e<-c2*28th>IkMg09pU$dW^1imQCxk@)yz(%xvb%UvRS@OGpTa_HD!n{=Mm zU~o~a)ik{g5UXM@D{Kf%KotV>T?8Qq74iUAAw5<&{6 zaCQS(q=<2;AqETyUFNWL+NsAa#?C7qEzkFz%!?Xid9J?CjX zG!d-gGOBYll8-CoPiqr)W4WXQX>`YRUp zNu?^g0Yg+k?Ar^N1i;EtY!w6o0JY$eD-Rj}Y2*qQSMJ zW8{=_$HBhpF1Ke-Pkt;C8O@JQF=R(>E8Cv$_IRo}m@o8^M-xRG`?k1`STp`Ysq5VN zh4Z>f#ZplVXAb?smi*v>%3yLsZ}<9SYO!a>ZW8KA4vj(4)xG?Cc&^3)djxm{zHlN; zFW5$~&t4wL+K_U9uMh$iQ;$Sg6Z62J6}{AI;jJ9GFt>DbH{xvVV5UZMW0B}+zGtu7 zy{p=Hu%mp+NXHJBzSK)*#{1me`CQfG>0$4!^oiNGZ6&uKUfoN7tsEH4Z&}a-axHpL z>N;;>{@kuo!Jn}X?%vU}m`bki?%j|iV?)WF5Z8r&pbK=Z*1A9)tD#W)KX>7Aas_+F zUH_*ZkaYEp{}uR@&v-+47Elirs}Wf1-TuAaRU-0kvDysX*y`e;!Zve3X`#!9OoO8b z%Sac@9v(T=Ryj0gPw1U0k0IR?@bwqty^gqNGqKe34|;oLp@H31-lvv&*!G`42}i0% zNxxW}+EDFS%mh4bk?2s(*LFMHZZYWj<>vr(3kIELyQ}i+hCd;zuM`#Yzk^*^B=O=m z|1TYIxtJE$(trG~yTP0k3#2a2VKY(!KtqBQ3e>gzq$nVV!Nd$B1jx~|26}o1&N_+^ zATdge=b%R22yd&J_bPLQ$%*oneH? zWGqw045p$@lX7@l{ajM$MBZr#X|&O%T3TbJPNhnW=eSk^Nt3uSrMDv!F%GofK>IW& zGjR55V;JcbZUmT;4my&{n6vFTa9tt8^YPN0paK2VLk?UGSo+U6`p$MKM1PYU?7hgb{xkkGkxzKm-m9m z50WmLVE3F1YHhUM2i%phTLl^}zyNhSfQGt9&vUz&q#C~)n~r(slJhXeicd!wKV(eh z(tnai8XA<;Kmz7!NN7y8I5_O#4&iF=DP`Yq+MWQE!xYuwlj*#CD4kJQugE&m%qEDb_ z25dcQmc$>9aTJ%jft<85w%hU0BFpj-$($C&M0FE#|+l^SrcXC`}FGi^W zb?rc1TntXCLJ7WqjSZZgn&v&#x~u!%zhVF>?8ESfsS=Gcy>;+-JrxgV{cw-6Ef6X7 z+&M45DM-V@!hEg>=G>CvnDaiBNDbz^ZPFmI&R=VFyRG<>ZQPCSe1o#&r+p<>a)Kcz z=B1Yg>;Ziu5pQCeY#z7G=Jwdo)oDO9REG%be42_> z7(0SOT|+HvmS2Yea1P^veutMy5LgihJiNeLZ_i8*MtOx5#|W)#6JP=IYNRD@7`SKC ze{EE{42>p*+N1SGZ1SLHpz?%mD?CX{;;m~mQXVI>UYLfss@eE z`PVmAfqR^U*-M^xHdz@4@~^im`OSMX6+0G@4*O*<_6w(drC0^6*7HSt&``bNYVxc0 zUAz5z_w2mvvh8;dsB*zz!R;)XeGZ3@{>k(nmdw%_yM&MVnpZ6_)sr|+|WIl)#i#q=HO3(tWn zA$(4YH84`75e^elM}C;qV`PS}aj*_!*p>9DcC)``hU&n+N?5*~6*vL?b!>%fSq1k< z4O|>3)~66uZWVGIv-&S7i6vr%#r))VcV2PH_B+3~^NJrj<4rzpIut=aSx=OYKhD0z z{`W80A1B*f*e!_kL%zYCqC)II4L}+^E{A3k={H;qmkqf{zHz-iJD9TslybM$-Q9+|MAwp(3gw=#F;Y-8Xe%$5I)3qZC{)PaiBEej z_*GI(Xiah&f~GzcXv=^;oZJ>|p-_0Hy*2`7v6Tc`>(o9Qf zC}?hC%I*0~Mk;BNGA`Sfu474EV3?0AjX72 zY~*bRxcIs7<+Vwv2GSA=mr^Y)j8I>Sw00PxS2ZBHK!e5pb}U?O#nw4r;}hGhEp6=E z_L!OKZPBIcg3?+)t-P0p&R3It3-=OxZ^j6HE zs1b>yr3wqYI!zj{MsHOZbs}k_WLrxMd8ARQ^O-GfIOQ~m3<{Y}0{t%TdCVq{Rty|s zR7iD=jq-01y3d8kiSruZgDFW}Rm&@tF{V75i4$;&sEqziVwqU25qX6=mr*1YwTKmn zZYJ_DI+sB#6Sa^fMyS=A{W`*Y|4E@xt26uc450~^6vRr7VTI5(I3@uc)C!YEWi3c= zHIi-oOfXVPwlrar`x3U+4wF%;lgVtVXp-CzkCt1%%6>ntHOgBn7g~{pJlxQbpyutr zW6mU7g)eaYB-P1qR(7<;nzLn*Z1KAdc0;u@;5OQfU0uR&N}L9*FAz31wTUy0PQA|W z4;vHh5>(cK5jl$G1z z`2+X+J6!%Q(egZUyVLg{_zQjBjOTBFl876>`#Sv{LH*RYT-^A*SLtuh@o|S9V|_TVDL1t~HQUzK-aOts zfK%{zB)+$E!dfcu%Cv`l z75ynML$`>D#@>QNu%hm(u@$wwh1g(FuoVhK+kc>~>zwK0W`Am9sxThkFzM{^M(kuC z`=ZX1Cn6{uhj(U8`UylKuV(uDrBXAQ8T$nScr$_$mY4=h%*&ls^OgiF$G{N&>vKa* ztZTW@IlBrMQ%cMp9Wy6PhNNv|UkiBWLWi$=W2Ufcplw5&>$UFT{%T|(VGNf@YX6t^ zW<{bwv8a0SHh0vR+ujR3Xma}W+h!*F#!0Bn4<9iPx~;?d{%^XzLAz*}CnGsbtnA0h zf3h!rg*j!kv~)i9FEv_|VbQy>y?BiQH$F8#A<8{+x(nW{RS42rn{;}X&66^dnOlCu z*|DV8}y|3u;lmfnd!lX}>$X)qNFyqKB_(kAY4tPczVq z2s{)k1S#cQK{i+(+)tjax|o`QD@Rz94AU5!K7Z2Q43iP#*ui#DgCW};-+HjPyRWp^ z>HAyHP=9x%uSp+jd3o;*+nU7~W=Y4ft=_odwA};yE8(%TzC1fJFzT&Dd>vUA0HJ{l zwU}`&cTUCuvT6dnlE#P=I~lF5WwEoezSWu9GXoUCUeLX6qSw_`D0Df=uDMG$XEK{F zojc>Exw)Ipxb~V)eR|umuC8O4M;d+6594G7P%2JkYv@7i{~5z*Y=)8K4+m$--{Luk z#-wd8!xk2=fY0Di8MX1Op$AGo!mBG#A~AZ6p$7^>FpAENM^ldO@uu!A`Q&8rGi2}J z_X^YNn#*kgPuUVOC1=W|ZJP_%HcX&qYNjH@df{=ydr~!mq&801g zrajG_6T#F%M{i$wJla=jos1+xrwyEXkns=9s2XJR{q0)|TGOP->gz}}6>Y=5wn(nU zX9F*{17i-10Nn5xj~l3)7DWu;#e^%k!AthTuV!L#&z>2?*JzM=_*3cDPbqO*cY|hR`Tu4 z#%?5>FzBaDR&Q^vZ&)UBkaZJ}3wcwsHy9;`jw_x{L%JBM&FMQv>8 zv~|X;M%QHS-H^8k#p+~NynSP?w6iZe-yM9dW30C~)fd)>TS&V7oc&X&2GOusoSfK0 z=P$dpcj!QCXzc7Subb(a2v3Jn8~8)_%m??nz6=+oC3@>*T9sc*4hVdy|7+BRlecJ*fGtHIaW$GiKQG0>q_ zazon@473OXElG~=Z8c+{xAYDlXr(w}a=K?cghXUr7-$~H%7G(kDMgCRrQdP<%>~HN7-J;VrG>j=S-t?dqq4YjM(vIkZ*_5Z&aB;$q09_vVk8WV zb-1@&%V&~KS`UMm>)ag!-WuWBf+)=0ap0|Pt_))6b9byL(@V=R2;0Zqp=}M493X@b zBX>uST){)+ZXRZK3xyeatXIj`d6>C7)C?v|?%`qP?r8B=7k39Rb9dlu0+_$S!_3`r zEx!qvQ4fWgyJNsxBV1d6nY%+x47<59fSJ2vMVVe&hQiF3@3~eE)JiOIC1j{0fZS(cy6S3mY^s%bp$5lW%zwWN4)j4F z5$niTxDqb(B|uBiIbYislz57-Lm&_u-&F_SmnivVy%lIGR!3^3w_-gU9k~^XR{r@u zB`~(+lk672qh-E{Z=_sXKHM-08y6MWcFMp@aG;OyHQ@Ebu(A`L{L_2#PiC{>LDhX{ z&(4glKl9tF?;C%0@=xYx@B01LgM|(1FQ&fnjno&_8wwAyZ72Ue`4@0zK>)LG@QN~e z)COsvM@+m+Cz1ASZq97)C&uI3w}-L^=hh#}vZ`)!5bw?7y}|l>Md}aBv)9xWbe}c)N6>foqg%wcWB}tdzHCp z>4LvEYuHCop&35iLqZEUJOL;g<>1Zr099u1)b93<-P4|^b!0K!yf|cIHgrrw)ao!% z>+ik-c9a=fQu=yG+KtsIZhQxyu3 z^(cklQz&#kUs#_jAVL*OtE*2uwS2byS+}Qm!`4gzsaL6554lZ>fadt5#XUgZW(YgHDPHj zB7!(0$U|rIATo$$sfmex#d>l@MmkAnMVXK_Dl5u2!IW-g*zbz8IMqs-UZr&D^$v}y zQL5=LhqE@NTB?yKtVUN@C2iDLTW&X4ECz$sil%Ky$E#JU{c}D z8pTqz+hb|AT8dUrIq(1l*oqG`B;JhH+ zG=MCPk}@TjLs-FsSjF|xhe@@%aSv>!ld}?j#Q( z$iYK*mkKt!$z(Cu+@}=pc z!Jw7Dd@LR(o_L&{jK`TuJpRsI;k?QtwJ4QRrB-k7H_V3%N{`g6Qc4v%{JsQ5zKd60 z(n_UT)O}EC(5r9_Y%#F>8gn&xS84)8sjg4(7QRJ--14iSLr<;U*unZ>Vr8ve$}5A6 z`)kXry(Sx6c8AO5u)FHt>{InCW}$w?{=9yba66rD7tTGeq!&(?i+!HE<8&gaD4wi- z1J*oXZ9Ey)wJ@!{J_)8Z{WB*T7|;sa^0;Quxsc z7X`QWjV<9^euuG3sHH>zn`FlDj+gu^eY+ z^g4VR{<1QeAO)+4K==XIC*kGp8pgHNzF(=M;?LGDnA2PyifTQsrH|GTE~(V7>feCn z-3tr3@oEI(LoTZix0L?p1wW>t!@FbIE%?Rq zYgAck=BOAwFrgcNN4io;JHvjjs+38W!hW}hCJQhuzfQh@-DH5CC=L`2QI%IzQtXR! zWE@eM*A6#Si=50F{)j$gbTu#JHXpF%BPOqIC;-aGQ9lWyOa zDmpd(OhoZ(m)qlXdfYB@n%pRNr&QZLdU5yh9X`aOBHSZfLIuTtXw3myKjwD*5Oa{<#W2nTp3xHg~yGx#sc z-riEY{`$WP|HuZ?Yyhh}y4*tE5xkA{j`hq6ap$|suaT1A2$&WvWG8Ay`6^N{)zSVc z{lwno%hjpN(=#x6-KIsYlK^bXmLg?FhZWKozP|$MM60HA~AFv)+ z`%BGmrMMt!h`E9C^f`4uHD#z`nyZw)1J30)3ZF=AQ4zIDENhf7AlMe6T-hjYY;0sm zqg=?xSR{m{ph7QKT9kSO z%4l$gR3^F0DG|$q&QzmXl=2}%tb zi998@OM-EgUaphNVXGl;u{zNwOPaW3ah(y&pwzC>H~M8VrMwa2BDEQm5|=?}kuhSk zo&=@R2B`*oq|l;NU`W)BA}G=2GAScfH7WvXwL+}Zs)bHQrjUvxGJ}wjN+I5(wnmLY z*dS!ENCe9VI0{F1G8{66FTZ2ilFMQ3Dwbb^P=5kqzmMDuY%Qi10sMU=%%Cg{eq%Q@ z5ClJ?s~@7~gG7kc53@hPRk$-CI0pRRSi}EU0qr2;C85b}B{a+x^?m|-=!ZK$zi8+# zFyy~W?)Yv$#}mU-2j!3D^S1!=*ue1u+|?RZ-mksG7eyl#GEVO0kPo)19^u>w{wm~L z_B%w2N9VF1BYo_D6D^QmX8Er|Jv4c1+exAr7S3M8LGOp;uZeT4lfeyU(h>zhZw{e@bU>l|LataNQV9;iK%mOXmw;{^y(QeRt<_Gz-?IOGEfUW*TN*{NkpRr1}t-IFNVl*<9Hgar;IxtsS~V$Qw|b{dQ|0V72>Suxp*s zn8TItXj-?)VeHddbIq<;!fVeIPXs)k05Wo;{lxNxg2xe_jZTvQmKrXh8LlO~M;Jdr zMaiZH#GsT^HD1Razs(j5+HC&4a$9>>rz5a#l6;<47UC*92Mgsqj`mOu0F4cE(h9sI zPZ}N{UbFtboxgz-w_qMa1gkICUge6T#&6S8tdHV?rbOkaD$#=B)P~nCp`HhAzrD9E z@EM46fAT!`p${Od2=ZXw79dl>Nf6cmnqEUw_4Q|@{%{RJ<=Z8lXba%*ZQ%7aBo#}R zuInOannKT!ILVQ6FZ@2lZz_`k0iy_iOH8_wEmlpVR26XjX4k4odv z>0L^-UZzw#TZlDK_E?J+YqQ1UR!hYYUlne1M;_v=HEFPU)iSwCsYSqQx|{C=O+Cib zR1r050bM0S*I!@!D|tFio_+_$B!XRno5_=mnR8cL)nt8uvl?+{r!$%9Y<4P>nacW0 zK3~c2Z}ItBZpO_Vy_rLSim%1L@{Hr(PZn@$KBT-%x|VT86k8 zDbtG`3*Gcu9gz7Xe;t02@ur}EvKkFGo55)H1yUwQyTwuoI9rl|l+npuJIaj0Ww*N= zF2^@Ca-Vg~W>*;K#i-3eEypv0^BF1m7rsT_37DTiFfFULHsE6Dvi^`Q-s^@`jsI?W zPlKRtd>5|0orm$1CX1PS(Vcx>I1!d|POe?-Aa|4?AbFlVdftKJTpR)M) zgc5Q2b-}GQmg1xlTsvxcPW4)s_VLYpmY42bOW&<&Ro^Qutlh95go()3x)O*zQQxww z(n5k)lf19mgwty;KgY?FF5np|)pB+hp>U^d7~1fK5o^pdwY#Hz_q5lQ@Avuo^QMle zSZt~Tv(zJajtqd&gQa3oE9xN)&ynCYu>Jk(vQ}_>`3H3N)*Ox$zm&}daycOUKqk9A zmknfdK3r$B7{%`8jNk{tJ+(DRRo?xW`88BjxaN8-b^S2c$EdpRfAPn>;PC}v3h(p0 zGgiO)zS|#gxdMLo{q;LPsNcaOTH5cXOPu{4u?fd$P-%EbB9tYhnmpA;BoU&h9e*c% zGeslS5pd;DmjAxgnMgR@rQt-PD@ZTj{YM|gtM7Rv(%UUCUJn*v;$9Y+0%k;^b|wO$ zgk5hon32>X9t_5b_<_ek2wa4V#EuWg0{q&~7 z_6<>6w5KN$8*K}$-`IC~xpe7g+S(L}q)div^in)UtD+cW*_)J_aWJ zG0adJNa!a#5~4gMLwU-yWRnO98oIzn?v?vz=0ac|Q51SB;e+JY2oziQmj_z}r8VD| ztk?K-Wg-%{s%>f*rZw8^%nL7udzzXO3Wr6kkjX@NKtl{hmVe5f5^-66^y;$7(+oS=EDgk9Mg^$_n zGO5kcKH#fFXe$B@*~~QJT`#wD!sr{fpTSEAIff1fwzW!sI5gZ)5L)9dTihuu3d21= zt<_nqH$pBNY_r>?GP^BO@v&EOjqvTA3?>r)fKaWpMK+_d=C!qxX;e_JivyE(@i@T5 zK|R$^tO0ZFUVaaV$y#36$Lf`#-fi_nupGvIQt&YOEf%U;AcHHH7~k_~kXjM!sY>?>-I&Ei$7y%w8?k{Ej2_ap2F zBjwYwMS9%FeQ;-aW_qA!7UmIQ!x;8IYPt1Rqw&^TEjul@-)=PCe!J!MTl2Typ8uR` zMt#T4>KXOtKaY=_?@-UEK1b$e)cAo0C?);{xd^ld)?)gTRHHaG;dyd^y`m;{)X6Wo zXhmVlK3ylcTy$TAFQf`NoKRBnp@`!{zxE4Mz!0)OUf>0Zz{JwWQHT+=qxo0JVIW~d zi&)D{L79nWF<3NW1$Y#?*;iPATQq5ZBp_i*M5HolJ+eZred2V+b8)R%)S!~7Y-Yq3 z#Ef`g=b+%Qyqz|(7Q?T-4u^wq<`0^?Ob+gZ@V?sj-vThDXJ4bAYh{$e;=G*iD02|`a7aiEM-f-KSXT;AJzc~AG{eSMdA zH*L>kwl_8H$Ygd9=b7gmIrGdT=Oo5v=f=k7X0hy#3S!I|aOTFT8;pM_e_7K*gT16$ zFsRzVsfDk1A$=A-WAh=nV{Fvt57kcJVt9Z9HlIv}S4U%ryAL__`+?zxvSgJkb+~j0hV21D=L4jZbkb5Xe04qdkah4?{zwc$;d76oM!4l;HD+LIcC6pQiaryhgZf zfFeSyp_d33N}|22+$pH%hi8QhH&t*jcSqs!nmUP@h7DCs3i0 zudtZ+W;p7~_@M^LP|g_$=>&1nw`r~HbHtV3&DZ)v`hMc18c|z27W~t~%PD_H?K1fV zZuW;l?Wv|}D&5>%ji;Flr#_Y|Ts}N_MX~uZyd%atH`U(3!~;juiAMnEo0=2VbSj;y zHl>(j(;v?jKRG!3i9+r&438RzAQAFk5FF?sh(xe&`RKBS4(Hm#k@x>CdzEBi|3W0q zcoW~k>*=sFREx*GFPZ0`zxzJ10Skt?_MQMaN4rR@_6PD4L_fgvNe>FXLhHddritDc z{1Eq{5!54&W#_ThFC)e-OK3ozF!_m4K&O_Wu!r$^8~+Vjg}yKv!q)3%#C+YPmzFrG z4It3v3(4gi?WH8OPJLHYI~9;&twBn)Ip3t39i>Xrxt1jRS2R1A1NZVpg6EkkwR8ch zs?8fnTqxwOw2qZqtl98rx%|w|`}&6N-_m~c^lZ;Pc*~5p{-gF5ojJOAxS9KpN_ixl zu@uXr?Jdvj_;z>p^rP)t?jIVwA1_$|wv%b6LTwQoGW<9|PmR>7lWu!BkKh|}8;w21 z`_o&TF|&K9-4Qc|6S1f%>TDl!TVjr7jmLU4itzPHr{!=m(rMOocsozSC-T+M&>;UKnQzzC`W=3ZXBq5z^qr?4!c|yH5qz0&|Ak?eu%4xu~n%?~aZnCl*Wzufd`2QPm;* zfvYL3w*Z}71gd?k-zh^bTi?2pc{@`fy9q;N7*}Y+PeASQ-_1=?YZ&Xe9J_}y#Ct7i>4EzU;RoHn>x1Px=#=7?({UU zZxd02w{zFvXTYg|YeYikdTI>H?jd+NrSe>A3~1bg)Tn?W0~}lXwOhY?@rCV2)=z(n z%(Az=sBfD|POo2J9^SXJXKRlA-KAY!H;#;q*ebc6DqL9@F0#dAsGSDm;%lyXxYN2o ztSR5lIpNdhW?mZHoLuMYNM5mX-KE(c-@4?Eb6%?0^GX)Y5O+}9skmlxDXrIF(~_<+_AjydUQc__+2P-DZc&#TPk770XnTM(rUo)@b-LM?F==Op z7z7A)IsH*~B=yYra8~b52bw!i-E|}{m5<4!Q(rpm6h}uUSaOG^`V9V5$=N>cH|r)Q zfuy_8^&jK>&xJ!gIG4bwB+s1<)5$d%u_WlM@}~eW;-bgh`0uox*{WywQ+sw^J-RWq zbKUr^Oy#su!mt;0PIh+6gzojHv~Ry|X7)>`%zdP<`^ePvvB43zW#7y$(m&9at;=6z zEW#9;=W{L9G6xWBAkY(|zV;oa8;sjwl6vj{1SaIRmvJ?70O{_0sIw1$pTBAPv=)0l z9O(!aclA3b+lD8{_DofsJ!R&G>+o+$L_fDN5BtWt*5(Z$H=dj|fCx6ij+8nKg1WCp zTA_|b{#q15W^qg#ZK3qvOb#s?bma1r_s@D?=mGZ+{~?(7+!h{m&K z;UMGc%7q3!h4`i|P2se4tRc{uOig%g;SJk&HkZ#mtI%=T<<x zbJCTARG*B96&&&j!hH@RGmcX^(GePK$|*w*&LYB~()5ax%0SLO)ZV%1`D!d53Y4>HIi7UP2fpK8 zm+Cqgy>i+Svoy_jWQSVqmRu#6?hBHSm}0p=u^MwOv59b?E$FL614#@Kh6c=eFU1a7 zSlZI9fYnJ?B%~uBDLDHo$Bs?!NQ}0TXu03h7T>j=eXflzYS;xG-yir>`S9?;(NLNJ6lr&Gxs9X*u(W-fC`FLI4<;34h^X+=s~X*IV_$fcaAcR zZEZ_$fdc!N|3XrNt05HH%f#jWh}NOID(!8K=fj^j zIrL&jPgE8z$M+fHh9~Ye$Nlm}3KP61QiAn>={N@y4)B>4z;qBW@wt})NejS`QcpC| zZ?XFn2siHlhf)B|nh_b5wAMiXC!Vds05JmtR#JJX6Kx;_$q^B#d(Pj7Hp8Q*( z$1^%QFg7%bX%FEa`6_$HFu8(xJKy6O8ATYo;gQ;tB^OsVhg-w-!ln1zVotQ~=sI}D z+57gNQ5_o}pTK`(B|5q6pIdi!9z3JGtMkC&?$L>H`fsfJL*C=2``Z}WpI~SqykWYj zZN$SE+NZ&AVQ8^tflq+uTbwIowhzBA+yp3T@PHtyUA*F>0 zhPsH^VBmfLPix7@%y~kvYP@;`tfLkNdZbyfAv*WtOo6@jZT45>j-@}57ucCUHN7?b zY6sayo+}pF)7U$2$+eTYG@(LrF9_##*cf07Ve`RjAUOsKG_bge;OM4D;P1+tt!E7% zx?ybYmNP5+lfKaA?Cg=w!r5C=Rr?oULAFV+TYvLuhi+ap>&GnjVdY(qSvFOz$Sk^OJBpDs;| z!Q|=~81r7Dr<;xtj6oP<;TMuS*k8TPUW-w9oU|=HLtbcMXC5S`;kRDBg^ZD_FbFR8 ziyd?j$amPYu^FQRm+)5RThJl%^abWrMu~w_BG(xNpga!MV$_;-k{f!DG2cpU=)L{eCy-rg`n<`=z_q6$McUG%nY|P1c4tmK zvTjcn%&P|@e-qq)93V1XG`=-<5_mNr)q0b~HIc4)qj9>k@+(#?HU5v^ag=LE-^sVS zswst`6mqAmI0Y)joQ{myWa}zcVoqzei465FZ0xha_g5R&BA{o?mNMy^0_?~zFxW2( z<)>ptJ47yDlZ9bSUYlB;R%-5M+;*!u6)`V8IW@mwQXwsh<*hBnR;8>WlQU1y{Zi}B z*|qM(DewGYyF>8=FI(10I3=hY#{DqK&E-NY2R)fZ%l`E|wXDTjNWMoRC76IhsGHVda zF|zzm=5>sK6*!t67}rn0RsqMP(aE7&Z9NS$!3&^306eD5|M>l;gnWkU%R_B2SIam% zy9PX-Oqd*e?*x#I9KyPoy(@09ws!vJM8MyYzXLc3-qONHfU`qL2ToO4Aws_yfd?NU z0PLiqA8-s$_W=%g3kVcpAOU*d1)pUC5`z$LOo+W^aD1|_>S-}+O(~nXVAc5j8j@g3 ziDWWyuj;_!!hYp}JwzeT%H;&6Tyj}XA`_9b$z4K?yU)LH>(_4Bar)t{Us>Auj)8rF{rY+` z{MwUGk~fe~RiYAKwB^M7&$kl~Nbc!mp8Xq9vR_*meUy24bXhR^0J4QUyUnbb`PovI z4hw8Or`8Nhlx*iTbYmEtdzjxt7Y9!n43h-I=YVE9RLd_zb1ndLQAuP?d>5)(s)c0% zB@XkfFsBhhEX~g1v`wOGzj1D4WbVfKuYFC(G&m<(_MV>IHs6ngO2sY*smhu{gUtNW zt;~GKR{ZPmIIGS?^0G@N&+Q)EwRPu~ zM&x9Tmt9?t4!fj}k5r(hNI*?+7O2A(tf6xSm-2a&>#QQTa1beqJFemu^BP-gY+cF+ z@G=VqNrI~k3`{t|mSZPt0d{%q9-VKV*W|}AEcO8l@(iZ1b}DJkWQsU^qNGS-DpIqI zu$kgy{m5VE9TL@t?Gv;`X zd`s%{h$VKXOipeignU&fv24~G8jSj=+0oSsLDZwmIE6Z_80RI2wAZfSW|A~)|^tO~{cI{d0>YF}1cI~d|+1O-xJ@fFcUA^1Q8yBv-W&i%K zUC2H~4)=6tTCD8rXaZY@xmu`!#i)()zI1!g&B5znXw(BFyQU%oQSPbUR=wuZ%6Z$U zXW*e-+YU3IU`ef7Yp+eR(ebd83z^Gf74>6mCd%*&6kdtsx1XRHDix53% z{!c&R`cVA~<%h{9o`&J^?~8}mA1=kZ0zcY&$CV2Y?%F>$5gZYcT(0MxA>m@vLQl&` zlahT9QRsfdJUqs}+1s5eQ7bnWR(Kicz>mWjEI2Ms38XIUAI`9g*H-f4&vWgwvDj>L z*Vd|!VQ(f2qEN?7E;H#3M)#FwFPx5!+#pk_$K+an_x8^5;%vojRu3CY`7Osr&%A8| z2CIZqq35uJ4crl>mLfhN6DW+)BOw>W3p;C-2EGpo!~&Xur z%5JvWR8n)y*NgyNX{pj?v07BRc*2)7Bb4Q9%WpOq5fhf?r#@3~F()SS49e;!6~I6; z>I9nth#&^el}^T`B-6I54gsf*OGlg7xpSOzNV+jyuOQSb|571f1IAjc-BrL+x77$ zK7Hw>pRRUXg_(^N3hb}Rmcl||M*-9P>jGAq06S=&+d&4f_1yj;SYup7KP+xN+5B4# zQM^+m|FyiZyy?qwjZ!31YGucncUrR}?@S68IhLZ}ETk=#Ou>aSCu--b1|q%$HZvOm zABU2GeT#Jr&si97$ek`x2`>ghV&$>3gszF2YK>DfP(nZcNdVIBw)9CqivmLd7$7h zSwaP~*~Xj}n%LUq$lD4VeSMYgQ>w*NHDz{c~NRL1cNv1_Q5L$3Vp zNALP%l{ux#HjyWms3=q~24evDgrgkw!X{VVcHO^TQzbtF7QN;@#qz7w-G2$HdxU(Y z%HBhU-&0Ua3-a~deFd#=8&OoBdWtJYmr5Go;cx<$d=$7>e%tZ6ZstZ4>mko_MR1B& z?*T1B@t5|MXWPDVyjo>$F!RO8v*-go%%@$2MuZlmOZQJFI{y7|6}2s0!<@p^22q$R zgpP8x(W5KvE6=yz`UO;XJvcUUd&klQ`6lWEby-^!;hnKTUOCbJ?T?`7jmD)%kCF$L zCa!;PN$4$Ur6=0IaxGtyCCwOS(utx}nM6BGfu#1}DEi8yiR0bmM-QYw^(hWSu&MP9 zd$n}Ji*zcE|D@@2$E(cDb>B~2a~)TXR<$y%Tuc4q5CoqK^FfjS29v7 z$<3}GML{o7<(+poAHS|jetK8x_{}G^Ov~k|DH8Q-qD@DBwZD3p41YiOfzB6C}eG)UD}ozBa{ASB`g|&3G;BIpornLiMg_h5Rg|U6ezY z1uR0`u9mG&GhNYP6s^JdWcx4nRF9L_?W}1pGj&p}T(`Mexo&^%_wBc$+yBlYs)h}A zxQRKgG_?VuFmRps*A@`D@>>s=zjtx^ zQ0y7+%E*7Fm87f8RoCN<_>fFcB-?d};0{+>K6E9W|b48d_P-N}y59{gZ`Gv!6&tmf*H#0Y^+5PnqM1Qk5Ek$RM zv3u*ijcrR2)b-PZp6@#^X1LRMpDu4m6Cm%V!!Q7zYg zz1pi#E#+%avFop>xQ;_HhuB|Se}!Wo{eQfD2VmR9^}p`>)v#qtwk&H)*0P3e*_I_s z@`{HXuMB4|2pJ?~kU&BL1j3%B>{V9S1;Q@y3lK_KEd|0TltO4}%j%;1T7Gme+G6Sd zdH4NlIZl53);}OyzI%7~?%lh0@7}$8_k(nrL@j`RmZ50kIVi#tP#jNj{JbYQSlK$j zU6?uX060nbXvVL(H=VvReJ^`{V(yi2r#(n*7d@IzUz}#gO`tYM=68TAo`oT)(ea*N z4Gvm``NIHu1RzE83O$9)@f$RYdfx&4HaOVlw@%Cz7HpJjlBa5pAR?-w0kH}mOjQNy zy8wVi^9g|HD=PGlcfWmCI=#axRAb_^-xt*k3+kh(;#(eeVQ~lOm%`e@WzUIo-r>_wfaX!hx@ouCf3Twv0 zfJ$#_f11tQjvDX%4Js^_#R)&edz{yJ&8^WrkED0s-uftev7|ytz=mW2`$7xbkcPYJ zTP^$%Ma>lkA;pJPGq>xN2h!=2ee8$_&IR00PA;lZo{%(JiI7y~ z)d9Bg4kGd;R{^j{q7b9-VfC-GbYTkEinmv8(WwE_DOC;r~7&1|)^!w*G0CF39<)rxD%yuS;+G1Ek z0rsKG8mU%2>pUC4e_%FVF%3$t$MVwgR_`@~!inb02>W#&B*(`9;f(z0Thp!u-w7vJ zGlQf=aao%iU=Sy#9YI6ccT5_!O*|%RM>!xGGpdb`E~>kMv?Em4`3v77T=hBaM|a(j78V|xmXw8Jpn?v1*9|Y9m}b9EXYQ8u#vB;>0y&>o zeIK~$$@9|JvN`EYRu=KafRgUZdE&tBE5_GIjLdL$gku%P3HBk?+jkWuC0S* z>tYU6Bt?rB@>}2OyzZ{FARq+IU4Fb{D)9|fD34u{CUg61T`wI246mxooU}&PWZ)28 z;KhO_bL*R(*Mn=Ghl$|^AC}$zrFleioSP^t(f9ti>)*~!?}pbDjy5DAlf!^$WGHAd zyWZ-$7n)4$UUqw3=8@}}i&vYQf5bujDkCP~zLs5stZ84{E*9i4xhcp8kTggzBow(9 zTQ9z!^q9ZA61|LsQqiR06S1Ib?rVPYXtexN+nf6YPYIxeBOpoUpw4}*H=ysY;rI2o zoL2%#^FNW-jIM2A-RaBO#fB&r#SN(xjM`T{G~ghSKbR1=CS76WCbR-jHs!{ z&=k<&%X?lO#5mq*l~wDUWTiHtnh*@T^!Oiizw|rd*i2^*D%T?KY+mKK>%yK_(S^Td z_5d!w-^syp>_PyRAkV-LMH^zdqv_M6e2K^@2F_++3CmQcgtcYR};F-Ym&syzUH&PPgR}F zK3sviZYyFM8Bki;Ki${7>ox+s>{|Bp#N2BRgrk09L$w(+T!h$uK$LrX_YdK_YqLvQy z-B)zJiGhA5^Rb`ZkXgjOEU8suL)1z-61#NUce@_F0g^29Tpe2@NxWRG1X-lA-tir( zb}8GE`GD%Zj_oPIf!E6!h_mMqXV?E!)*f=gj}Yb?b-oA5JnthOY zF)a&eH)dgX%` z?@6=tuJkjkjCZ6&;9vm;6kqWH)3%TFZj9eZ$8Hq2)MV0N6p*99i64eM^$7IT!yOzz5ND z(w*=F9|xQ>EPl-Uf9T*&d*Xe4zjg@%$IoemqwaE z3Yv~2Zod3g3L-lVuulaOX7v6dI8Z3B==?18+$jW=c|w*rxymqh0J6x6&d-up-p6bE zoZY(()m=i>;q?M}F|`0QS>*gIb@$bPWJd)uzqyI+o|sE+w565u4nykvEO{fO6E*%% z1kumQoyojSa)-28_KO>1`%WquYOFq-4>=n?1#LVnEX({yZ0ezw71|fK#va9FdgH?8 zUuKpIl0Yw6SU4AQ&b|rk_ax-aL(M;yq)m}DhP0t6#iysFqJBH4q264Aqa5VV7oV_P4s54hQ z*8=^i1d?czU+Hf|q>MCM+LGCiN5PBhVZfty~_`5FYpX z?&~3%-c8GMz8H#IN;w7ZzV6vGAsW(O$y!hjN@|ugW8Re$U;f?|Y4*cY)7N7o2MQL0 zB?^N2fvX<4Dt+1G=^NM&IaoM*Gm9y9^Siy0?*PpGk{earv}bT^bo%M1x3#pioqps{ z|G;2lQ)^3eBh2yPY)CF<;wM*RdM_$S&Sb@fvp}e*f*p;GI0_FlNMzw5L8GPMkQ5Rx z%%XD2Y)U~P8HUiq%#_Zz(Pe(Z=MPJmoj!eZY>@44jNm==#_0nCgM^<{6UqU<150Xv zU!gSm$P~pD06%KGK$?`)Ahpa76#a?2rjO=Hvzr=~nx{@kq(Qgl!TIV-AVWj35R#f- zfPhbxLCkq+;H&}>R^BA%ev{iRJcKQHU+%i%f3YBY=)YUgbEtyF*DWWZdikNs`48U3 zgB2rvFz>$t%8aKk2T@EQ4kt{%!{u_&XEI?9U5-8U-z?`jR5={M`Ji7V3}{T1vE_LA^hTom&H zil4jXujd+bcZcN*$+!_V>839p_A0%hEc~|U>Tl-R!gXcLmWJ$C!V+N+4KeP8+Kh{?+y9Vot7xPqgx%<1gB zHor?+#J>|n z=1E~i_FSHFV&*Dd=4@ew;*XTV=4TJ%Da(*@A5WQ)ZR06Rka7=CnVD_nDMumYMvS9| z&CX8aDOV$9tJp^IO0t_NC1c`ky^oZ66MyC~n*sA3;ZCH?%1(!)63a$KQSnoe948ba zd_mt}w`Ep}Ge(f}b77$(3>PNk7~#bqo-2HH#~pC|z5wYb@pN#g$o=~%_cNYP5EK7I zyQ_h1B^^fNVA^8xw}_zx9O30}pI5j%`j{aUsw8Mz_7msZ1$@(}mxT_B!!k7QZNuaetV-tr*2|yIN4vC};QJ z@0t8>)!phokKymxQvSV^e`B^?aa8s#;)?9?U+*tTIgwI;-rd=tVrdrR z3+KByoMP}2*wSNR(>`M0>4DO03nTyl;yn9$o~@`7%2*Y~NR~kfe-%@tpBBFQY!Av_ zk0Yy;5R*%c^VFw(mVif%h;MZoOijCPf2x|*TH#oa_N8cQcuI=erTbiv&5Ym1VWxtWn zcB1re>0k%(f~ij=-4Yu|)1#y5n|p?b@jr-lDK0&4%igTeC@;%y%`8B@bFw&5fYOP3 zhMIyC3@WHqpI~%r%k0$_+nml%%amiH+UB_Ks{SENd<6x54%ZWQ4%+@0ga}{LB-1F)0pMzV% zn2j3kHihEr576Cl@Wvw&l@Xqq-iY%*!q%ogNJsBI7DsK_!R#Ex)7c-t7;eNw!0APxj|XnUQVf-CCO+QS8dThLqXap0EE1n6=qqq`V5WPXyW@BV{x@s(3uR z4>0qxp07Va%I54bitiA4NE}Vzx@y*wU8ndUdlv~E3%sa4$n>*kZ|DbTTh^y|Bl~+? zL>9ByTq9*%@w(zEHkVfy%p8Z5C=(D`VGK5+`Jx$#`jorepa^Jcedr;(Ap^v*#o(v2V^#r&r*$Mn7!`J{4{i#xuhWX9sMMc%pa?~kiHT1{d2T~gEP&Q^0n&=0|; zInU^HA`-p)aX7@*u3?OX%hf%^e_dojltYA-w|tfR0?u119HF>dTns?-u>B0D_5SR zux56FQ;xzKtKu%=MwoE?P&?zeKRl?I33<8<4y_v%$04lOS&DDtordcbHz{tz#+lCU zF){h%r0I#c_HmQNmuRN|wYlG+gZ!+8(b9|TyKQb@kM>Rgbxp5tPl@k7nA54QEf57K? zeD1*KaC~OqlljNZA0`s(Z%nSg>8ABbgvqhobkjzpJ6h<+@$}`lj|~P(l@q_er7)4-=p-iP=Hs$;U9#n;W;$rkxR(j<#sIa`GxvMSxHpJNl844Ht$drg&+3J80{q`aczEs%d)p+y^59D z_qj$=Bq>)m#t{J|#(&OijNyBn|DO)A8`x7Mzv{#g3tD&0Vw!qn_t88@Aa_nf->6)P4^xW*WIb0sA)svtfr02M5 zjmFwkEY?9Tx}?Ewq&P!GA9Ue1Y;;zNRkZFHHU5+zuJ0>-@tRZc5nerM@T5T~7-wYd z?Ck7*>Lz$h-jiUZP^*a~)bo~b9EC^}xG8H9YOFcdEW44NqOZybY$0=BRiKn(GhVD?@7F2?NSuGDjQ(eKz2ha zLv?}V_Tu8)`KO&Wv2!&EZcs6ZS^BPkO(-hnR#uB9eWLG*i|`Sy?(ds5fDgbnfY?{# zJsd30MsCu+`m$4e7u_aYJJ>f9*+tR<&$k?US_$I^&Z|k&g0?&`c0f+UUz}_ZfyvY2 zM|@hSEQM*2xqQ;R7??CKbW_ZWiMNH#*{twagx8ssc~CK%6y%8qKxLNMExf>%K?{Ql ziVK)t{QbzpxTvAs-M^4kFK1zCV)dDKkbxW+6JAiLq#Pr1R8j`amgm6o@QGx3I2@GD z4#GC^l<0@#B3*+vdXPiZYiyA6qA*bOeR`RpO0`Ps2^t$`Qh-@}SOtY`t#LYqZ`a0? z7Okm0VO5hNL3+ek?h6`QgvRbGG-l)ihsay3%FqMpxo9a>s;U}IqcP~Nh~(PRp`9AE zC%P=jcx|OM(QeWX<`kB(+!v5wxv+xW0`-tA!*wEA6a?&VAS8RmRLn7F)uxV~-cycG zF4=oncjNjE%iThzsy-C1)#_co8fPnh2OAoyCov{j|DgnrUEw?NB7B4ev-CUh4z5ZCxW z>5A5;nj6fa=ITyoqSNPY4L8`VcDLCSj%F_EUD0<+OUhDb3D-CFxJ^!z!(?`-Bihb+ z9{>+B-CQT(AtK6|#xGBhJ86Ol6TcJ2!Dk^#QAsXScP>h2hez~*nQD<4^dcl_M5w*OD zypc>cW*ti8MthRJ_AkS*f*DD7D^dQfe*uS8IK%s=A^=qf{%) zDVn|t4~457%JQnJ>gqDJQdM4Ap;aLfX9Uo{S1IB0E? zv7n>TRo(BfnW9}Ijb*|OE|<;`c2qfC29u!|;`mXp-+ZuNh|S1cLfdvW0};}cINe;q zv|>u0a8Rm?PYH@A8Y0Tjr6z7hDb`C^thcW%*4LN$8y<~9uw>f{4v*Jv_j_JN`#L0dJ#lknM=WJbPCHAzZHj}0*9agqoY{*X_=7cy%d>& z=t|Lg_)Z4|R^_n5UT3?#(OaeWg{`rHzV<-MtoJlHVtuYy=3ln3sW$9z*ZY`Ihs!VK z26Jtru)Nl1s_~lo64Aj1FHGM3?e2s(?ydKE!!Acy2xIf(^?MQMJbN|RYqL1YkAuLP zq!;-~--8fN#BBz=Q`Kguu8#Svk*b)mrvglFX?Hl<5zo)6y&65+CY-3aOguF&)QaLR z6vt!;6{TOwNolIJJ(mkYy*l?rxJM#lj&%0D^52-&F(@Iga3c?Pym+5mLv8^iB~(S< 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

k5$zta2z z`lqbo^Q{SyMyH%_%4)fOiX=0|d=tAl9hxT7M-0j7#q?Q?*>DaF4nYc3KzyP2GS5H7 zbSumvv?|Y&V)_;4(Y5*fQaX{`Dw;>a+=IXoJ&NX05nL(VczuQWA@t4rX+AGslK(R2vk1Et?N1@sg;(VIZ{zs~$aR<;X&y!tuOh!l zva^rmbUr`jc}Ol>LtM5)MJ3se$g3p7;TVOGHYD4n^jXmN#_ht}SR-R=i>Qgz zUMclhN|kAe)Gv`5Qp8vYwI4vs1M(-)68XQ8%i};aSH3{21M(-)68Vdz@{03|X@T^# zgzYw9TaZYYZ?vMv6}NI|xfhUBWjwt{@#duT=cIIY5z=!rtyrQyAm{HW7@~d=`kEE17OR+*4Nwn`HDzFpy znB}z{SOj?LNkt(-1)Vu@*m>K2Z1Z0VF}zWxxRu9p4R~Zmm9k;l%;SbG%SJpXbPQNrXk?& z&*S$SsofIYT&5x59^i1RvtKA3nCY?(06P3GU;bfUUecZNR1{Ci=RYau-wNvI=_sC; z%U2yQ?LJ}5eh#pG0 zDq06iC1Mc`#mqtACeg46&Lh`XkdVc^_({ILQn*Pp6bo?c<@$;xW`Tx~<8nVX$Z$tZ zNy8YyWgp3=6^~(kRFgvhY&xyoUOr_0uEcYg;!TKfbmtdem9!wmBPm7N0*mGWVE)Y3t`i)n~odv3B6d zovAhHfwdjjw^LhmunW4NB^YS(r?zyB%T$ZQ2ZZ`wvf}jK#)YTO?>j0|ADENsS=L?W zo_54E_cdjsr_Ap^dUhjDWew)K)Oa*Ho^pMFdRIfo`90>BWc|h=BY%Ivu$rBhd7Bv* zKP9|8XX5oUGe3pV^ItHv{1PZY8HbS`7PJ&10_M6{6r4lj%{x2uBi>s&M#{8-%*$P> za(iu=wH*G<#@>N4t&=4Om0I~x3T;oPA?7*b$5p`^t3|CEEz|U-kg)2vQiAkUMfM9& zL5Gp@f(pE4+0BzXd*b||=-5TWj`O&f@O0>1jZy#S@O!r2K>HGVqrGQF>utL$?WS3m zjMn(8w+^1^=`de3{cKzqG!NH0^dJAEW#uY_t;PV8asCZb0`Wjr+=%O)bRsPUsnUps zPd`2KiSJZ7{Pt>dnYya1(o%CDjG|BA0b85hYfvhO1!nYQo=0>YZd5@mus0N;%7~;s z6{#yj;>AJ`>6ny=FFnE4l4&p=zJbM8ElA5M21#h-jCU(%Sjq=8fDwZz#|KeFK3Pn0 z9%jUUu(5+fQhpf!@k))!uzKeol>dJ6G6sW^^3xgru7r^Z9ujA3Xk_LmkL5;$|7{mSQJY10A&;bL&@lm=n`#DP!!s=g3GYnYH zBPpeRdGbz|9WJM%YXz+t9j=wqi=?xrSl61APZEIg^OhroaOCZ=f;83?>spiYdHIt3 z5t6>@mk+kn6-MRyi>0obEEv*&v+WoV>M!4E6l_aurJQ~T^;cqqES)GflHLk<&=EV3 zSBMd^u&OaX>8*15tn8bdLCC1ROss%*b{fIM?j`9Clhb$LX#kRNrRk9J*x(Yi{xW6m z4sheabGKtlN0j{6)Mb+g=H4sgN&7h3XX1<%;X+@@<5kGtfrkvF{OLvcWpa6Ftfv%u zlS?IBeo??hcs~ct<_+edh2Q2=XRj=z-kDFGwN6T{#>Dc;sigJZE7y#4?0_VC2MG^Q zXzE;AuYk`1`MJ>|Dqyq@k{n=g;D}ZdY8#$EGx0t>3YUMzS;&G{X{3 zJdFd~DROtf1aR=&?cK-)jU-t%x#k^^x|4H>QwU3N>=A|ba;XIUB*$YBc3D-tPq63! zgYEKsElo$CmQyXWN}$mvzl8Pkysnv(a(BQuO?{GbOKU_~n&ZIZCsW`7Jr76Ih1_0V zGmRf%N&NdQ!WQFa=Cib~Bp;>MO1T!EE4560r_!LvIQ6A8mD;+WW5V0wJiwvZJaZnJ z&r7L}O=bC1J}W5|vvQp3pDHgT)juhhW+auQ9zjkXBp3ZzUdWqj3}}{t%K7qBjl^V_ zsm6n_#CYWEnG8dtG8ty-v7xzzvB}po)d&#`Mko(cN_osaa{-ey=3bKX>3JN#?KYx+ z$E4I9e?lrw)r(=lY5zv`T)2?(emN;`$7O}Q-%ZNf{sZK(1uLlB%w?^5n=&YNo9Ch?}!uM6L!e$6jUWea);2i^|nOb*ND z-9@RN5G-F^q}16zq}0FgR9ao6)LHu|^?{OlHTrY25FJSW8tKyNLeK~VkzLQzrJkKE z*MjjvpKjo4A|@E{q*XmcqoRPlflH4cPMN+#@trBsK`HPxNr;Ilb9ZzcDtG%)gy{l? zv)KbM!Hh{Cm-HN2*6H}(+u}Ypk2XruSc(Q8| z`~y>_?@*jMMLOs(LZvQLz`YMxmDYy7_z#uKH7Q{J*Qv{5qX;UMQj*9`|L|J^C_X(R|=w9mXef1ctYJ`z%Y z3i&$}uypW|e7Go|C@1wd$6Hdld^+$MF5tt*io=6?56S7(NQDogT+b$4Hj(ItbUp?W ze!PCr^&t6DI|t;``j_h;#^VtAd|VEZFO3h@IHLa{;G}W-&*7x;3Q6O2$ogp94hB~k zA8GuED=~ft)K`F$#*yGKj+5c?<0I9R?vb7Z&{Zh@HxE#CU_t$4>5RxKQVC>GdwB9H$7AUvS#)GezqQqO_Mf7oGv_CVe7+9%pU(ETTBjW+ z_@-^0(>8CwJ~m`NVe#BGa9oKmAJh+xIj7HQo^#wZxf>I}6G9z6IrN{GO)U9x86HM| zBNOFaNnmHb7~gC_h&+eTG&z04Oz*%Z7%R3=bd1j*2bs zy!qzN!()3M=}WVC=Cy&|J(&JPwjYAM)ymf}j4FAXdN<5Ft%`odLd9X+(o}HPf@hoT zTr7F^NWSp=-mK&tT^b+*5%3VtPcp&Dv4!DWX+bnB!~rw(AK9^EeXzI9pwtap4P`Y- z6@qdH+A1{F(SCDkux@bi*vO2JC`NPJpiiVHca&_rOIN6#G7tjd303U zd&=P#Ty6^3#xg71HYMv9)yn!7Yrr(txOBRD?a`Z#TDwlT6VFO}dm0+dcyzbcT;VpD z^-7^b(D)ntQT?sjn=A9(-~E5w{REuzHUHi2-(K4N{^-#wzft$^I8^s5Z`R(L@BaVh z=z}q(3*nO04lHWA z!0d=h^?ZIPm^o5CwFHy>6Ia$B0zT&fAGLb*(^z;9NL|HK|2heF&6KG}K8+LH?E4({ zZa5u#@z4q^3vfLyTxlhP`8OA0e{3J5=iF=ERk~o^H<46$@tvKWIi=07R^r8X;nPFS zO3s!_zQO4ecmGfE<$QNYe5VpElkolXq44EWM4A2df1SPu6%&WVcPd#h3EvX>PUia} z`X(&?LtZ4=3($;0&=L3|j|*i7-W!CgJim6P zVbk@_s!*V9Znvj*>#Xn$JgL;-?HYDh`g-F{gCU#oW&5z%VmFjkg!)#bSDiksN|aj=ej13~gX8Ih?bsHAm%la5R! zSPs^aZy;g*w>$F9M`S9A^WW--tRhIWjKl`bJ%}E-KtM%+iI7x;zw@R2ATZmdrQLK0 zm>u1`9;P@H%wbYJZVuyxD7*(&X|)obd6Ig0=s&sB;$&oWws(c2Nxtbp1vfr z1^xpm*ttRwVKsD~t>UNp{Ms|W0;VyElK%kRtD`G$Ozc_S-m`V~*p|N7;eC8Vo31JMdur^pnu_|K!;3{{$GoIo z>rXW{^?HE?ym{HD*g3+}0JlfU(SW-eJh7Brl6i$$7C-lyST^U?_pbnG6rf)t{BSFY zK|YyMMpeR?-^*cFCtZ}&XaXjYUumbiV054SmRPT=T6YxQuhARKrV4ANRUdNpOfwos z*oxyTbt;eFfGCyj&)l5>S7(6PXQgm0u+LHppMxQlw!5WntnK?_U77Fu8l2UxI+Zx2 z(!llMULf=e5OM+`jzz)m09*M~9Rh2pHOv=mQYk+*{#9F7^Fi&);Wa0ZRh;s|MKc-$ zpN&7h)|s@A56-C{teY`37@yT%Ip1>JJwHEv^;2{yV-a3S(1A1_-rw8}p;U+mE~2XG z-X>yYK=iZfX=}{>h4JR0NZDg)#8ec7a#Q)!N5Aq*U3&eqj`C@GlR44)&*TpT>qX&N zwK_+|2Y=4I-M_dIH+~ku3O572@F9rAv^;6~MJO6@x+|j>q}Mb#3(|!s9xO_YD`&>S zAK=B=haVFiIc;v&+=k?WNMx?3yi&ys?L!T{8~TQ~PoKMJ{!lm_GYG-q8L`&Jn4_(+ z+A^x0f7cmjJhIZ$6>8~mx@?xN0X*$i8(*1Tyd^Pu_{`aJj6UnCO^pKcneBlZzrDtc zIRXp4unIW$NP#9KD~G(Lm)L-#O4bKyy5ORXbUBr7$x(DZa>g<87mEHLd+z}y*HPw+ z_r2ZIJ<~booNniwd#0zmC-mf?G$YB9tT>ir%L!XffNdN=4uB2DWH77=X4%D#AXf$<7>dXv# zZTY0yr0MUg^()L_t1(w{Mw*S=4#^x+wzR(z83~1^PBbTFHr4!XhYHLuvI|9fEEuTz zsB%!VZ)N|$Vv8)404p$}IB*m+w~`HFT`s4mb}wLtdkpeP`B*kE`rmL*J<3L621NEtj`GANQr7{jvGYcz(fatq{5pBWGIOWVH=96dd}V~mPb`q;ca9y2ie$+OCc zz5CEL>S{j(1kqIh023njQFf#b9v)9zN>#$JK2$z+Ts-JY9%OP?A#)4MYE1Jd>kga= zam}s%`f@%rgMP*li_*0)js0Ljt9kzr2PkBa6A_uciKm#{YQK|q1SsY9eeiD3|j!Hh?0)Em%y`lz)F9CwC!oE}^4&>DAyyX2K zJiLQp9-4Ry!$8%xf6vIVwRxM;?Uw)gR|>aRb@p@65hA?C1K@?o@WHh<?dv@N~Fd5Yo z@q3wMVt3=@vBQTSvXC4pNsSjE=vZ~4t}kEUM(8ZW%>=MhWcQvDik2dee1zVmCrU8Y z>b|-+Ie#Ek-jmm+F1r8HleaXCo~+%RN&1cYP%W~3E;y2y!!aR)S4h3v@4MorH}CQU zrmK$8v7z|Dlq6iK*+WUAA~1P+_eIwk;}nqDZ6US0=mbU~0=Kn%=B>wLD8 zC*k@SQHpr#W1s9q*Bt}@79f)zRoFG~WCK1CXA^((CdH}*S1}WL!xSOhOl9htQG1cA zI>W}~Tw>>BZ8; z>|m>nQ~bylOxD8I(1^KXLwZ(c2zWZ_Yv)%Ff4O}rlQ`W+?xU8<#93B$_781@n12>Rajb z28=MQ63$aOKeR**H##ZZw z`8`*7CP%~Lvzf}CTy9S#Gt&x>Vmh1IREX)h*!qFW>6&yif~nOya~7l^el(0Xe;jI| zD5Q?AX3fbJ@J?=GJUQ_3`tq{EseJs%cb;DJaI-PSlEtLjztniu-~2=S6L4_P0}dv& z0lfclpJ9xN>JAdsO_n2Z01id_U!PMvY&I_cKYU(eZ}8s+cK?6zGx&yxV^BhjE#apR z@_78~bBc$}s`h{S=dDb_U;6wUGr&7(ygLFu|Npw3$n|H?7(fr&u_uXu$|DXR14Fr#h4HCzKYNjty${`c@*XKM33ss0kI-Y>!G^_4%_Ftd# zmKNLG2Z0}I*?^xViXUi-zdk1#8hCgaiCB2~0)7zV{`Gke53uw&Up&?cs<2MI(+})y zWheX5`)IE>DcHVRK>AZ%OrMj`3NgpR;oMoJtD%|7P8LlD$~tYQdY& z^IWVveMM(R7`59wsJy!9ht@tL`0jbWgA!`pg<7w!qZM%c>-oRyIJfny9Vkg*@EZlB zeNhk*kRzY)2XJ-UG4geMYjj;Jp)$c0Y7Gvp&87R4K*D2?e;3#7%`8UA0a^4Zd$#*j zmiWn9ApEJ`(=^!%0SUW6{MMsckifAyy6d%aJUr*LcX3Z}07`Ay4jf!@p;kgU6yy@h zUFaR4;0yO6lqB$ik{5axD7sazF6FwEC8f5Y>^X1i_Two`dV#{{^y<soo) zAQ+^w0Sw+od2i!$vGVj1;g1%Tq;7BUx|7WAjNnuBJ6HpNoUOH<{^R=Ajc>$vIkW;p z|9GD9Fc;Cet%NTLl;GA$0?mcxn!v%wc2{@cLx0Ho+Vj(b`?_PVdk)BU^Kk$1ysfA6 z7iztl@NZ8eZ5$D^8a}s`(2u}L==@2-Eui2Gl~MlNYwf48jeu{TUDr;q!q4-}8tu-j z*ZB7lP9XiUL3fr&@zjMP-kx?O91qT*oU<-cUTX&>p*_!O?_!(G4qS49c1n#c+j*)G zC_t49^di)G;a-GFkUIu;<3jHOwYKWDMiriFMD9SfbKbVrkEb5#2kM>EuS*rk=PWOu zJeFzPO?j52IK|4V1BCN8KRx{iJYD@cpd3yggV2LLM1Tuj=Y-PCsajcaY#`pm@E zfA34=;K1!C$oDq4o&KA(w(sG4lhncx*f5?C*u>VXM+tYXejlw<>sn6}T%+}aly|lG z#wz6=eqLvO*_qe5zDMUx1Vgkhv-m;qE!`-drPhZ$mBYaeUzjof|rv(q4 z=Q*%-obcWm)asI%Z+sgx#n^>fufB@layz3x|99ulZ6#WQhx3f!HS50Bdk*>Ky(?%5 z=JS*r-b(O_dA)-6-}oFB;UWSz{xDC|-o&3Hy>F(yH$F%2?dSFe4y<&R*aCdM*3-{l zsFmlo?Se0y|GSjiHntL3Bv4}9mkfn^{zLJSAjZh^Iu~Axr#2$5X;n!m0ez^w)Y%DW8(3gil|(Zid|vyFN0H zXTqhVH@FmYdV*{=dy+uOd&=NZg^s@KYQeYYyEZ>REqK>?o&!&(CSMMKJKz`5j!c%||kw2x4PasMm@)kcdVg+0>rwe4EgQMi5)HLobsEV$0SI5yY0g zNDN4P6dGr2*=s`tv1PB*>m!Iwy}r6`RwOng7^e}$7X2_g#E7I9jUYDl;<^~-BZyur z?84T0C5n08yY2Xo_}&t+$HaRV?pkXHWq#A4%=&gh8UFhn|8djz*V;S&;}-3Z8hG^t z>(qbTveyRxam!vC{KqYO5pSPJ4fQfN^&+(C&Wm{c1nbm)+_K*$|8Y}4LLKtHj{n$e zg{Ip&+eNUyQK#X1w^8cQ@2$13o5lKeV88SIj!xV3{k8UvPTQh=lTO>R*9M)oWv>l7 zZOdM#*Xy)Ry+EDbyoe4t-xor}3?PRTOiQIf=t35~Nmbt-_~s zHy9}~>sA5hOlkckC*;qE$KF~} zuE*c)LaH1+xL~%3tLm7YR<~L47P(F%mWd<^rQNN4yV7XxSBWM1_IuxBdfC0En}?pm z6+=wMWM|n3BeeM1PulD(JagfHrN8)O8doKP&%DeaG9(&OTqn$SZdlA`X%WhcUtAsT zxAX~%;j*cc`_T=|`1_4@ZTa@);Y*L^ZUWqX!2K9DvFlOI;v;XM1(*d|S3`^8aO_;3 z)`y~w7X@Y9Q*--6v&B+wHX5ESlm>J8tGSH1RDSL*@vf@76q?l9%G;F zVzKyti^W&+Sd0j_#v*k71oKwG=h+}jjz<$Pe~TwBc(YU^hB$KwptHVQ*V<#CVv!Pb)eYvBecYj%)eJrgR2sF zZeCX-{YYZO;T(_UW@5tj9~g;be#S9ovp5z)(^ogfu9vEmGjeTUZg67Tj9S`KXiGO7 zIdD@I(1utypv7TsuvVYNkYSukhl7~t{jBHNUwzreEyC>HO}m}(#xUzZ#q2+^V&&BW za^Q65jr23Ik{do_#2JkE-Oh-V;fa8*?dg5Z#%-zW-c4KW@WvU8_+2{U>F$WkVZ0GK z7!;7eLcX0^0F1=kNuSgB8qdGbdG28D#DQ<{7JviN{|odA13=0gS$hvK^bqZj88YO^ zeDZ$uC(mjBP4CC^^S+-vr~N~C|Lbs&O9hc>k5Fe$Zx- z#sq8qPtR`b{}S}afp~y_cGXAw{~D6;THIm%J7GU~OGA#9Waus>u6sWUL_NFicV>L& ziQp%7cDqhzv;8mfQ*X1e`^iQ|i^XC!nXLHH`3anN-VLhq*0cAS*+Fr%`E!Upjk#XW z61yYd4-X;xXu*Hyc@C}!vHJy|rLYTh6z)5*9h(P-eyhW^pcUbl z{R_nm-@bptXF}1#YZN6M)1eTBqW9j-v)aJR7-#e64sQcX;5fehFXGItIB+XYTjP*T z9M$8rjhxe)&lXfXFLl=A8<^_glTfRNrx1H9s4b-UCQ)k`oOn6i@i_yfNaTiY$AVm9 zKPcpPKje~Z{hBF|*3+HVFVI%<-4(tS_5|M*(rsFTzv+GVHGC^fJ-(~pTfc#KFap!+ z2bnLkf1szDCRl#271>I{<*>5{`!D%&Rrn;mVes6| z<~KMHQbW!eT~pwBvOfwJ^a)Xwn>2W2GHgb2G55BgoW7a4_ba$nQY7|ygp%2_6O$9n zpJrzv$pzHU8(1HH(~*nXisZgz9%#5Tv{1gcod?zDZz?fUrOz&$$Q3W0Bd5e(e|lze zdU|SVYML~(54K*ieaB5>p~+*lm%e^#W#!n>qsNY%z`OIS&oNK2-$nheiTEG5n+cfV z4_N@Xz29*(NbmP|J8gES({6Kie=?!&Z!stSxEv04(cyGD@Jst$PTa7AUqF})GsN~Y zw_#A6sp84A{p|>ITdRc@fv}G$3-3VE2lufDxoqd&AF=q&V+;M;`T`zzpl_RGQP?+9 z^LaeJ+6av3i=iyWJ0_MY3)#KLFJ|{YAbpJ-WOxyKN^m#(&vaTi5xz5{P3mv2!EQI` z?e>SL<^$BHtX8|(Y`5YM{}bap%03}@RQP^ktc7%c+Z-ckJ|TSnbB|$|8`&!ax3kY& zc$l3gi`8hdSnfAkEGCoL!d~ITb>R-1&FQe)?GBrrT>!bcEC=NFF%xN_M~e zHPQ#LWh%!W7Cedj&-ns#6*$5KaIhPyh~rvJ_#41qA3huK_bbWdKKx-`mrRhK!jT{U z*zNu_{>RU^xsgL2VP7S9LMUP-QdFM`8+h_M_L$%}b^%DF(Coq~JaOU4Gs1*`lis%a za^aMKv|Puxtl9<7to}q0l-~AoWD=#fT?cK@{w5?g2KYI_wOBicR0^)eQ3w*jwQX`F z7Q1>sFm;viVMv7sL^ep^CU^W!FdK^1ac8)RZi|Gd!p%K=yzIBxvfk8iJ{eoS<>G+H z8}NI*!iOzGE?vy+ikY&>Xo|JTvyNB!-R?lZ?e+tU4`Y<~3Lg=;$wq@9k$r4`ptsb+ z!7xBfI@@#zFHcz=0e8qPX60dXB(73Q6cUMc!0i<7vfJQhGew6+9Sm>Ns94s)3f(qL z;tlL2f<2TB1pO#9?_50AgPcSc$3ET4SB8qJNGcdmyOau-Fz9eRQAlO7ifF_a!maUQ z;)Dn7#s>Y zIgj7^9k-t!5q$al>LDft-!({XNEb*3-nRP9_S3K@7ChfcpV#^4f*^T*PX9M=(f`e) zKk-2rEu)0~?k60C>5%)ZL#}29H&Zj(ZEw1F5Z6qjn-kqc=!OFv8IEjS!d8ApwA)=v zZqGJcXq8c~UT}-|N8$!>-woH@soPF?~;p$y)Ku;HXiuj)7 zC?<&yxMW1GMs{1G=4P}DZ@8;Ee9wck=&2UGlW8*d5mj2`0;ZgwQTpGRe>{(K2ZmP9 zuuloIR8?5WrEIt~+NYD?b~J3#@R2hJI`KKKj3naF-4V*H)X5(v9NB*3B2F9+P27LQ z$@`|yekF5!VR0pM#r2EFGilKyLL>8o6GmyIzE2uo;zPZ zb_>QYuD%9)pl?2ReBIXL6NYCLbo}r68vDxmJiwvC+73_wc?CsdvBfp9i;U;GzLlcrq2QdmO`=*%^!9c^UH$ zKeffJhGw%g8!8{~ABsc`=4~2t{<$9Dks*(_76}a%tl_aCXK+wGI_gY2Op&zDF}{mJ z{y~>eL&V%O($+ z7)5ll;%OAz)ncn&+}nP1`P~Rwm!5cZ*Zg2i%%v4q-gC@iS7}4>Y{larG@EM< zODdVpIh+aOs8TBpOcdHqfUpxFB-lR@NB9Lnpf(44N()C@rQHqvezVdUk2x)-BNi|D z#qOx-M#3W#tY`dSj%!9PGC9?{XsS5u=f}6@viXwBnY0hNxY?<*|BBI*a9^!J0NLwH zEkL1YqQchEIp;myW$mm2-xarImI{ff$+?B>sP~-P;A2DBOgo6%;D=60FFTmsJ7M-m z_t%ETaR+=L6E$fH9h@5!1j$J7 zrkL*Sr0o3P`%f(|*2{HUVPwnuGG8Q}pQ`V6I`!GSnM-YbV`g-20ic8!3(^o@r-qr= zMF66+6T73R2^5StGr=t^xC&NFDR}Zk_Q-^_d^+!u)=zBstK3-OE6B0a*d&Is0chU_z2Cg*uI4^PZ z2~voQu>M+MG4rj_k;`}N5e|qZ4kVKYCNH_H{p#tt`N_$-{HTX{e*To<Pf`oCgr`SVq2G#Hri2Fx2UvfT4G0VYn!qAyEKakv&xvLs^X}G#C zAi~ABLeb0aCJ$~V4-hM`B62C`Nc)oq58l1IU)|rY8u;nPkC-#kUP5J@!!P)q$As?E!WrP>*`bMVTxilX|@dr$!%jr*kZ;=UhrDCs$i+ z7W?0_UZ>3xPdHwhjD<4*9v3q+doXQP2iN4DU7~Q1&czR3Cua0@6TSH5f#P(~b%)$6>C?(oYL*eIa^c3jzYz`RR3dqpyQUP4RFa7#`^!FI zj1{S{HQF!L+qZ8oP6urIFmpN_{rl=rZMa??8p2flpwkkvzE(sX5x~)PG)-ABFuZg4 z=UIb?!zIdO);ygc%%-C6gN?cQdN`{VF~Z7!fAo{>Z}tNecQGEVBoc|QeC%V4W&8H+ zJMH>@*TBtpgnk>2>K(CCNm^};mMg=;=fTu|!MoW9Ft!RK7r`fj07geB)(bJnXa20h z7lekroD1aCDygPVtZx@z0JL|9xlv6)trD^^w(rUp2J_$92LWaj+wiO86siDxTF4$f z>fv1Y)<}mQlE5acnYxx+!aO4C7rmMwExZBTysZ-QMhr=ASS;^r|8xzZ-*M^{DvewF zrvYt0khuZuR5D;OdbKjEYR@_xKc`dlE3I}g8+X}z2j}3{$8)1Q@z8;e5p_00hCpR3W$zySYpsbS;F4U1) z6-8KARMyE!G92v)ZTt2O;?h9~0fL@VLj~o$2-yfvPm(sk#GG^{HX~;ZIF(ukAu@kz zODwH}a?knD>ZDj9`x8h|-XKC6{xl$xC87W2Va@o}(vIt6=p|2(4HPqP!QDs$TDjH|2yro8 zc~^O8$d>WzeF~M#h9iz|8xU$Lo_bv$d8J4g6$%XwEQJNFx!}7POZ!>IV%F-yIkQ9* z7K;4=L(F0+)!J=m)P&SZo3S!8Kuih;0}+ecy_boPAb=bIR)o9Y3yM1@|C%~0twmf} zwPtf+ZBzY9u}Id}uU5{R3}LS)Y%pz?st3daLa{=svun8ljaVqw^@o&>Yo$unfE1=^ zMTq5HR;oSh3|U-$zsnl7uP9`=$UDr6w5F`gB9&UDIi2BaN~=|*|`{ji(mru%pQdvr>%hm1U;dgbt8UK8kf@Bfk>&G z2dZp^&_-Mdh2>xbFo@x??1R!ps$2)l?_1}JAUE1e27)a4E6$vO3#qAihwCMdtH#Rd zH2Z8Jl#`hUES7TZ3!mkJgQYhzCqf0hm-tgF@TYJej6ONm&@)^cPXI?c)cm>MAcO?>y0UkFQDN(-h>5ZdvVFt z*=r5Q< zL`d*M^wyH4QC*%FPRfbIS@an=Ac#2g;Mj|8A)hNapcR)#M;A0IUxhr?dEuD?7o zVsc2eQi)5Rj|DUulisdlEFbmTUAW%w9slY1upMdch)|Se#x)9+T52PQI1!$HEe1t= zxQ>;`xkkL_h1qxvoh;8UIO8l=tQwM{>zV&EXIVBO(zI8_;o@{Vl=?0po+IAzr0K;=?J0Ychjl z(58oG2GkayHKAn5iu3m%7u^S9WQRjRZLYp_JmzaA(wUfdZY~(g zq!UeI+ex+3ZVYaOl^0+wW-T_LoR-C{2qaGLWEP-|kU&8+oR198`5TdNPA%+DR1W3i zOst%YCm1tMD!gaeu;#cdvp*Em8ThuHC+`M^5fdi4hIO-M6*kGy(758xeUt4u#2 zHE5!xq=ePv*%g*evqH?`I}V3Ph@dE3WlmMC959lH5%@L+P_G{VRu~Llc(cMSlk{7( zCS%!}WLLzZI4iL_{_WpFQ7!O5jLku~0t!%$I0L-7)(f4a`ZI3HGht>V7RTxP}< zu6~FB$ci@G{zz13)LON~F_7s79z%VB5N!Hx3YiKz7MnO}oVku!!Kghv|JkrI6VVb5 zF_Y{22MizKk^I7NzdKyzIJ-lHV7%}2UoZt;()Po1i;=W>V57U(Re@bz+33sRtW3ll zL|5p|oT=;34S1Bcq@A)x&f9%>iOkl2)b$_m;yNx}T-c|Hag-GTJwLDgDG~c?Fb2^f z@F#x&lH+nSP_vVr#uW!WrbQy-eR6yMfLGNW?WpTxRP69xW{mP!`xEqC#1!shkI?I8 zdY&k(Y_D*ZgmX-@Um+IB#VYN$mCvJeo14`Zua0OZ@>MM_uYqX{TN;Z1oPSjF#-~!MC#zu z!#k$yL7imoO(SEbY^2pHSF669oeP^XdV{IT{&J{bD`oYm*r7wQ8Cf9Z@CDQgPOZhe zHF&oI?}o3mrnx{7_}gnk@awOy_g0ZA%$UL)7A&gOa;p`|np}hIFSTk;p$_;Qseo*T z43W}jOE!Pj4)!KX1teLo!on7ob;$}b^lvv)zcE#BqJBQf_j-fOx6%j3`HcP8f%LkR z{goz-+H6*9Ow9AmBSk)OkL#(snftO)t2G*RI?QYbROX#90Ptj>_B1=PnCX|=C1?Y* zFb3L!lM6{3`EN&dZ>IxWrKkTy)Mk~>`y$%07h|!W@ zyzgNZgA}|Fimj7oVtQ~Ja#px*rrTp3mrtJHOab-SbZ>(7nV!jc7`GL@2-7ke=+rcV z-=c11g~}Vh2u2k!jbSKqp>x;iU_PTr2B+g1O$ePAd@2~za8VKTR@1GLw`9@lGZufq z7vpjkZY*A}Cqv$my6d;ChFmH~g{8`@A5ccU!7$Zo8m-14lUhR#Z`>U7I6dC64D!pW zRkbjK(^JjxhH?TN>`B7TbF(vuB^U~Jcm2V%;gfJJ{OhKAkm%{Ih~f}gFwtfE_lM_- z!C{k0pSQ)LPdveF$1gg2-;A;44UXt;+3+b~_M%W;>j+kcs^gC3ma-j>%2cVc%#w#@;744TvKqBYj4H)5!jml=QVw@0MmBX$;494Yz-Ri?!?l zZFtvMds}9LcpUs$xL&L;z+Fa4f#+n7R;aIc1js!r#1o*-+PafunH`tB=$cE4+wCHT zogb?l3kEN)Zaa}1m-jh$g>Z?MHdqa{COpHe_jNbF?7mQVATBqIFBEfQV{a?uck;(q_LsFNsUzZ~yif{iO zC+Fw^DLiRdg*7cfj#nkJM`Mm4AL&ABQJVOcNH}Xo;$CT!?!4oU>wNuMjZSU3d$s-E zQwMD+r#0mq7?}9f#KHH-)Mlk#u2nICwqg>)5Ml|~%K^3r)eCg}pU;&N5h78dhj1K; z5_#E?5NH5KkBrQ{xg8G2a;`d+-7{4Edi%@E%gnpJK5?Q_Jo@uO)4A-AsqHFRa*s~E zptjZuk(_1dBkc_PhacBJDvT`*mX=Zv2dDBUSCZ*I(RiPvgMqWCBPJyPSeb#7($SKD z0MieUfU7fkT*i&6P!i|~afki73*iy@{aw0h0Y)6@fZ?6(pL8(7oY?;&sYWRhiLJ`Z z4m_*NPUg&hh19KaCfqVR^DQ1%T2I<3nV9I}>g-RLv@Me~S{B3Yr`SW;sc@fgoE4d( z4np^p`W+E-oZSm&=3k2g(6%;$F$G(A97@f_n^jz+o8!Y9x;pS za!+ehqAc1~aL<{-ih;Pv<#^*8lL381q0E^ht=P=0yUCvI@0%1#yxyIoXMd7TN<<@) z0mnpxbw+&6%%~rvpTJ=AsLSeD4EWSNJ|jvSH}!3>7&ni0xJx%a=qp=JzNlOAR(wfk zQoH6EJy>H0CTAz2AoWa~&GmW%n#O3=($yp&L{1Pt(@<>_fAG7_##jm~DO zHus>}Zew&&ikXS%%&ad5REZehL}AceO(n`_Om>x0qt>x^i~D#KwZ9bcU3KFqQ%I9_ z|6==>I8fIskRt*S^z~}M5ZFtwJV>O47X_NT>mKS0LrDB3pph)uGsCv1*&A`yoci3e zau-&Yxv{;uPIV%@NW*~Cw-B9J%r8dLvkrw``moxi*SYN;hi#j$=}x|E=T)!Y%W343 z18U#&^-F^Xd@j#uAv5f7IP@vPHoP)4BdaFJ7U3OYM-&)@50)ho%ah+f{`YIQCH#ts z{;u$evp?_Nkbr_fRKGCyg3*J5dDOv($!G8fZs-u5!BeeZl3Z5Uw`L!S14!n#_J~x* zbu}2bMlmD{x(m!brN*pZDHR!XE@{72ZL+-WHEi-p~fAorG<8(W?bF8_$)oOhWCE-G`#Wp|ws%X{ap}H?Loh^-f zhW?|SnJ@*6cbz$NkHK$LWL5wC1R}`&eOi(8+Sd zjzYQg)(w0_GO+HbS#KPO^9F}PxK2O5qdS%Sa?Fw|t{I8tOD?&wqY}T^fpvW16@c}N zOt@<=7mk~V{!V@zby1r=7WPaRDvIFmZtaq6LgNei z9jetd^HQ9-uO%M#8Yj@)ImH(Mrq&*j0`wr&DbR(dK5I`fd_dtVbv7kPA{&{u;y<^F{p(oMMBuxP^q?xLYE+?@k zz|tF8a~CW^mnBo>0y*Z#Al|{ZiKh3i*Ou?;K7itG1yh&!bJgB1$aP#|~z{ z-BTv*x48=bR?})03nxYW2v4L?EmdrM(9*h3;%08Nv?SG{LsU)pqS*D{G2^RNY!z}jZWv}oj!+HI3^Zb2h+pMaI5w7S=_Muk2bPL0-Gdw-A!*- zQX?z?vCkRt0tL>*gL-_uAH$rwK%KGm;F?FnEN@wCOaw`Y8ppF(0vjS3r!{itUqE6= z+y!;K!4K|95%U64;~$g_mb=8LVR6ir^y#LPM(4 z1N^##gj=7N($S<&*G&g*xFRePDTY|f&2hv?vF})%WZ1U5+;Xp+Ru7NbB4KaCZS~Fn z=;Eot1KYS(_@YLvQ0HP%rB^CdDD}Sih`KFxBi)?%o^jW0`E{g$B3 z!|CjovrZZ-tz@iD3k4kcrH=^3*G)H@*I93`A5T^0(OvJ;_>p{#oc(+0T4b# zoiU-PCIP1(`&-tcJ-&E{R1b9*b-x`R4FyJH(I&?=qrPa=7l_0elYclI91aF*A+8>1 zhCS|Z)aeOhGtnIT2O*XaP64NXU}|$Lyek3I-pQ`4 zzFl}T$q*o_?Bo$CU-Bj1e2xau{Chl!kj0eHTTE%QI}x{w?BR%Am~hT{StHSvRxQvZ1vLB_u&9Cz}1Ich3zqBrTzL@M3Sp5_RFgu z64uCC`1-uq;~t~Q?KT-bLXp|)HREp=-vE}!H>cw9Em7r!WP+=!%LMOql319S53ZM>UdM}FIfWZZSD=ZEGLLYrbYgMBJK~wo_~WKxI+@c?&)t1n!lz3` za)Y*y#YcnQh0)0PVkl&bWqrO}+MXY5SxqWC=L*z^w+2@8`VO!FaXqk_*Hd6w04!i9 z0j!^9ObPdxXavLC-mXhUL&QQ+qQNHnK9huFCs!6N-W`?wr*62|nK6ouans1mc*!@E zRx8?x#N z7W3!Au#Gv~elzo5e+D3}76Ii)0Oi2ku3Z$ATsFspQfPhT>ye*;YS8T1EPoyO315<| zJ0spfSvW94DrI{6g4Wie337m@4^&1S|M)Vdy0Z9>4!thoH_EL>hbLrrMq~XW%Tw%i zvDwtUKWnwlKK;jl$6-NLm|QQrtyFQC?5@5>-$=Dw;f0ue1?b=foz^fw-d~jDJrbT- zh>f8%U|(^`g4VV(UEH2@7+%X9khm+;rD$%uRo+hGHJI%O`|aM)L@HQRvlFdsK9eOM3&Tg%7_!+Ieo@}VpB-V4P~JM?-)ntI2tvQWdob_KGiQk5i~ zm?@8K+c{&6DaC3xHejImk2`+6)oQz{Cns{%fWsG84(aDhrK#QfD<^kmc8=Q18W{@N z*cKb`go3YCw(_-lpQtGmdE8!aA0f@^r?J2B6bTSvbh#dg;0g)K>N=c(JO!OIR!X|1 zWkr}A6Z00MTdI(V{q8`@)B@)7ui#1?}MTz z4Zooc68wfHA^tLNSzP=9--UK#R-Xs6d(aKc9zaTkM>;NLA`IVwf8$~*&lE5dOw~DP zj*QIAU)z2K8$JBRkl&&)mmG^b!@EXz-I>qiFCD6uqd$_%Y?J9qWvSJAv(>8e$@`_# zjo5f-B-bpKLIDpl*oeJX;jEH5ASp^E|1X0i%zV2YWz61jyRX!myrumzHhuUhAL{-c zb?=UCp`GJ9?=GebSJnUyb|%VX1C~ZSlSby?9-~oV8R(ZZ%Yllg5^ttb4!gw;h5kJ5 zqy$!Acu@upg?<`)D1k+)r5b<~4B+9NzsHqYFhRka^v8?QKW zd3EWMi4#}4K>=~fm>pvAHbU0H){5uk{r?OA;jd(FzC*1V%S zxI66%uo96mXIDC8{ZhTsn>07G`CS%e?fG`mTXHXq#Va<0X;7)KS>0SBN_5TR7Kmp2`*+1)vtn zpCM`%aKV)$8W&CgUk=xS6oLo%iB877leTg^=nbfT(Ql0U=dvZERx_tmDgyqUl_BFi zUdX*YKNePuNo@)LYrhP+b817@Xv}U&8$BwQ8hIye%$XZ2Jxwke<9!w4hVj124D)_M zb?C`=Lr)%~Tkbb##yGDKCl#ecqNETm?4O$2Zye8N$Dv$5#hwxPpj?IY;2W5;z=p53 zzs$_FA7yrHE*cxVNHZzVMj}}``{nw-E!67^x_l^vyKCDAI!=-X>X}~Rx#kraTn@k0 z5YrkB1xsuw6}7S}Bio|t0ZFT0Y8k$4M{hdBd*r9H&~d%6S!VSiKt}duQ`d{+wa9&f zU|hlzruWLtZi~{Z_U5D7mfUDFXu^7bA*x|lQh9^WFj%tqLTZt3=M=~`gB?Imu~!fa z66l0OMbts@xBL++WkM;mzO*;*tfg zq-;KC#hap#|3Ijv;&%rxe#~bCWP5M{Rf+$M>OpK^Ilum;>Z`MN&PYcmdiNHEwqGKZ z2O&dlr{0)%*AJKK4J1ju!;y4Np-{S1;?_%xcAZb>4#xfVoK7Z{XD@CvE)C^Ev)Ry) zhx1Gn&ydS%GXeu3IEDQo0v#2i?qD4jC8&g@#zsXFhmg>Mvhw~D1visV5xIwSWF>ElTyhJ~JL~U_$6G=}~uk0Tn zhCa$g!ZB}%nQFCvCk^C1zLe3a2qIbEN7?X~1c4ABk`RX#U_K#uFA!S?%U=4Oj-*Xq{o6d+Hnh6D1CnW1`#d z_eE#s&a_|0dRCr_g)O?feS!SY*ktkeRA}y|iNT}8qdT~8{-?H~K%u;gm}r~Mr}%~{ zYW74cnb2_2IqGih8^(Q-;gL{e44WfXXIDjn+g6`O04b1A14GAzg^_$v;ZPM8rsI`J zxe!!ZWHDCgnW=}WRfCWP){f)WmLIWq(cn5Y}Bi!2CD( zqrrP6U4}c?DJ1h8i8Te z*$x%lg&c<+bQ3wIzE1T1xJEnQ8r@yiPa7w4QBJ2~bTpn{@r}Fci}e>@baEvXb_}}f zd;;QvK0UBPs08K&n$~>!F=;KC9FmPuQ^tM={=5Nxz1}!gC`=g-Oiy zg6uHROB5UNcsrH@JjfM6AUKZfJ&Uifx&|bX0=OnLIo5EuT=j9z9Uh8180Fc|v%e>@ z$Xvw=rH+l{W-cUo1L_VFZs;MMx7OX=16`bNWB#i>z*c$0NApv|m7}{Ot;CTk=jmeo zKl$hvd#Hs{<8-7vl)LVzhn%!Ed~dkswK(#}4q0 zog)Ir^Hpco%f#meITPU_1VWUTgnXxt;@B_`Wdn4mjhf<%yxSF?PWZNoOOam*ig*piqH6;7MyV?v&q`XoR~hfMg5 z>(P{Y+Mpx|%?20R5%$aPY(IVIibFG*DO*sJ^Ct^CE@I5nI|FmW>Ut^Ta;IHZ%ZOw` ztxAMl3D>|}e{!+BxLeQM;5&oqJXyJY=k}ceXVvU1C(9S--#RxO7>W)wr7^!39(Pl% zf5vCY*3s`<34ySEN&8;G)hM6T!6_KRe9kiuvI;H(Iu5sDb_+`xw~JLiYA(2nE1g zd|_Ev*P2XRzQUHGaLO`~lynL_TD;JjkzJu^&hX6#OKv&-AmWW&v zHS_TkVv$kz^8f1Kw${Nl*|xu0VSffdBuMP05D@NrL7pIRY{F&Nd+nX^K-!Cc8K-3P zEx*~&Fe+mKchYOIHk+ANFfdp1l&S{)k!4gm-7nd|JhCmA=Xr0*>xiq}YOBU>k*SB3 z`ZxN@94cOC)?X%~$Gvk`|C4RO={n>NJ{!;>Q+W8X1p7hAk1ZHSARw4W(8zJrj%07l!x5z2V7F zWVjfxM7>I*K0g*u&L-lExoD%}B&_=I!|m^QnxPE#q~lR#+Ftbn=b_IUOsIlTo6#TDyZuU5EKcpJ7EdCOUrYpw zF10H2ovux#<01^BH_SspV6bkk5K5aZuPlDZZqkOa*}%)V+An2K5s{A+aEt^E#y(8y zQ{Xth8qmw&c#~bO>pW;uh$8&UGG@%G+iZ4|zxUnu`9CL($J8utx5e!7FcYozM_w?e z#|V~IpJg6JjD&O!Y6W`%%En9%P2})P`#_0U^10NIBNPlJg3*f|oZf7m*PFE532)S} zYg@X-CFWAh={{%7=8q+~;IMzYxm2=vOHNK3HW_2SBd*erzrGY4OQc3Z{T=>!1}HO; zaysg`(n0t%474yMF_S^KNz+UubYO2-yuDu~H#C#UQ6qeB_L;UhrnHa z_LyH~!FhzH@xnjAZa?bQ#G+sPBA3vpwVjv|Tn1*os$;O9A~9q8{j2p=`|4vP`srIo zyY~CL>rHpiD9Ga>t}kd!{A~%gz9Yv+Kqt1HcUL-*O%aDvP@Bz*F9-JrvffcqaKMR| zeabbLmn&p4sa;!YS=$v?!!~uuUv4QrS~+Y56+)-g8%~W3%ZEOV!BWVUw3;{QRpo%o)4UyAnQo$zZG03&Y-UERfK; zjg0eri`nTh|9Muk*~qyoL5$#%)t@mBLj#cY#twcYoKx6Sw1^z@{0WG>tupbRQGt=b zU#QhCXU4ZjlsfI4QY8y+Yu)9HLdFBpQY*e~&O6Rt=O0N{cE;v&{(LNKvZTy@Eb=H# zu2j&mPtV01VJ;N#)(lDOe3ff*Jx&Uo!bgi3G*+DI?H^rx+6BvwjTerIq8WlTGT|ges43oW4oK5YPCKaE!xuF9Iu>6 ziW4z4%5#{lL#AE+3`i)!;!tTyYL7i!PmYmB#9+C2<-KA9<-W3B>2cETgTVBCNRuA~kc zCu{iV;^R~^oZ@ri-yo48&~pr!BDt{l;4VEeg!Bi(!&FzvAVg_6o{Lx;q58_B3E;d% zZe8M<amG8 zRQiKCmr|>n))-vV4RiZD6OC$JIVj=$E+@hijh->Kghq>1>C!koDW}=55vuK)h9Xrk zSbZ&%hve0WmXz}pv}ZN?nUUH|UsJ;Q0tkhuQ}TP} z-INWw5v-VmutXNPUZ4Q%K(TWsVgwkwTQ-2Aan|0N4_D@|cX7UKlzJv7e1+C^MPJTnvIjkK-AK|=mML32LF=95<^)er7NtZmIfB(o*AX;} zSZq;n^ui=HU66d|!%Qz9PWYgMH|7P%oaz$Q$%T2MK0V;-5Ou-U42;iiTl9_={ccCj z{t}}O=SOCpcKb+hVw>B&714EF3cK7%SBJtid7?w%JGHucu22;YvN#;ZtX40x4zdBHi|U`!q~6;Q;RZJaE35+U(=p)V6I0B=tln;LN*jF{$ZKJALkQeMV;( zDVIh>%|5r)Y}07=Nvs<36XQ0EjDfjHhpsHWza*9wl%tl96_N5M~FB-V%d zRg!bqh@?P#kSr=^@VYqgTd`-_Xz3bFk6^o$Yx-)NQi+^L+MI;d83_Le^Y(|mGMULF z(&j>}r8X7Gh4;s7;jwUdI_R5ioMM72%Bg$P)|k#}54if2Q(<30g)E24T=s=VtP+D; zDf5m^a9`1x2Q^BSW=5qzHju=)kOmI*GCyW7qicX2>k02{O;->x2zDZyVkhqh)583? zaBz6|l0k;C8s>GD*^x}eqIQ{#R&PD7sqIZSO3ASR6W;TpQsJhR*#~FTlW%AoJC<6i zz}@s%xx9rLWs{4!%0yy6G_!s6kL-tGw3K(0am?W6k3~4 zldn(7nREowE^x&CB_7F!EepMpMH6)GKV!M%#QyM*QDsfrD&NML|sCrC6qhIDTG85|95H~h0>mTVKh(`h$X*&|x5q7I>N~;l$Q)I+zhfsb5EecuU1@bj zmv;QB3iHh3UBeT#!SeXbsf%9Uz5@MWz?q3yKD}Jdj$SviIQt-t>abS|b>Y{MWtjl4 z!-D7M2qI;?b4OOOsO+H*k6m=S` zG^{Ls!(sKs_D#qm)j&Auu$bJklC}}f*LSw&FERUua^{%5z|^Sxu!6?w8<>v)C=*#$ z({)qeh!A?9NpwbPOL+0`sNVH#eUWQhsyrPCj2{^um{|%W(*99*`ou-4RHarOJTW#l z>9afHddA(bPg=@uc86NeHNw$)L_fhABTi3Lr*2;-E#v}aO~kfPC{6j3VXMa%R&jfh zT>3zaPyv`D84H9GSm@`anJ(3KnUievA<0ZueC_s&4qwzr&PKhVgN?BhLwCM7;y@v& znB_jxoF1Qax*DE9{?N$rGOrgcrrUGV%L z-rfU1uDaSEpL=I!XWR60r?)%3_qww)TW5RAX0w|@0wg4a7OF@M(h*RafJh>uB4R`A zfP#qS!IPgpc@IQ+K7A?z`jp}Wb?^Sq_j~W1vOAk>g71%pB!|2Ae#`lu@2Q_d+v$i( z;~TKdSSlW<1ojSvddf=mkXjvDs0{7Nsof@%Gvu&j&n>tsS0Z3Xw46zNdQ=GP2K7#G zvmfRB8D2Qpz=W$pHDq%6Ux`l`O{u+8ilylwy_k;dnMuqI^_WL(J;UK>F&+aqM7K8Q zjE;uHqwS%DD<^$1u#lKuvX5M_U_J4?WFj6LhKL}O11(4ahArsFLTvBgOajgnWfuXy z|B1q$ZK0xXbRw8eJ85%*3R{L_Lu1>Sx7^i4I@W9P(iWFqm$g`@OMQ@8u(FLj3~37c z&=iG`vvLANFAo0*De^00Cnbyp8)JOsX$N<6L@XPn&i`N)E9wYoBH2fdhd66^+Z`EQS6wV=K=fScSibqkb zEM}2{;EEvU_Rdn4$^41u7$*mv=HTHkn$4!3K2R-K zRjs+#o*vSsQfX(B$Z;}Z6ZcgJOE|c-tA7)PDG+K7Tu8OAXCbS~n^hAZZTdL5Y2VA} zyRUJB`0~k04=wfmWYrLsUwj6Cyfzfmg}OvS9b*0$E33aCVG-cOej20|vK=20d<@eM zBR?0=PiE<4TCfx3c#q&>;#q(j#yRS4tgzHYX=9E$A?ewkjBV{LZH-44E7{)OT(;bQ zaeRAkX(^uAR)!q5;c8ELu-XeJ{6 zxv^!5Lw5U2sQ=OtTke!>rs_i)HuJw4rOQ2Fbt%=*g9N3P{X>Xy6Cg`h(58f>CGPuziyFRv4=CnB#sOJ*eZtd0 z{NUCNoOhHL`{=^suUuBK;Me9u(k+97Tco4yQJ+65`35CdK|D}SohYsrd_7KKFX^*7 zd?cI9ryfWq2W&d{M+5(iSK!9)NV#2UZo1FlLE-5t?-AU9mVpVw#J+~;%DZ71+LZTz zE0J7L162%*(1ox$8dI%nmP1{lQM-AU-L%QJP&I@UT{5RU9CMn<=K)%p(g6a1W5hK) zED@JQqOi}|3r=JFg?adb8ZH3HkE^AXG`u&PN+z@#SeI-QvplluD@kw}N#$3IGSO&K z93zZSQAUt^SAFp|hr_9oWmBnaC+%`OIqeH&lj~TFPcSNJ{u)A=Eg-j%TL~$^f5`5b z88mOQjm$=pMXhvBp*#tvwFnQos;3TBcSN#LM~bo(93xB21AJx+ET(|G7T&K#nj_dX z{DoHk3dOyDL807#!u)L)2B)1n50uJ78acsc&6x7`iKT%{m-6;&X}fF6*1FzdP-m*}C4lg%)@>yQAES zH|=Y~yDvLs{>~4a5!jr&`qqibty(!Z@QicQLSTGvX>dm@m$OGzO(Pe&H~RJ~_HMrG z$}@tSbJyNJF}=O{?GvZ0^Y$fpJB7h;@YvxJUvKceXN;Wiz|H3cmI}Arzc7DN!~3)2 z-q7SJg@GOM7Q;Vd!yhOg7~S>Yhu;@l>bv8UOAC9NKM1H@H}rluSf9D|!rwgeVCjU)ouB#A(skGJ@28Ru zc>lyH`2D?k!>Yq2`g8LZBoiX=lhD|yjqJz9J^1{cw-Rl?{>IR@@h?32zx}@}JRU zt&pi1o77uKWjN4THK#{?mc{sT;ZjHL@zHTvtA{y0a^ z@^qmL)4$Epmuhs77I6Q6hokSS(MK`;366eyjXsO%Pjd8+)#z7X`gb|{vo-pMF#Rcx z{_`6BQB40HOBc1(=zqlYr#X6#r;D~?`u92dr)u=uG5rS|{XcoSSc2(4Wa;9$8vQm* z{}D%jnWvMlVme-D3E%$_Xy$o=AOS2)A2e3y}w4k z8PoAP1AVea{|2T%fyM*$_tog%#dN&RK)<3!2j+(T!s`t5FV^UP!*smPK>sFB7a1`f zuQSkJtkJh&I$mexJt9aHXU8vk8q@JQ1N|zVE^fzkyv{&}-`VHIXJI;CXXQO&s7d1J z|BdN*oq>KoT1xmOARmEqqXu;cMag-Mph4jwngxEd7DD_{ZI~Fh?|D}=>n$0OQ;>Fh?|D_p42zk})QM&B!hd2rAFFQ&5_eJ?Zv;ppQ1 zn9gqWy`ocVboRiq8-1_nb(o(BehJ8jVWW}moLQax(n^0m;4vG>!UqTcl4SKziWW4L~ z$lg`Faf?i;lFAg0R3wt>bXjfm6-Sd96}%QKuN-dRm2)wj<(0z?ymBL^v%GS+fmc|b zV0qDU4%c}_9L4WpdF8P1ts1X<64O~;Ib7$JHV>w=ymDCd8hU>D zHSkI61YKZ-Ux4N-f8R<8(HSf2B!%(c$I%a9I=G?1>!$)bSn+~3`TM?ro<5O{?gI5@ zmih>K_j7EfGEnz(?{MI6KF21U0{x6ST|h2B502^YW5=`shSKC2bvJmL{*c{nqO61I z%z#yI-o{+RCx$ins|&RpvE}E%`TF$AZ?W^$yZW{3f8^Elb_->xCX*v(z4?T6cF{(8 zhJ&GDx8AnMT+4s*BTlNHvRHNfI=aCp`(f_uurOc6ML@rTslt_nmP-;sb-aR;$Sbjf ztq4c6VQTg9aISQ&NNH6i6L#`}&z*P|`^3O6_T8C}lw!pz3WXq@uncIe5us*plTXEI`Z ze!+)H2~5%o6Xb(zx_U4GJ5RVMo8*G|?I#6>0x^gJ`A+U1+~326*(9X*nrPY)))@^I zv)w-i_E`5n5~d^ zy89EBouqe+TFmy0(f*l2X2jJoS!MQWBeXrK=%hT*GZ7*}h`)UB-6*a#t@~lY8s^L1 z*5jz`dW@9V)xbz69i4v&;GdguK_uv$Zmuw`x!!->5^%)Y$*J@EKlnkvocRRVf7`a* zXHSfFX{7^Dr0DQys6omwF`eBf7pUpSo(`jXLTmhy~cCbq?V zC7(BvNdW|2G?CSK#&hFK(Eu9n%4fK8Mp(V0mou)ZW^@G_su?wUsAkNR2S%30{rT;g z;-1p*W+-NSOV>juGN_nQN2%@IPs{u|Go45zC+r2PvMEs%*7IC=OZzj!;mr>EQ8L$ zQQzeAggmPQGRMxMM_a*5hG(}>*w&E8YVBg7>jDSO-en@!-XDGS5?Dq%klvkzG zv6u-4OXk;mgK>Ks2mWMx@P z9UbF#v&JMP{6u?4Te}2Nrc~mtHid!?$si5O-KhiZ;c}K8NRI*~XM^_e6Qpc)v6}@{ z2w7s4Z3kA(jO?la9sB{9embTPG3Ts&j`=1jk*DGBZRloSd6E1AmWEkWpiiJ{9sKIB ziYRFw#B%el;+q{(wd#Q)T^j|@p%5?eHq%9ZVc+a4?qRQsvSz3?2mK_;vsP=H%<~(%UwHtcKMVJ_JcE5kWurC6OY;0UTz}LnVT)1HdYvRnw?>_r`LQ*X3{qsN;!uOV#CnsiIbvk z(dIc~lzDh&Z!GFF*(07d|9pg4@=TWweWWMnurKHhkiL)>bPz9-S&)0Ek0@Fp;4`#1 zkk5#-z_M&LCfvO!&4f6utJ`2U5AI4>(r(w2#Dm{)O^*zW>W2Dca<|&0qIBNbN@ye^ z>>3*(C5yRA7K&doCYbLOd_6;rhOm@J1ugHEp9RRy4nDubu{fQq%0Ck(P@T4Sfk$|gD)Bk>W@{iPQCIq@^24Q!JjG{-E${NfW3Bu*Xtg=1oVL3BEpI_aBb{N#t25Be5{^u)FD54ft7xH`CX zLL`>;ZnB!_sEH~$%AS%jWAx~I02zm?R)5Tq4ao= zse}QRd|I#t8z3Gp&xuXd<$OjBSBVZBD)E+ul$SmINYw@|uIDZxq);6Dg>>tm&0M*A zZH@Ww>!s)#k2>4l`78gw$bO}zA8b)`ZtNR+lsIo+XK=JdrFla+x=>gZ5*LhY>O8fx zm|0zSev(@E0GE@ERQ6Y}xg$hbQ4|z(2pchA*y9D4tnw2n!tDPIk0?`eT@ElXv-*LD zbHtT(SQ*!UqfAxOi!Z)cNCW{R1ThVlHM}_sSfGt*UUhTZSzoReKrk0X3GEdJj|~h) z-*;b!honnYk{Eoga`@)t;OmQgCV#Ypzi_btv>$1kwE(NeYYEkD~|xwhrf&9 zP~0fPvzC#Bdqf~Pz7~OlfU%Lc%svDt9Aa}oKVOI~&UmXPD3G+e5gbHp`3dq}W`B&3 z`mr`GZ*bKjGvOSSY5poLgH9{a^U_PPM+F{;T9xdEExsh^})jc1&i=z zDU?bEe2m2uTs!X_l;g$OL&O5}XyFHe??uN_v9Y+Jtc|tVs}H{?V2}TCsgGC$ zduDwkN2-MV3pWOE*=K-p5!YDiYlYa8tzQLUC}9i4i05XR50Duqii*6LEBWHC3}5b5 zyRWQJy7g7IW=p|VaKXtez+_Q6KER5jt0gNwj->qe6XXY(PY~garsn%^lD_onv83no z@R8ggDRFBMvzAUJ>=u9vKR_5qnC}x48-|jUooo46`v&180f2Gkc?>Ct`bj~2r6!d@ zheVPF6c11};Q#e&jE59KwGBrC7Q8A-bYF4X-dU|-;W)qrgMD{Oh;sp8P)tYNeZgY~ z7-WSvs{a=v7Y^cc&_2+`)nLjbLFxKvhOqdUEo+MM^#jl3h%dqI)m)el$LvkO5ks%l zpj0EQ)-+sW_>47FiG~T+F6JTP%2u_a>CcmYBvY;GMbT+~3(FlLM7zP>#h+PUdE#~p zf4re;G(<@DGEWj`Z>V+@M)NwE+-UtMD{l~fFpuDi^t<|n&Z(@8st-y(h6P6`!hM8y zmia32(gq-W{rB6RCZWP-EuOGlLGyURV7-DsKp?&tQ&fz0yTO7*!)n;}Ru*gy$vNiS zBP06iLCO)o-TW(92oa_5;Z6_WA#$T24T}$<@Wu33QL4F610TluZ+@Kf`tOsU;fH=gB z`BzoT50l^7H|t!5ixd6UDqNgY&jbC$9MUF_ijBh_eN;+-SQ8)pReD=pnsK%!X3R4| zb4x#P z7b|9tT8|ed!d2$c$huW|=?8Vslk^cP^N?2c2Kg9lkOX%NsBqdPV4oq=7rQdR_lWoj z{!%x(u)WVhdhtdVUQ1Xya(?z;ClUSh4cXzKQby(7Puw5-rI&f(==H3;p7Bn5cUx90 zX5JqBaGH5#BPFfCUV@dgNhi!h$L=;8;XvXAS@V1xj-r|z6`=nhuMqGcb_BsJ5o)7z zFoj?no%=9s<5!gS((uq|WTD3w-(02vw{djIZ!*2`bm+SXyU~>})W946N1HNxVhFr3 zXC2h1N)u7Y2@H+|f>ql^2Vz&@LB4=3IxWZwP|8>^9ClTkF+H;|7Qpp1W<7wcbFdEU zd2tpz4PNF=gOyHFl=+juK@XGD%kNarEI*RLANUrD%oTK3ffum}!j5fhx4zZF;@FjI zri-`Nom`wHy*2{F&@SWH(6TQ=Of%_J4wBtWzUb-v_QSbf~^YBFtSO7!jb|^9zKI6mbj= zGGgBgfge6QyZjsS-O+2AnY zTpGx8$(H0IN07ve^|Yt{BmDoojet{Up9*+WdRkovoVwvNiEk3WY6hJ;brE4snKOB7 z4Ri|S-mUCs;W`wM_kw~Zqzn!tfZBo|i$zUj{a7de-*~bb^IC|1`)7Hzmbdc>D*r71 zmaCT10xMQQQW3&T;G9G&M*JRVcqNga3g~bx;gu{30vsKDK|t^0=%;Y>-yz`#^nUI= zF9<%3pI>B=92El`{rv(xrvH@1x>gKw^p^#+ZqfeF9Ag5b)4KE}~u zewe-=**QQ5yAZEKh+hY8{1Y5q&(o2_h36qX89(2T=@D3GP|Sfo#nGSV-d`a>K?XWN z_2K7FseKn04=Ny82h$zg`_DkyCOi+>vWQN6TM*{P3A!H8=eXzDaT)?5!e2lZ1^(;_b{2b4MFOfgNC`j_*UphWG<9x zwvbT2{A2R9eav}kvsn!tlTSmx!>@bPCKLMmc_W{R<5EJoKVj+ZOJB4XIrtoAPf>@8 z3720SH){}nlg7LW3KmhL4^+5_f7d0Sr19nX3W>@|S>pm!dt_cnj-{v+TNzMV+)&lJ zUSX-e@3!{utui&%uP()-V@uluVwWmPay@z%LAvrx;9?Q z{CpJ*>KF6pMr-F*CL9zVm5FgJo1GcYjVZ%;a65er~e ztr;gjLdH1qnZiTRU#*(gD*&-XrEXg_LWr&IU5NwY7W$t+oK1q;M8fR-j_(`A+dgvF zp+nglZa@(VFg8B`6L4eLHSB(20RmU^K8}r|Z4e@F9+;T`he4ip-;q$7$>pB;Y`&fS#T8I6aDmvaETG zt)PTxI6cSL2kK|!GsDN%1By^_D>g%p<85>z{TbmV@R%nMu7|V4hwIz$s%6$-;Md^s zAq{kVrWyXeT7$(W5P&Q)D0Y$v)<%ZXm0^FpUWl=wg8(5n)U%1>!e$>s&7p9V?g%8w zVcxsxv`rae-af7f+Yec=d+6=d)~-8N#CvosE+CED?Rstz=YE+YnJ_%gP9&#>%=52zF{X2^mOT1Ra;IZ);}@k}!jW;1uF@__z(l@OjzMGCl-f zWd&Nz(bXsh2xoo)8cs=@+D-LEiqj^KZQnOrbelSbZ8IflY%&#b7X69euGeA;U5<|t zH{pY%s!MO=m(#Q%adJ0@z#M$i{3YUy$5`QA1r%oDG++vp_u_b#ClL zfMmpu#{rMbKccsrx7-OBWIw7_pM@J8U~X(4d?O0T8{jPlj0gkYW`7(UmpH)2T_rSX zAjDnE#KkYMaGoRw@JXI=-)upwa!2iBy{;&Ld$2H`+jvw@fInN5X`m0O5nnlH6HmbR zjBx3Iv;t;sp$gzz25H0SK>ck^FUOeNR@~M?7Fo@pm9P`d9;e=E9uGk=2;^&VEBvBx^8)M~QTqi7}R-IhXZn8o^K4OpWwZDhs zn;11{Wa`|&_+KJ#-CYL~^qciT00)~UA`s5t1UN$KMsS-r*R-~vuze^AlS}nvUHg1+ z0$nH#vbY7v=AYkg2H8vm_k_&;DZeplA`P((0c`$&GUqi4v8dW6!UH{r6v05XC<4~H z@PdVpuSlW!8_F|{OsegPl{P;%-N@G*FQ2rjjW-(0K%yw}83 za>_axDeeg#cS5QiisI&NL`kYP8s1|bsuc2iF_V0a_&w}b5LZ~SuJs0GcKzH_tcDq} zPyNE9<()FWBfk2Z4WyhBr*i_U0~;q8(h^!j!{xOmo~Fiz7|MuGB(=_ZvLM`QGV)xF zLlYbgm6`t~p1=4*&ZtSd6dZ~hP08VaG9lA=RQWt~ksj|ggtUVv{Zj6UTY_;dil!-S zdXJ3xo7$bUIWu0(sLSDY86%dAG2_O(Eg*Vetx$J!P~94HB9U~#H3VP+at-#32MOP+ z4Aa~XZ}~+QcTRw92_f7#G@MNwmtvJ%;Imrz6Jz^xfMavSyNrZ*_b%iRT-)l&viwzY zyjoqa%@gb8z$$?d!ha5=hM~%`;*@M&FTfG7&#Y1o(wnFT-Jn{%{)9<{t~V$K zaJ5t-YVPy;;;-nQCk8n$*iVsr0=z^AL7hTQTR;)V-mzDan*iunaCB&Mgz1OT;sE^` zmW~kOF#WeklLPuq-1CnJK85MOK*|-+Kg7|YaU`a{gf4ZU-^S4o3+};A+XwODn?Wq5 z1Qmp$+iZNSGUuT3i?>$S_15CUkV)@aMD4cODJ|%# zLm3F5=`|=XbNBPg3qbv~X|$=nX%^=1sg`OCB)N`jotl$ah`+yLh2|~nb`rt}z{7{K ztJoBajXR(AMj@m79~*W+b@$!rLrJqocS0d`>jv@xSRXN<^+M2rDwC902p2G%F9f#E zu{l0!yohhg=vLN}-;hSubUgm_<@R6Mm;+FD#&-+raw?!1ji!}H>QHNkRAfurIpr6~ zdmGZT#gam&V&iTp64ef2X#3GbbRO`@bxSZJeNEE03)-$tF!%s-{EwJu> z?4%Ncb{a>?W@tNE&fmDJ>h>r>%ztg8?kauxZdLDwT~=sEU%|HmE5Y~yqO;lBarJdb z5qBS4*LkJyyC?2h$AN{VM;tk@Kzdw_q=({i5{0_hQCtg)jur~kcm%yG#=f6*k{r-3 zpo9hT1U@kv`XgdNVJi>&96p?x%_e%CS^X-Pk_|}>O*z?2l;5SDB-(KyxYjAb5(q97 zY6g2t82=|{V-rvQAovZ_*B=ZFhJ1se_mqike=zlVvJCFf-*(GJp@^(#<%-?H{Brfgx zC@I$k^ku;iaRufgpMd1w{K2F8oFLWEW7&Y;3Fj$ezmpJjCWzN_5(*1|-nXeP}BYUja)Z+EMR``H(Dk}0?fpFy}#%fk^ z%#od1?8W{(>@IGCr)J$)2+AET1fQ)3gL@9VS+yQ`#J65UtV8r6mlo^d0-Kh--q|;T zE)1ubMh6FO4X`#^cq?jdt{u@A-hcM`o-Tdgg`{bHZx`CjH#mfP3U(5_f+#b%bvS;F z&kIt5AE%jTkLvkK^;}#0m!o*U*rSKMUqaRw+8{O7D0Z9=Y#-zRNA6hP5vK3E+Z|ZX z8HOqi9DrDIA&&NeBIQP^w-@V}Y&-*dy-;*xZSpS?+KA;gnEA_m7t(&66We|#-)Q15 z^XkyI3cw?5irt$WoU{o$K7rqXE9x-y%#`HS4eXdG@BhXl>HMF=51r%^fQe@(=hl`x_1-^qp&F1lgo)WU*TJOs{y zWGWrjj+^WdE8o?3zq{kVsh?opB(WpzLM)0oC70Ln*tKS}d){-MIPuvBymz1VPjShm zA54Cd$o#Y1a){Hu#(9XMxZMm$Z11r;=Pr4`cgM%DgYGNeK1$9j^E;B>{n^r|zp+s# zT^o$>Nvtg(ri};+T%5lp<3e2n(uJY+%Aw}j2?&kpZjDYBls`+b&Xfil37Jny%C7Ve zK>QpGs>e7d%BMJ|3U;o5qvf(MhdzE=wy~lWyeb4BgBg7p6Y)}Y`OVcHl_lQSvh~UQ zqgc6m1@~veE>Q%ophW_RbKXm^Cq)fD6)eCS?oeckeAT1t7K%p4jLP0@X2j?{S>=Yt z3D0%{2(zuUle*!bF&`a}sD&66L zJ*(;hje)#V_&k3D)dAiW@olOWb>YfugVQo|`#3@7ntb z(iDOIVUGSFem(;4hd3nAZ(-?VkjvkEiGU~}&~N3Qe}tn?qnI4fZ|CTcrpL{Tbxq#U z^nUZoOE}KuQGA4>e~^36FVIyA@41ts^W*$8fty_@?m~3v*mi~BT>O4Jj?8!zcXQ7_ zzVa(fKfm$bfqj9l$e6yLbD=)SK94fHF&#U(;JcsY-ov|4E66hh^oKZlEw7p5lh1MQ zv2gF%&+*CUIr^ZCo@-U9m9xcArR z3uY3~zs@}`s?C>m8GmCno#U%-a&#kp9_25CWdQH_7Ds=TJ1-Ri6m_6K%Fz#S^!=Rc z86$hbKJxj?(?~0Z=O5>uKbzyX{U|~Ubd2l?&jY|QtTW1A22~R1-{GFWlh0q~`0WXf zKE%!IC8TG;^G~vL;5RmZe6EqNl&6!=!2OPHndfk1SO|9v1TztM67-NbcHpGPnE~SQ z2R&o{4ZtS3hn@Ff*reqXlRH931x>P#`N>Ik4v%qb^bR+-GX$4_v<6E}XaH3q3U?5c z+O0`E;DhVn!etG~8m1An!)eHa)c&ZRi6FC^%+_G2ePD46r6T<3O5)-ND3k|TNkSeZ zUya$V>AK33Fj^?HP249QDCP^bG}=F~$&j#xk(J+};lY;tt+rL4#!LSOPLM+ZYA|(C ze(b7TAe`GJ25bp&!zkNk7kY*=sZy!$w58q5IQhu(c|>;jFU0drS(-RwXlpUb_pZCE zx|7S!#7)IT$aN3^T;)CWK0%y0=%IlJ*wmr=m4`ETp(e56?iNE18n5@lPe7&xH+n8< zi*@xp_bxI@O}3Q z&IT2{b)mJE2P7!Y_u}=vN2Gp(&a!jqr z+J<`v`;~U7q{FCiSS@C2OxE!ZudqA|2$#{~2MRr5cd7|0_0Fexgv(8{3kNTj%Q}-G zbK2ro(i)XYC6nEiu^+Sl|GO!ic@JhPoML>>m{@76xR#y_Qt-q^BZ?lbE zvX5~A9~HF)qsGOww``Ue2SUTAIMrGWLh7S6T9Jqt>Q~Er#&AB7>d;C=ogHFIZ_rR~ z$@`9RF{O58u%uD>0t$Inp-2X)s7k3;s|lIYBy}iA=6giXk2<@2(9)hDV}wE`l_}-K z*&AP3QH>LY5NNid;FTCUGkZZ{uKR!*YpsrPnTYRBOgw9#v_6L#Dm;lT$2R>(h#}FN zMl0p^skFvxUO1j<(YRRV3^-yn$OJe{Eu&15G%IBIeCYRrFZ}p~o~nk2XHBMVb=)Y^ zO2nPg_L$G_@Kx1{?|XxkrlOE*)kNml7UX8;I}05uRXR$!yTD8!h$5j>sgy>o_h%ny z_n9@0F0(`}RcOV;!0{{=N;Pl_psI|*kBnzD*xCXmD5GR0RLBif9 zjTyg<%#x&PNSKne8e}rMg19E1O}8lWxZz45kVH*P#%Tq*2Jyt_DpADH{635J4q{xQ zOOBMI>0zDSyp_3(_$cx6gi%}a4{V$0p$(hv;YuMJa?myxZO(jyxZ%BGM1x-znk)PT-~I`>{omi>{s;Vlb?$%S z2n!8AbBxLSq8zUh3{`D0)@DeZ9+Di7yoy*o(m$fywntzPReCYtc)9( zCy3?K&!KZ(?Lvj509_-nbP46s^8m7;R^wXo+?6lY6J?SpjNTx7grO&Tc@9NMv z3}L^~&}X(Ym($gBzTe{f@FQ}!BjhsxG`tPE5B_yU$Bi_Jl09*jZN29*HVM`rD;CRa zUrz`Hw4o{p;s^uo&!1RGpVa4}X0qjrcJ+-p=}2_gGrZo2FLRD$(*t(f%@=AX($nKZ z;ea(PS9%>GXjy=nQ4A~W7eLiC-zT+Z|J3AP&Ev#n}PNy7!RIcnF0+g$@ar;W|J06uVzyX*}Ib*VV>*T-+T1|H#OTkdi5E- zdwL3|j?mOhap>T_v1yM#lAiRB4^D0l1!8k2&Eh=$)9JCorg7V4dvtTzxhdvKkmP9n zFFH{-h1Ne5WY<3&Brc1E>@j&T8Hpk*805nHUkKTmM^8)oCxE)$;T$U||8d_~QZAz)O*E%z^ur-}3 zX9IRKWocyx_Gb%Y%;WeGt66WAb}9Waliw%n0XxyqA?X;%<;GBh5MWYNJQ)`30855r zP0-)aiPursRIDNRq8Jl8Qk(*^-egxn>(nOg9zIaH@jO|2OTt<5chZVb(QI+r6!IaZ zYG5ebV~OraZfIFvjcx1QxwW9nB)mDhkRZIY(c(23eQK#OV~tiF8EdfLO$;7&b#QwW zfoKwDA3)h!YuNipzLsP2uiRc|apYh5EfH?^uVDUOUihcDRbD=tHw6$!{<;#!^Y$t( zCw>LBplwPSoOP6lU?g*}9vQ)I%=@t0yacUZ7)Rv_%p@D*AtHG8jeQr)%$u3p$lS#j z1*#eANELV^lQmo1PKB~6*9?y!-q<-heoo~>7s|3*Q}#*}o{09Yeq#H{dj=Q$uHE1Z z=`zRNeR(kVJTAl=R+kC@r)s>xd^@-_xN}QEn~8_gCK1m;^{3J{;2`cQItjDK3CF}9 zj=G5F)dE~csDrc9s?ZkMK*9$%#3T913;J)kF)3&6BKxl2z5ATW(ROotzUr_$Jv!Z> zUOzq@D_PG)H&$SwZ3@WZ7B1TYxCliZS-5cId*h4ikl?|0ILII2 zNYkSH@aLY1!u&OAlDvHSZjTBm-dQ>~CF+r&YW)1|bkB+{J2H`YU2 za}(iH_f!S~C8JWW?CUnFn+%Xv9?JjH^ahG~7RO6NcQO6OY*J0j>>VyULHLXYw_Z%P zcWeCR5d5DSO$7oWd7IGZ?2lmM;{-7RxAcQ#y-4t}BQ4%)UFJAINZoCCy^(N+Wvzq! zqtyie3<7DxPMmBeK~YX8_(CA;3k8j+9z%2xukuonb^m_-N3hDPl%wT0EMd8{P2#e< zV-CAg5B+BrhWwYlzp7ZiRp{S;$>P$&h|;eMYeLTDKje4jZN*?>piMj=6zV9mJviju zU)&rOk{U{)N|-uz5~58e_611N95v^5OxnWcxiisj1m-KivwDqqSf37MvwCO2Q*#&J z*LP(qqO{5_&X~;@u#7QMyai{H@koEUa?~&;VC$>aiy_a(Wz=z znjKC@NZIx`ktOf7MYS@yk|2lyLg<3FTiv86wU{4@F7;q$-zhqaJMQPV*st~PgX7pR zxNDJg<$Pzr@bE_&Df}AG@KZB&PrQ4&+@z{5|H>MXgFkESZZKz(leOIlY9dbNfytfr zl0OqKm*~Vqq%9=t-FlNz=WgYhk2^Te{C$JhWIU^vI=!7+>YhSxTW6+l#;|0|h_@W+ z&P($Cs4qH9N3zpwN1jz~@a!ZncDE-SsI&=-}o-_AtFmez!KIkSgqC+?i1iNrX=v zQ%#M7$GWs9HS8n^jZ+)%)JWYdLfhjY^|aA1u=L$Yjojm4VH~8?YQ&WQeU>pm;3e{QTpU)bBwM zqcG|TLOsq2 zNCcPa>br&6M{cSe2XwbEquGc2yHituHVq=JHycPyWaMdWvUe1%LHNiAz67_!JGviu zeEzYxzY>+^J2KHwJX&={0{vkYZ|k@leoI zQ3}1Tlx}Uj&y};%*@)J4gE0&O?dsBn@io#fwX_pom8CqoDpRSG%SFoAq0`FrRztg9nxW8%$ls zw69d0MK=41F6dq2yGw7<8VW-a;&Lph-y*MqokAt3P-}2JMX0F52l(Wa^#T2ml?|DJS!_j<*@B}7@< zVZl7uiI8oIc)*Jy$PlriX)oq+d>U4(wls%01@;190)s=L9^%125B2%TWD<%@j+stOPPM1`~4;S>89x=5F zFeLIRc~_YEBk`G=)CL=9I})!`*WD$lb||{lQ7T)}1j_!jDMnn%x`pJ1q&+*G*L6BZ zN9auT!YrKv&DG=RRu4oi`7RkG;1b9m2H7HKBE5#t0*E^w@D(h-E z*g5GGmIo39Eh;oDKSEJzKds9z#Wx?wvwwEw2dq8wX+5o}s*SxfI)|ydQy(sSY#BSs z*Q@@@V4>UrwZo?>oIYVU7|>q~Hl@Uz==Y{~+Ps#bK%y+}Xv@+5UcW{ri=T@Jy|RzI z4+gz$^`P09E;~@p#|s`Gm`kIH%Bo_l$A>%U;1S@m1yGm{&xgE^iL!;&nnYM@&Y6lQ zjd)3Np}4<~E(gFu&5h7zI;7H6rK*mx(RkT*?w--J`^K+X^qZ4nGPXJAo3u+WhdI7s zu;@JjrPiYBAjNH_>}*ErQ>*iNKUk&&5%yYaK94zSk?8{=LvqrUcMfccZ?6n31{}sN zgFG|jkjr9M@q2};!NK(n@rqh_vgSzUMvii0_@~GTIZtk3Cc6z++gB0fklFXM(1;u6MmE0Oxang>|+w zYU@T;Ex3uc!|3E7d5ho_5Fm_-hA%?~F}~yRa3x+(!&t$O2;NaP*;ox(>6Ap7)ZT#y zvYi=$flOuh4OY&Z@@jk<`8lonNQr{cHSfxnq_vD7-29V6}RV zGh*vzzE6*p3S%@u_6dou?rx989a4wlblBJyQiOWE;2R-=@6vC_2tx52b^@YpFoA$z z0#un@EzG?2eHzEL7s5~QCLK<$dh*{^`7n@cdwKL2_UowT+c9h?8~ZySuSY>}lHe4< zX~(o8#CzL);bTW%n}1w)>@0HBC3=rM1VFu)!kX#efL740&RRzx7&*i@2kY<0_$|n< zg+vM@R>1)PZHe=(qtcCZHcNr{fk0aZ4iOyP>kYwRHSh~&fV}i9<^^ZOtnTSw3|aFF z+3Ugu^OQuRy(l&Aqerr`R3z{|Pb4ds2}_;7Rh2>}& zCc132+>na}CWh&Y^7-?PV%z!oe2>DUIB>vZ$LiE9c?ryi0>|&*T6L<`Y(S*0o(-!6 zVtIPK!mbI8248@ATyiGNBWh8X`j^7Co~?z2^0a4G?)T27CValpq(>dJ>a9OJX!vb6 z9c{q*fJu~ni@P$>iHy}bH}Wo_p#4hl{Q5?QoVz?3gT`2i8H`xFniWQ2>@l2*g{~`f z{eldH{2P#mNb)yG_+*k-%E7sa9?oD;uR2g4D_WtO)9{j?E=>i?o5JG57Z6dTrfSrX zL2Gha#KwfbXTm;Seh8+iQOaFm(^b$Ipm6YKHe-jR-J4cujY#U5%PB@CbZk0c7$yN>a;+uPC-Nvb&_(HEd z-=9j%&N#+;KWhlKn&TJj{X-K$=TOmQ&ILU&TesWgmB*|J5`epwrw&R~w12KFahOf! z!9o8>)ko|ECT%fWxKdVTajA+0pzC@Bn;@AAZw#C!bZpiz8h5`m!ag8q2=Hpc;<)+S zr}-fMd~k@0@0*)1&iE&&xUWAyN^5eN`AX6fF&KPmTPGz`=p$aW(4H`h)cS6c`4^qp zIMn+RFz^kRFu%_Pwem0K_b$0AOHpGv{|};5XY4lRBc|c`n9DQm0n?loA^M^G7bufgJE#U5h%bG9j-UzV z7Y&uqhn`zi^^A|f8|0Jl7KD^xLo1ThQjk{&T}E4`*?%wb|A@I?&wj85ym>cs08%TU z1H{YZ$X(FkVkDG~FXoecLOo{3H&AU4{sKms16`9A!#7~9a4Zf^4+zL4#`L`NPQv~- z;)=;t$ey6V!~3hN-Ys1D+sZOd>_8oPykK777#}pXW>sG(ib>Hl@ z(OF9Ir#5Lm7 zyStNNl+tdST1F|9?I035sEdOg@^-bJ0~`M$)PJy8ms2PSkF8lncGemZ#^YK!8Vojc zje%u`4KwZs&<57-K%|1!k`n3`H1Hk`{WQ1%*Z<}i8cUTC;7 ze;mE<0B{pp_=w0Mp)i%rqzlgJI^ZUB#4{KiED8lFBpcCCq5C+orONzrJv>xwUI{+~ z`-_$^BOsah=-I_d5P4S@HbtQC|;fQ=+oM`|>-9;hT@fmICw*7P1TuDl_dft@#i zmk6>e&}d;-H`sSfT#FMUK0!hs6tfmp`N-D&Gr4QuY-m+?viz4;bthw9NH12+u57|R z9ItLlBuuIEOSbgxnAR6|xg0^iJ3#MEvPbY}?aOwwY0Yw_bIR??I|fR=F^AHYg+^Wh zL$^KyDJ@RBF-<8IMj;3vGo06-z#`C405uGEq8DU0H<6ki!(M5qwHRI@=+s`zxB+V# zegd5U>@VhyFKOuQIVTj{7LEBQ-D$t48t-2S)1mieCkgT1S>`_-ZlBW*mShH+lWszM9D-@_4bBn7N#VDWYGkQlM!C__6DE;_8``eHAS&Z2{IRU4`2G| zj)GgC3mYAEcZHvy0Y~3OpJZNK1vv3oi{23V4Qw%SGiv{^{LCt3iqhKN5pQgKn*l*V zh%RV!(?nrK*15+}xfl$mD@YRw4>yqCm@v+z3m+QHaS8lslN|46I2iGDs7bK)Zb?x zfwm>6Wr<};XI!WnLW(Y#Qyz|4DD;gpDYKc#n#`dqRFZ)H=-gjNIJ&o-8`W&b|Ab=3z;W{X8Czgm=uMw8+gVKiGz1RBJuZ{Ox{ zI90N2DwXY|U2f=(&g_JF$6+XH1Q^9yR84}IqS;2dz~so|OWmPRPZVrPrB-2A1p~_N zajnhbGHOFAoi<|#m1037xz{t{tCYJtdckGqu~i%cb3sLiq}twTD4#Je5aLfp;gemE zVVr=E;+t*VWd_Z!c?2bX(H9ijnSOrJlVWLCi?KXk+k`24V2IlUr6WW)4@!gwbr}pw z1GSJ*Ciq}Y~%;S;C4tTvcxzk#k-mPs@sXh18M3cCa1kCj;sF)Jv3iitOL(lqU56nqPfk>7 zjJlD*w`PxxO=K0HtgI~m2{xn)=H-=7tmNUgZc{*FKSvig(&gW*(dV1!-vR@PWZdu` zKhPBj&Y9iT25HOMzaXo4(+zXo&o=kjQ);cssqy-SWUyOrH^`g{XF8~=cI!-9rC;O9 z1eN4FLj%&TlB6Tx?o@T`ilwzeZBNcX`xGL2^BC|H`m_T+joSGD)Mq14t==Q5^*}~= zPP)E9QVU7{dL!c5CtZ`>?W*>jt4AinBRjw?O1#eRM_rh8Smh@h8r^6s@$uG?M!JS8 zR$S;37ak-%@)NQ7n;~WeAxNA>^xNxnCas^1iKWGy(+ zywiq4m9|Lb8xXnrywwMp8kqS`NJ{mk1^KcDw|M-f%C+ z(`VAdw#sbf((R}1jrlD-_6plm2`*2599>{RL=k8}Bccn+OxozEUcq;_+5F87j_!V* zgXWGtOfeqjC3v|gxLOM+pt@?w*5LpMpL51u>y@l{OaZwI=#9p|>-gXO;;VRhTv zN@7tW>u%Nq?pbHCg^U5tT?TWv3mM~}Ab7zN&t}^ozXPOoE47Gb_n#F6*pGz-!F>{| z$>H)!iD80rT8-vTC@`Na8+#+Ap(MR8Ezv7$^U|OVi%j zWeL-SUEkRuq2%}3$IRm+SXhKZwjR63Bvi*kl-D9O0E{diaK1KRut$!6$c?4+t%g58 zXbda5x*hUJLfX}O_;WnVtTzvQF-2F;qr_<~0x_P?b$C8B_{#fHYSK|=guDW+_h21{ zJL24Stv9tBTCm;`XSr?FW}Vc`g92iuO8(2rSB1SG z)>yQ;0(wi2)iFm%svF3$5TUUP^)Pk`c(^>MWh0oCH25~bzh680>?OuIfv7eF>$b7E z5VxDlVPRy@ysLj|YP_^KXsw#kMVBWOv8n6|%6B_)IdjFON1dDAU>+jW%4a8f%QHRi z-)>si6ZXX_lriuNl|An{6qeK@7!XCOqu$!gh>3furS;Nzj3z+#8i7K*_ z0_eqg97#mNy6V9hovi8$rUh|GXYXvCVS9+Q)bsCTPQ#AEo^7F`Z*(G+69V0d@sBylRLN;I~H3AwH!JT)gOlAs$bRct)}#)_5dgvqzlbuDuO8bilL% zHy28~qp;16JX`Q5?j(~kS7_Uu)0IoPM-rp+$&@L5VXrN-H?H+Z-5zH+=n0r7HhaqN z>^sje3terc=9%>9mVBcoZfoZL5xLTh-9zr}CiQ5iBHn=0iDs^@IZWpaHHtFl1&P zAF5;v1$3;WT@|T(qBt;#C-pFDOpGT5V&m8+b)<8(&a}48CG*=d{IpJA??kOLv+R^V zLG>@B>N9(&<&i>n+)gqLb3=OW5F9ELD@OMm%1Yp3;H(0cVO3y`&v*gBIV<^u4faPU z!aTIaPm)8XTzGKUKAcZ&Ju$QUx1*bS2MeW)&aE?sDZQ@9JVFO2rqGV2FUC7cgaQMe zZim!o_iK7GuA$LTdid&z++2v+GhU1icV&aX`_i_aHK%>9p5POSs;4^VET!XieZXwc6^V%{N>@_L zLT+PNr>AnS!wLw=!KM`$S~cID&LSNdloZ7-liAQN?dy`=1Gy$4rCniEnvLDiwNFNR z0z=+zi)_u3RM$?Qc^eBjyhBw2B94zgPBwXXcSghehZXV&8k&MT(5%VX_&cy{a5xMwdt$ux%#&lTfTlPV zuh0D7tMhJ$U1Nr>0=+W%c%jmt+C7Tr{uJqixf|fh+Io?`YzAM&VBgYenn|74G)d_M&hyPQXXX1=#t-Ldg1BNcbTWw3RKeB%)0-h zO_@D0)LJWLs2E0er4LS|g)lrm5dn4HrA-U?B{CVerr|o>^ z{ovJY1Ih1zFY%h+YQ>LovtJ4t;%TRic2G)(T(5{43&Rtov9sLFZthc;We0(+4cd;5 zo-S!Qnd;fQ^!xgk&ckz3!?y&&78(opjUH`}bzpREx-%7ZnW>PLd6s+mtujRgkQPK` zvCV9ty1O4{-za!3Y$33QFh6+6}I=0YO2)LZ4nE8B- z+~qXJO-5rG=w|cBxzB$?sqRT8dqhRCS+CQ}<(t|Ja;;vj=uxPPabu|SyX;DK?1Se++7m%;rHy$a}f%C z-}mUY#pKsfFs+wf?8jy5Czdlw5pQ-SYB#HToJgr~fi~;m8 zT9&~lkn$C2Mj}L82V@K}M-;h3^o+aW>bk1Kdta(R>F}VY+Yt1o3@G!{;hMgw1160c zJ-L5M-E;HTmmdPGOt{vZ6C^#)J;fZKJw)Xuv(OSJN-QH!!t zvMPs<7~d~Bqk6=s1^rWUCKeP<%t`LIVDIHaE)8wj(((Gh)G=v&`=*Ua8C0E_I3_hI zDRoR@CY{-~wsd)&Keo5RA|nBom%{=h^5uEoB>Ejd*mQhgW+xPmADdm4nV**lTCk4P z;x>-Uo;O5j)Xzgapi^imyO)GdVAkq-peg} z^*#H-3revSC6gADe5;azh5Rz zr==(MH`0>|dJi8vuH)`FyTfMzJrL8kUXp)Gb5`HJeo98t=#m|@(ClxEg#U4b)Y0i2h01W zCZ#0G@>tIv7L8mso6i2HByE19B*N;gK_JON%vbk!AYyZ*#?7RgKOo&RliLnt9=Dfa zKC^d9FHPIqlQ9Rq!6Drfb4w%!#WYZdp=9HFtipztzX@LB3V>HfN@`*E= z9uLb8Hnl&PVLeE{e)>-v8!G-c6B|9SRtK@QgYtxbF|{;|@~jm2L&X%JniyOCPEe1Du_I^?x?NOqT&>J1P!ridcGiUT$H6 z1(rBDA$ef0jsJxuHpBsabIsAk?hq~QubvI#8IL_MLOhFnz_iFSn+NI5%X`}AI}Q|Z zPnV<)9%_DSby97=8g>18#VaK|Q>RKWc^PNl#0CO!55514m{C!}&S+c2-Kl zAiH;ZD6PEmu#TSxO$_Gcj2Qs$-t1#4>R3aaGJ4b$Kcaq_@3Qm)s{>Ef{x2u;Jtyla z$+vd;AA^b)mUN%2|J>cj>Sw$IxY0j1m_KlYlQJ^3d~TqmGCQYi$dK|rt#x@Dya40= z-7ISd`%Ki@RpNyb1Dg9q`)x@W2TUBQnx6qw|K4Fw`@rq34*ZjPJ_h6 zl+vLM{tIaCN$;adVy~oUtqcWTLDP3|MyA&N9W=!ga(j>Jl~|fq7WUpllV-ttXp-nu zJD8n1NH z0-Mu2lnvu-bH_@5w&qO^ypd1lAN+p_jvbrH^o-6-jb@LIR!$e-v2sSAQ15nI&&=!{ z=$)KaK45G`pUkGVwSic5jcyd=49#PLY=W&Bsy3N56-d<*-553~r9Tf(8aH>;!^FUw zcX{%ZbxM>He}0>CpkLwHqXVbiJ%?>v%JLDTMilfeGD8-$t~p{vC{OPT&lfj#)WOsIcrD7QIsa8X{t0fOlpd8Ed=Q^0Ub)fm zCYyrvyoBCLnw{J`C;#D`U`l3RLr=2ozTj94>oY9SD-V3A)PzK*9eys3{;Z+@G%L@{eKY?|7R%bpAoo&$HaS>#(xdGjU5U5d3y%lyg>gx49d9P zqqP5Q$q$S#{cAMlpVj(jgl+YqB5a4K+5Zw)+t&@Hz}Wrg+8sRL)HzEy(6v7_f*lw^ z8+_0RT#qXLCtT~e{vbU_LZ|=#hSjJ0&{!$G|4inh{qL}K-e_du$yxTeam+4OHP!yjFS z8F1;phX4#LrGkf0eE@yq;W}^m4v8?qlYLwXH7`9hCa2Iz(x=(>oT<^834K|A5|(<0@tP75#yaMBaT zTc>3KIss0?qNA<_QGh?S$1 z>e#d#%hWT?fzYZ4TSfT$zqGU{jOMtUTo8WJ0ZMtuhG#ma|3|I#ULWAC7M-2Dcv(q! zLb5*7NN8RhUR51WgHoQ3N;%Y5O0RsGuatf{C?#xj z0HyTG|7WF)3m9UjmG=w47Ki~!g9=5d=n(SmjgI$?WI?XgFEMy1;XxpI+Vtz4{#X-^t4RvabGrQ6=Modu`fhm}Q%pMoxh!)g8o4{&47a zmW0tfmp{zTPF#F|Mjo=+>5e?6cK;rz3M^)ZKpsTmAXpv`9eKc1(CbwE(E#XkMju7#`yFepm!*F63OYaUm^ zB;*il9z*dpkIa6Td6o);z~0JdiuHs0_yo&$g5$CmXQh}4u#weFsp7{CA2PB(JDM4i z*>4EL&P|4YN$_vt*o;xG92l4#gpE`uz&HNpv%M+FdmzCce8XY{DwH>{-`IW-<}sLBn(`|N zyQX`5UFIM++!r^Ffec8|FhG&k2|>reta-=1ZXJ7h}E@vo2C;9a9>qLOCD0o%4=PWegn5<<(dS{Fqx#b?VxFhc>Ajd2s4PauyhufuJj_ef zP-Ye8Woif$zmGy4&OD6eDm9uNfO(A?$yQ-rr~9)PVBVlY-2IqOqbzP8$wR|yJdb&r zQg|El1F3Z0+qVyOqz6%}`5@*8Q~mjCF+T*(c^30Il*E6I`Jqt$J?4i|NrH^|TxyWe z2lIK9B9vo3pUMy>W4@rP-RQ!uHlZC#6YB9Cm&z2{F<(Sk!s(a~Q2m8nm=98tfc-*; zsB|GNXEBu^#N{lZvW4IA{8CC0GQ`1HJ_7P_IY&|n;u0($MWu__FZ5_i6Srge z7|8F${8+f>u9Hw*)>4bEzY@>V!L z#J@)y+_M!N$O8CZ3wQR;Xor`1<-=9YFl-B`CP=+IE`z@&$hAUQ13aW_gR{N2IKuW` z;1PqDf91h7M7{<%qaLW7Zt~24YntHd>2Pi>@bK=@0H1YOkf@eB#%}uRQd<>*4w=xPKPZwFS}|xM!m; z^$IBSS|kgkZHE7~P#drHC&B-6;56Ci>b2WCXkYJ0rGKT@!cB0tM>j$H9PG>pobSn9 z3uk!!8Uv1v@H&UC(iljR1%0#*e*ekIld|jjHoQL9=jruS6Z~bt%b~pXulDt!9pv!z z$YsD(SUb<>Q3LtNc>Kr3|Jp%t!ghgx{O<7qBw=?edRPp@Y{ zZW)}j#&2y;UUCM}Dz6T$AcNNm?U46s+yZ$|cfE6GKUMqIpc@o^I8qOkj z@LJ_SO>v;!-X9rL2jd%;rixk(^40q-xfC^E4bYw(L~kkpC=c`VZP2n=o$VAKao&jb zWQmWhp7qOzR%n4fi1*F^cGZD;J_k6(Eyo)CQR(;HXbsPsl;E1c~~zY@xbCN&+zdc==JskLyPHpp}gWk)r$28E|GJ$WZ3DbWC3n2! z-|7}WrwsbTvji&+B16})u6uhpM8;fv6#la$F8e=^coMZh%{@J+^!w4%uxha09@=jP^nP*}Gt#%FrwzJO?vE0cN8T%or8$-ZYp+8Zh&;V3wHxGub2v94A8% zIu$~X=`gR&fG~0SPZYiI-IJaIcgVmG<6JhFLf661SgWa1VIVvW3iSl_6!kpy z4D~Ga9Q7p(#h0lUs28alLD7GpPNQC0~+uK9rG4r_t$jZ#skSLub-`=`6Y*-Jc#n{YL#xXVU}eLG)mH z2s}s}3M&+I={!20E}#o(hj!^A>JK_V2k8)9OqbB5^lPUJNJ(?avkEO$O8TAqM zF?@(4LPufa>o|HmT}e-%C(@JX$@CO@Dm@MMT;D|9Oi!n0&@<^-^lW+#J(r$G&!-nq ze^P%@pHQFD3+YAlVtNUEI9)|ArK{;0Iz}&}Yw0?=o?cF`pd08$x`}S4SJJDfyXh9X zm2RWksn4j->DBZadM&+-=IFEH&Jg>?@;ejA5d>n@6(&8+|N&9DO`}0==C+kv@q&nLdR+l|GH$L7z^aL7z#VMen4~rq6-Tke)}MPhUV^ zNMA%>OkYA@O7EgCqc5kgpy3s8^wsn=^tJSL^!4-&^o{gQ^v(1w^sV%6`ZoG@`VM*z zeJ6DueHVQ<4Ifjd@1yUhAD|zkAEF5-=g29-=W{7-=p8BKcGLPKcYXTKcPRRKchdVzo5UQzoNgU zzoEaSzoWmWf1rP)f1>x&Khyi@U+7=y-{{}zKj=T{zv#c|4thUBF*L)#TdX(+79TJo zBQY|gFe;-lI%6;qe2{Fa+d8$(CL}oZMf*Hw-Vn)NJ$gxbADPzi+2oq&0;O%JRnM!5?Gm)7D zZ(X0lOl77qhrz4tW-v3ESb!4`}q%;8KGvy`c3YM2AH6SJAw!fb^X z(jUWYV~%BxV~&USS#D=egb2pT%qh&N%xTOH=5*!^=1k@+W+!tta}IMZa~^X(a{+T9 za}jefyq^0~W*2iAb2)Pbb0u>Xb2W1fb1icnb3Jndb0c#Tb2Ds?yp`F_+{WC_+`;T& z?qu#_?q=>`?q%*{?q?o=SLr>(Jj^`8Jjy)AJkC79Jjpx-U$1|Ld6s#Od7gOz-az#d z?ACjQd6jvMd7XKKd6RjId7F8Md6#*Qd7t@!`H=aD`Iz~H`IPyL`JDNJ`I7kx-u3?t z^DXlo^F8we^CR;UvzPgq*~k3C{L1{s{LcKr{K@>q{LOSQ`@x9QEW@%a$MUSeimb%S ztir0S#_FuWnykgzYyz9eCb7NPWHyCOWz*Pnwl|x>_F*&GzHAoTkL}M6V6)kQ>>ze9 zJA}<)hqA-iTsDu*XA9Uu)?roE^cAWJj^1*)i-`Hq4f>>PG3JCB{uE?^h3i`d2N683Pm zie1W9vo&mtUB=e3b!{@mmyPn;^9>E^T zZe)*QH?f=9E$mkIX!aO(8+$B!9D6)_0=u0(kv)k$nLUL)l|7B!!Jf{Z!Jf&U#qMO! zX3t^IWzS>JXD?tcWG`YbW-nncWp}Zcv6r(~uvfBIu~)O#u-CHJvDdRVus5?8EFM?4#^s?Bnbc?33(M?9=Qs z?6d51?DOmk?2GJ6?91#c?5pf+?Cb0s?3?Uc?Az=+?7QrH?ECBo?1$_}?8odU?5FH! z?C0zk?3e6U?APo!?6>T9?Dy;s?2qhE>|XX~b|3o-`z!k!`#bvw`zQMs`#0Oc?&m0u z<`|CUIF9E8PUIv`<`holG*0IX&g3l4<`TF>E{W^KC37iUDwoEkbFdnP>%(PoeYq^I zAJ?B7z-4m-xk21uZU~pd4dsS$xm+HX&lPZmoWr@W_CLS{xe!;(m2jopaBc)Qk{iX1 z=EiVixiDA8m2(j;%2jaVxba*iH-VeTP2whVQ@E+zH105NIyZxx$<5+sb91=4+&peR zw}4y7E#ek)OSr?iDsCxP&DC%*ZW&k0)p7OQa&86Jz%_DBTr;MD8T+WbPF1RPHox z2X{Jm26rZR7Ppf-n>&X)mphL;pSys&kh_Sxn7f3#l-tE!#$C=`!ClE+#a+!^!(Gc= z$6e3ez}?8*#NEu@!rjX4=5FI|=kDP4aCdTdad&g~aQAZearbi%a1U}1aSwBkaF242 zagTFPa8GhiaZhv4aL;njanExva4&K%aW8YPaIbQ&aj$c4aBp&Nac^_)aPM;Oaqn{< za369XaUXM^aG!FYai4Qva9?s?abI)aaNly@ao=-4a6fWCaeKL+xqaL(+^^hk-0$2U z+@IWE+}~UWyswMmX`bO(p5u95;6+~IWnSS`UgLG%;7#7*Z9aidXw zGx=HkY<>8s#zl}eZKaM}1KY`!Q zpU9uYpUj`apUR)c@8D18&*0DG&*FFTXY=Rq=kn+A=kpiv7xEYJ7xS0!m-4&#%lOOr zEBGt-g*W8~7XfoA{ggTlib~-TZC*?ff159{x`LF8*%*9{yhbKK_3G z0scY$A^u_h5&lvBG5&G>3I0j`DgJ5x8U9)RIsSS61^z|;CH`gp75-KJHU4$}4gO93 zE&gr(9sXVZJ^p?E1O7w)BmQIl6aG{FGyZe_3;s*~EB6*z$x1VI!eK^7E26*NH?48asE!4?vP zL?KD&B_su3PnOd2nr#gSSS%nh2g>oVWcoh7%hwu#tLDfOehy3LR6>_#tGwvN@0R9QJ5r5 z7N!VOg=xZJ!gOJVFjJT%%ogSdbA@@rd|`pGP*@}^7M2Ky3su5Wp<1XBV!|?^R;Ux| zh2_Eup+RUAnuKOyrLan95n6>dpxA{f2H^9+%DW9 z>=Eu1?h@`6?h)=4?i2189uOWB9ugiF9uXcD9upoHo)DfCo)VrGo)MlEo)exIUJzas zUJ_mwUJ+guUK3sy-Vojt-V)vx-Vxpv-V@#zJ`g?>J`z3_J`p|@J`+9{z7W0?z7oC` zz7f6^z7xI|eh_{XeiHTyKMVVWUxZ(U--O?VKZHMpzl6Vq4q?AYQLl@%$cU`Si99SZ z6h%ptMMYFaP1Hq0G(}6a#RM@?OcHyE$zqC_DyE6)Vs9}+>?3B1eZ?%XpV(gwboiI0mG~h~J9eiQkJqh(C%yiF?JL#eL#0;;-Uw;_u=g;-BJQ;@@J2 zxL=|qT4E$t;v`;zC8e-;O_mf%l{87049S!%$%b8PiBgi(OG=hfq*N(QN|$=Ww_*B7 znNnXVOX?@}mj+1L(m-jDG*}uUlrAldnG*Ox)O_rueQ>AIrVbXMIhBQ-}CC!%R zNOPrm(tK%wv`|_kEtZx@hf7t`QmI<1kz&#^saC3!>ZRq<3aLSAl$xYwX{EGEYLQx{ zHmO}&Ev=E(O6#Qc(gx`W=}2j#bd%CqFz@*H`tJWrl4FOV0?i{!=f68UhsN?s~g%QbRLUMAPdb#lGDTwWnJ z$c=K7+$^t@SII4MtK25H%d6!z@>+SFyk6cQA0ZzpZz{HOev{I}d8?^h^=Rv3j%m5@@blqjXjaAkxtQW>R;R>mk}m9SE#lq(S>s#GZBl<`WX zGC`TBOj0H*QtUC_gGcDSMTlm3_)D%CE|A%J0e_%Ad+#%HK+dvR|cCT4hvLKDs3xhs)MPb9O;yv>bhWpdq4rTT)xK($+E4AT4p6hz zf$AW2usTG|QHQF-)Lb=B%~uQ5Le)`SwMY%9K{ccnt0iiwI$Ry0j#Njfqt!9$ST(Gc zspV=!jj9#uICZ>QsZLNQs*}{o>J)XVI!!%HovzMMXR5Q*+3Fm1t~yVhuP#s*s*BXc z>Js&EwMt#8R;x8?OkJkdsx?EkMHmHqiliIAVR9C4jYOC6&wyUevHR@V*ow{D# zpdO(fscuw{Qa7oa)h+5)^=S1Nb(?yudYpQ^dV;!LJyAVLJy|_PJyktT-JzbYo}r$p zo~7fwN zH>o$Px2U(OyVcv&+toYNJ?fq6UFzNHJ?g#ced_({1L}k7L+ZooBkH5-W9sAT6Y7)d zQ|i;|GwQSIbL#Wz3+jvNOX|z&E9$H2YwGLj8|s_tTk6~DJLHDZGe`o4b%o{gS8=Ajy6;qrsZmRTE14G6>5&=YDHQ=3u+;)SS!&=wc*+b zZKO6z8?BAe#%f`$Oe@zST2!mh#%bfVN^OERQJbVq)~0AvwQ1U6+H`G(HdC9W&DQ2< zbG3Qed~JcYP+O!e)|P08YgO7(ty-(mV%jpTR;$zMwdL9htwC$lnzUwZrM60I(OR`O ztzBEKt$LUS2JHy#NNuBbl(tFRtZmV@YDa6wXxp@7wd1towG*`M+KJjp+R54} z+Ns)U+79h>?F{Wq?JRAlcD8nocCL1wcD{CjcA<8WcCmJecB!^YyG*-WyF$BCyGpxS zyGFZKyH2}ayFt5AyGgrQyG6TI+pXQE-LBoC?a}Vk?$Yko?$Pem?$hqq9?%}t9?~Ax z9?>4v9@8Gzp3t7up39o%1tj_7YF6g2z>9Vfqs;=p}Zs?|N>9(GrC+bOhFFjdL z(Npy_JzejuXXt(OOuet3rT5eO>jU&`eV{%_AFL12bM&G5Fg;h#)ARKLy-;^_S1-~7 zdQcDP#d?West?yk=p*$}`e=QOK2{IwWqP?D(W82WK29I6SLze=iTWgcvOYzhs!!7o z)2Hh*^qKlBeYQSFpR3Q)=j#jfh590WvA#qeYIU9@CfUwR)XiuP@hE=nZ@+i{7fY>FxSzeT}|WU#G9vH|R&`N9r5(qx4PsW_^pkRX(ofb;(NEP+(|72n>u2a^>SyUY^|SSJ^mFy|^z-!#^b7Ti^o#XN^h@`c?YX`ZfBs`gQvC`VIPx`c3-H`Yrmc`fmL;{dWBheUE;pewTi?evf{y zexH87{(%0V{*eB#{)qml{+Rx_{)GOd{*?Z-{*3;t{+#~2{(}CZ{*wN({)+yp{+j-} z{)Yah{+9l>{*L~x{+|B6{(=6X{*nH%{)zsn{+a%{{)PUf{+0f<{*C^v{+<54{)7Ib z{*%5}|5@Ls|Dyk@|EB-0|Dpe>|E2$}cj)^K%AgI#U=7aT4Z#o%$&d}jPz}w{4Z|=E z%dm|EBhg4QdKt+^ijiuh8RPSw=sjzcIkbHU=7ljKRhbBgYtO3^Q_# zJR{#IFbWOFaE&4(U<8ejQEZeLrN(e$gfY?>WsEk)7-NmFQD&4I5hH3;7~_obMx`;q zm}pEgCL2?Xsm3(pFk`wg!#&v>2^Mo6&BpHr5zxjdjL)V}o&oaip=)ILg>$Y&NzS zTaBZQV~lOavBq)6@x}?pcH>0jB;#b`6ysFmG-HQxx^aearg4_B(>U8W$2iwG&p6+> zz_`%3$hg?J#JJShWn5-lZd_qpX^o{8IK!J7*85c8BZI}7|$Bd8P6Lp z7%v(x87~{J7_SUnAHiwuw=1_B(nQP{m`DTGxXga2A7MTGvXok#Uv&1YlhnpkJk>)6Kv^mBcYlh7- zv)qiBQM1AvXO1^3%?aj2bCNmPoMKKjrR+&r9YO}_Snaj*tv(BtHmzyih2D8y@GMmkn<|?zrY&F}=c5}74#$0QzGuN9N z%p=Sr&5hajC!433r<$jkJIvF~Gt4v1 zv&^05+2%Rsx#oH1`Q`=Yh2}-(#pWgErRFa4GV^lt3iC?yD)Vad8uME7I`ew-2J=Sq zCi7pX$Gq3P&%ED!z$9&g(&wStf!2Hns$o$y+ z#QfC!%>3N^!u-5Q+(H3K|7H9F6V2PGw$(CZNmS*XeVVRa?+3?bzL@Np2tDkJ8SgBT;l@1>v%&_`c znXs8P%j#$Kw+2|*))EaJ$ zfVUZqvPN5D;58g!tIR65B39I@u*O;Atx9WxHPM=6O}3_3Q>|&%Vb*kOhBecgWzDwc zSaYp;)_iM$wa{8*Ew+|ehg((FQmfjkv0~OTtJbQs>aFG03ai0tw3@7DYo)cyYOz|a zHmluQZLP7^TI;O!)&}bc>qu*(b(FQq+H7sHwpvG9$5`8}W3A(?{X5DVxVePT*wC=L*w(ha+weGX-w;r$_v>vh^ zwjQw_wH~t`x1O+`w4Sn_ww|$`wVtz{w_dPbv|h4awqCJbwO+Gcx8AVcwBEAbw%)Pc zwcfMdw?42wv_7&vwmz{wwLY^xx4y8xw7#;ww!X2xwZ5~yw|=mGw0^SoT0dL+tY55O zt>3KQtv{?kt-q|ltqyCyP1*34a+|d|o3{m9v?W`%6dxAaDo@7t9r`S{N zY4&0EbbE$9)1GC|w&&P$?RoZmdx5>sUSuz}m)M8fRrXT5+ODx<_A}GqVy~=K}TkSTx-Ck|4vDez`?Dh5r`w06;d!v1ny~*BeZ?U)9N888P+w5cQ z?;zI}mxp?#5kv3-es zslCg-%)Z>d!oJeJ%D&pZ#=h3R&c5Eh!M@SH$-ddX#lF?vZQo|!Zr@?=vG3%j%$hWb zDW5L3H`Nywh6^!`$jz%`Ev?nfEiqD3=3-ieX%N#=G2B>H-O}77R*_T)FKvmfjtNzM zB8Ho5o10=Q#43`i<<<2q)$NVT8e(hJ>aM&}UenxGRb3rxYE!B^vqGf03T`dbkR$?p zs@lXTGK?X^C}9}$6D8VtwG!*hicu6JMp7Y4?ilkEbzGMqYHe3u8P|COrM5HcSKM() zgE(%HI=<@)wXQ4AjbB>T!qvf#P}x@BP!kjC{Y0!p`Rh^sN+N$fX|PI^w4S6)Jdvd+glVz1qP8U#Yig)!s;RFQCRJ6px5WflMhpp_Qif@{Fo`rlgP(Ad zpnhBf{0LLXRZZQl3XtA*0wG}vxvGgYTvOG`=GL~B=9P6ZHriCn#+quysaU;ctlm^o zy=Fhrr`EMM)mF8%H#StYx9QE@DPcO{+|rG65UUm}7N!%sBKP1R>4i)yK~zwUguVOZ`ILzn)tPr}MR5<@lOdLtB-I_u|&W0oFU% z=2y+T8Nb4>T7zFTB4k-P)6~watrwd~{n!?$T&rKXHmDpjW>-SRs^Jgh;G4Y`*S!11 z^^Sz7FzrkgtP$9psA!BH$oj2l+Y?pa}UFA^#%eUxfUNkbe>KFGBuB$iE2r2ataN`3I1H0Qm=yKf*>Jfb|a` z{{Zq2ApZdJ4

    nyxN(nsPjIjD9^0@b4iiU<C&f?2b9M7#c;3Cr&m5tgvv@_kS!**$t#zn%srBp_l1Z7?*6+k?ZV{-*y%G zug6uJe`q%JedGT~J+kT})jPEc1;S6L^mQ`PC}Om#zb z<8_bgX6oh#lk1l1R_nH;6m5^xQR=EsGcHQKr2f(nX{3}cO_DOCTxp@SOe&Jfr5dS0 z+AkfEmCCB56VfLgL(=Ec7t+_#^?IV7R_|2rUhh*MSRaPswLZE&en45Dg0!Ah&#y18 zuc(*QE94w+1*Mtwz!qH{3$_7+mvuhqA-DQ#7L+<;wTA75{WH!r#5clNa@)&u7JXOvfESC%9 zB`|A9amX^gx_9!zeeHzqYQ8o7;y zjb)9ZMtP&A(a_jGQqnlmIMMi|@p|qF7O(kSLT2t-^>rhkA{Ay4#C4@4KEwqpX-zJVmn@nwxe#qnI1nQoK~GC^k__ zlTDKYnwxe@?fQ3jj@vD@J3H+@smZ0uvmNHdCcmcOriiB4JBv+;s18(qx6JMx`LQXj ziPI!(Ds8IjSD~2JbK1>KvL-pT-FsD4TrrHoT1E18BFB~MwTELVz^3T4}8lzReYk8(gcs(hrJR?aFHmCMSF zW^%Lr?X70#W{+myk@*opb5L`5bIiz6b3$`!GrL(ZQaMuDTrwgZQ8icInQaYemNu)J zbt9?GrskpM@sX|O$EuL#ndbTCrD4zJ)jpr*Efq!OsB%?#sr*$Ts>nObBjYOiosE%I zRg#LK;;IT&Wh#+MuF|Lsu;`7bCR9&U&mZ)tUZ`HH)?0`cT8mSQdy7v?V5fW62AX+V z!djwR;#*Q$SS|dP;+BdQNsF>Y+hS}PY#D2rYR@$*I#!*iPE&K#LUpOSN-a~X)q1sAJ*<8RGNpc|UQoYMuc^0hQE%-ZYAGh-s0UVx>bHld`oew?N-mNfnoEl(OZw&;%`mgn!UAnYgt3SwV@${ z*lV2IZ8RPlUrmrEToa>7(4=bE8iA%nQ>l?^R2rSeq#4qTYaVN6H1nDz&8lXrmD1|i z>e}jcPtY~n>fajDF6{ShuQJRS=366M>8(j%Wwdfz3tP)tMXmByO<#1Yp|!ttq;;b8 zN$d007p<>b*V~9TTANdwdz(*NU|U#QbX$B|O3!8+tBns*+*Z*hX;Zdo+l+04ZDVbd zZBN_g+FrJ;v~9NAv^%uBw0pMuwFkFHw8yq5wx_jo+J(D{q7SY7Z|iR4zj<#jZLh++ z0El!H?QbeD1Xlmgyb!l`_05$ZVYHGU-Cg~6@4L*{y>}8_vq*PYwtIhbAFzve_XE54 zT}FQ4K45UZ1G>AmwLfg1LW(%GyE{PlJ_7a@3uZIy>|V96wQp;w+WlHLLxR?Ouv{CU z4b?_zY3;0bQM;_&=pc94cQ|)=boh1z zb%b}sbR=}7cCb4H9VH!=9nua}hpxlaG1M{M@wj8AW4>dlW3^*TN6|UzTye$u25H|6Y1nSjn1I!*Nx~VbWe28buVvZaL z2l43)yfe@l)*0Oy-g0D8cUE*7J0+dUJ4KyZK!crQdf{ME=Va&8&biK)ohzN2 zdK{sba2WWSu2N(5KgNy&2=w*Xqy;`r=oAtx` zhx#e~v(LQx?ez=#SNb*mb{Dm4f0tXAcUM4HXjfEMTvu`zvy0bN)K%Uk?oxEMb@hM@ z+>;vSk#voACv`pQn!ddXd+Nom<*p6bS(6R+24{oEkn51E!PgLE2sgyQP8{#O4XFmU zL0~8`R2obMsX=AX!F|Xu-pw#PMw~M&p?$ew%edH0>2~aP?e^;S?+)pX?51}obu(ah zU3h1 z=r^Uu$@)`|dyo4Nym0jRd@g}KVLj19(48SePdsSK{rESfhtP}N zd#XpO%_dF1s(KL6c=e;|sp_ZI&#ULF7fl9JfAy>CmFjiVh-t#~#PrM+8 zk(0>P^xCv8@(_88{62H-Bl>84PJQluK7E0GVSUkk@uI-Kls;A;zpuEjqEFJN?9=uc z`v&22?vTE*zRA9)eRF*;L00-U%{FESvy0i&>}L)(N1(SkbF4YhoMz^jh2~Oom04z1 zoAqY1dD#5WJY{}nUNFBhubH>+Q19%&<95gUPQabeJ5hJy?j+w~-YL4n11-NJzN5GU zyM#MEcLwf^-g$&(OL+ecy0ds^`OXI7Dk!<%zTesUR*6>!^d=V5pU|HQ!Uhram-JWm zOYz&R4yK`@{&A4UAT#~*{Y(9;{agK8pTbw0KXrunEU!=fKMeti1fhSL^eN+0?x%&H zmVGMvR1Ts6F?`zp>By%OpFRP34)WsD*PpJ#+ZlQYOGurjcD*XFJRhzp44UBA1*cO&k`-c1Ba1L52i z-Yvabbys#*4Wb7z-yOdD@b1*zXLlDsUV*IL-5#V4?jLj;^d1Zt3>}Oci~>y_WDXV$ z@&?P{T0STqR1CHa_JE)!j1E2;oF1G-v2~CARWi8z6|yn-1%Y?VcZvPIcZ&etD*p@F z{aj%8KIA{-4{xCVwK(5k(2J0v$RYZDr=g@F#t`?u&rsq0z@f7H z(J*_;hcqx-_TP^m8o8e`G%@sK==put(2JqhL+kg6omtm9$Hm|0!_4jjvoY<Fh$h+_MX4pGC_(c!@pW{#MedGPX`(yVf??1gi zcmL)6mHV5+Hp33XE_k=>Hyk`1F&sObIGi@j85V++4p$A!hSkIRVe|0t@WbJ$;b+4O z!>@+dhPNM3AMAhN_Q3l=z=O~SQ4iuCB!e&?@E#OBD1RUZQ9NjS(DPv6!6?Y12h$H` zA1pptey}k@9uXhp@l4I9Y7o407fA!6~Yr6~1=!8Eh{$bbSu4!!Z+({)!X2)^CFlREf0>c!=85;V;co(TDRHWWAPn$rcu0k^1~W$J8D*a%_-?rMX$I@lP%3=C zey0VT&k<`E8OnE2SJLMQzLCCDA`T-|ODsmH&C#FRB0op){depi!r+c=aOn!zMF#k0 z{Z6ZbF+%mZd~UNr$g&MKs}B&O;8eJF!4s`z^V7RCp3GiIF2}IpmA!M&}Rv0g5tgSyS~|!|D#w7~rg7 zR6?&Zpjs?|JPp8%?Iu8C!(%`zfT|48e6*17y^|h!67|iw3(n)UYy;X4bAZ)D4qb2#F!mL#t7ivMfaTT_?#Kvj7R5s7o0@AZ6-51S36N#kPp_nn2-;i(YexB|6dp+u#=5b|jNmFu~HSb$3PLR6L{>)7Ebir7xRwZ2ZSJ`s=&N!H0mj39lR9M;Ly zyMgT{pftTN*ggi7qKCeb_5w=kgucP4&0(DhoohQK;yR&kByX_Ab}j(=08n%%^o{f_ zK#`r$H)4q92#t|_X9}QJ z^5ae_>N$!HC=qQfp?%cpj%}w1Lbrku%;37$kUC9v(Ji4=OA?u{TSR3M(sBWjNZ%oR zVKzbYC5gC#uMrlQ9Z2I)H~a{wlpxGg82u^Ki056Rg&=NwVp}!XaGivSRIXdly@Y2E zlS<)pp(QB$Jt(Wh`N9CnF+w&phrLINvUr({x4~a9cY5`_G$Pw~End0-9mEkyZaDa`wB4vpZ4LJ;kk!kezZRK zkntf--3zsdueCUA5CP-Z z=e&zLA`ya7i0laOOoaA9te9Xe1oT@#n;5}3n$|J;5!8ZxPs+0}M^qh%x!_~dJWl;{ zNVUNTwEzI5LO$(Q2N}==L5%RQ4Ms-0hS6U`*&d9*Cnh~cR{?1;%7+pW7=f>}R-ax5 z1T{f@&<9f)MiAK}?ihJNstF^$C2GVG?Gj0cA=Mt)$hLr}ICTq<4Ms^&OE^Z~1!Nub zD5wRulnniNu!K`1Ak`D2KY`RljDTAvCyWjPa>OXWQm756903s1b1Oa=R_BC7-*!De3;qZEU8swva4W0<~%>weq=x3yl9u(qy zQQN=jNo)^;d>?H8sw=iV5D+k>-5;mI$h70KBfm++1;e1CSRfBD>0jV&` z1Ejzx0ub;J>Vx(fB^Vt5Wc9eW#n)Kbri7mV#u9EUZ<9mK;92l8dd5|Yqp`RLb}4Ay zHCnxa+9$xNWI#Mz9~1I%x}@+7FF>p=*ny#5w#DFl(91T6TChbzD!nZNp0*AsrVaV@ zx+SVDL^lB_)^emRs7(O~V$v9ZOMusmei$K}4@N;y)~lNb`H){ckd64o?g)~iEfnMa zHZ-5^wd^%I=vaUzEKx?9jsZw&Ibx)=qIDToh}NgA&vDPaT4!1pz;?nC)w`@i>-?Ws zqI+L;YyjFz5UqGTNaqNmcMi7z;-~jHMkP>UMn{2sKeim{oo<6w5ye3-^d8v&;gKeP zV4?I*w5q{2VAi1%)(RvXlks(A!uuR+bpnumZ=p>K(rF+eWRw|EV- zkHmp|bnP-AZ^##eQ~8iDN(23X7VPbf(6j+U{tMHh`i?=q5Di2k={(qibf~32fR+Ym zN&)>X*!;BC5=VM{G_ZR^bN0P3+$!k9;37uA3Jq`sJhTP~SOxiDM%Tn)1S^Cl79)s9 zjdf-q0gA*n@PP)R8_K3x95taj)FYUm2j_7ra93lE#66a%9+P%I}ZU(Kh;~q6fK=;fnE~-|zAZo;jQ$o73nQqZhk+49 zT~8`TY(U8v#Q;jg=-YteF=9bW>9=Cx8Q%gFb1NE9lqJ41LRSvx153O%SXTt-yMO|9 zh?jnr_;yZP%8t$bmMi$c2)2|qC<}Y8c>N?4Q2eA!i(Qd29QCqD1fC%X>#HoRRtR9D-)uGr1 zdntAB=Vh%vg>man#5Pom)u;Xzk3PEE30hzWB^+@o%p2Vy7Bwt(Bjzb)>#O){{i`2aK0%>ox{ioHX6@incG*AN8+7^{=0a79E4U0In8&Vf^$bVNF~WR%h!zmh>T@No>0dwM?iXUWj{u#&sqr;Q^_mIQ1Su^eYj9S4XvNX$%^S_CY>XJBkf=uz{DL=6?qy!>KT$1_`$P4)Td~;gE_@B~C@H zD*rrRDbDvBu;GzL`y4|dPW6To0_`T0?E#yWTLOYmS$R&jSPW?@F{GlFrl1n<{SH!b zeec1@sBnE`swEQs=ZFM+>S=LQ2|5O#&G4?F;&lLj$!n0xQNg_So&(sp9SX3O17deT z&7=oVvvn-npuS|>D)4>RMhEh^$l|4~Y#RjxZ#y0IHdHh8yldg}wt(lLX4DoRjLrgr z9FXtlkZ%m5V^H6S_BGgCE!8S}75Eh1HBPA>S} zmVoxs=5avK@@8vnzeqF4iuceypQ0U__YG^17M1Iur_oD|N;2K71O`Vg|m z2)G8HdZ5;$5;o0d58?gD>TzJGe!Lyxh0sDitB3v)&@is$4xmAd(9`n}uVsUI*Y=USac@RVsjwa-xzG&Qn8jGbbvgtYGgLM!-O+)qlJJjdg z2Ju4LXX(}NZyE<1a9{7x7P5nAO~4ca=9VT{GjWOcJGbP1Py)sSJ}(0s+QY%8JSY`B z*}2j>1-88wkIvVft6+nu>s-e9VDvj*wVJ_p59(v#62L9^ln2U^M=iZgNlg$<vqU-rXd6-?5zt={^@^<~GN5`(kOI89gEld$ zA(j+d3RD)MRRu%|pvUkX8Z;Aj5wgwzoSI1b$od%tp&@q#eghO-E(#UP8xI!pBF$c;&m3bEE%45=T0Z2;RQ0X@fP7?2*LRzO;e+5u_Wf}!RV!qB0Tw*fLk&G>1g06QAAi9=NOq$_g<8+yBkexd&8rUHSis7{#t=&!Yb-U!s-cEZ zwZ<4?tu@5Q`rL_!^6jWvul{L<8>)>>+fHN;xuSjTZ3W2|GX zHP%>bsiW}wtaWbkN1e}n*IxU**V%iY!_DigO{~X_=GQZ1pJVvYQdN83eD3wc)@W)q z6D?k~-H=o1cX+JqJZb0r`U=&4g0@U4X1M2#Yf3f4J+IGKdVjdfJ`osipy|9fKjzj- z$C8NT*m`-ZoE*M3JoNfR@sQ`jR_#-sLU(_t^Tql%v=f?N4|g|%N*|)xD}edjW3R1; zhv&7A+uBF{HV%jMT-ZuPGU(GDyHDwZo-^wEW7Fz6wN>Icz0niM89LrAaW~I=!oK@5 zVvOdV{w-r97wFIyb_&M(#*QByly@`+(PFnV}++ z#AhvSW#bCShqj_|iR5BV*rTgfTfS(sM8YHHV?Fa*OdZJUU7Ar!fdJ~f{k z&gQR4!&S>_nbtA`D&$FWPji_tJf>rj(#qlG+pKn4ZcZ6q-agb$>OwB!N%^P0c+^sE|ODku$PscY8YhA!P zrny{+=Vi>Xaxa}+K3itYg<+~PgX6jC#rdp zY7s5k&!mg&nch4at)HBG+o+5ApX73>EfFf?lp5c*8k#e_{Eg7IWvZq8TXfT9)jV&E zYLYQ38;*BTG})uDWO#Ygp|-Kqpq!j{w~fSO$#7cJ-lqMk<+ijm z^`dc?(X>Z%G4bebl0LXKyu2;A^(@x$oVypcooug)$(`GXew1Lo482cLn_+N!CDaDlF=xl{nAh%Zy?}NM&F=Acp_`hHJGaIYN{njbaixC_k9h5D zqnz`03_twZ>BfF`!(nJA8~e}>pba$cgNlY1y>_gT)o4ZxzxdjbMw#Q;XonlSpap0L z8#^FBr5(_m`-kVh_I6_(8nu6IziRV`AH42rls?Tx>rrh6)UD(nzWZ8dBWu+P9iH%7 zyJ(IyYO1l$5d_(>I2u~29?Wr`3epFDNTYy7zcLZ?sy+8)nb$>I0;Eez@p0qftEOa%XfuU^RMjge-FDx~Upx zgUuI}YN7K=l(hM*5OH$K=F^Q=$t4Tzq*{Lm4XCwcc=_gIP4u|YM7krJk3(CBmuxdU;^d{D@oL0z;~=GUMMwX$dJN>%!pbe)=x`PgOm3w_n4 zJ#I43y6hgGOgf)>uxh&&eoj&9%PO<)+>BEYJwmy2hR1fzQhE=KTA=;ZaCA*qV(-&M zzoIo8W>=UJt73DAQY17^NX~hi$213%j{Ats!Oc7`<*czod)(mPh9UKsGCX$2P21!1 zoc|N+Rkf1q4()L{8|*m!Sn*9*{vg4R~u!q~JWk|0z>``s{@R){O zJPGv|u0S#DU=&^L)vLeUq^xROxjz zdpt%$_IQjOp0Z;^BN1KBM>`m8C>~;^LEJbr1lxp%ZGDnw%6`?L&dZraYizBv43z0Ps-MYMj^SQVW+KO^3?NVxnr+oh9`xq#HH-WaAC-F#bl)6*iHx_PD&E>|Ck&~|nHVr@7 zsd0n2me@J3UV2ijbJZFN*}VpJ_p3&q+V^$R-pXPwbc5dIL8tY)Yj)yVJq{Vg8FJb)OC1RBb zx4lNw`FIArQ#TK5B3hMd{iI_&(dwXSO1$6aS9YcorBz&*a{22EYVZfcs6C|GMbe!Wk~df#+T-l`r*)jH z-AyjPh6ZYxi5C4{+o2xcV$Xl5jfiel3>S91TPx9G`tV};n-3{>cyUK>Z4JbodB-00 zh#cO~)mU4C<|mgz)fPg`Rm$bQq&7=6sk6onGa4;kwF=0o6vVC76(#mpwM&)eLONQq z)305m8l%!NPwAW73Xy_xXQRzhl3L9WlJ6O6wNLSltkpg>{sZfHu^NXBt7EJZvAx3{ zkFeoCb&RUHO@9Anm>nZ(ZbFxaKkl$+fWVtV*G@f-qX@}(rvpNAamR8nv(oYG-d zzrz@9G*{m*lV`11`|1`!D~EfksRgu&JC7yRdjsiq*U|?@_3)DFJ=Hx*%d5MqchPHK zpIB`bwkatg$nLo=bpLei(z3soCME(cYkpV|&6-6y~4)wIL>0qH0Q zs)wd2F_){!6YT_Kk2F15Jzg{`9|~40ZL1!sbP5VmD>;x<(lH8EI+kV(WJj}j=%!lf ztE%ft4(O5+ZK%4S^fGi#NFsaH8Kp#sa%fvGM9r|?fQ~EOg$@f@Z$a8#>ourPHRfa0 zK23KI+N<a0S^|4JRufwDUtz}A= z(W;adQHG9(d{>MkkSK)HdDV;Zu6)aM1O9*sKmcpwRf%U&?)t(gpMf6>9v#<>@vgV!Y$Z<(c{AT~TGQQvP72AFVioiQ zL~C05l^FS!LqZb6+U$1x6K%g*7eKvABe}N-(RAccaX__jJn+Yt`PfpYS|pmz9O?0v zQnfOlTYPGj{Fq1d=`JWo>CaGxkYhZ=tRTM|v?HftHS{ZJb;UC1O{2Lbra~eiH=ixb zE7(C9|DY~&)#D$-*%h-YB4``+sFwLqH!Dl zM1_um@e4Fd(;YXTXdY7QZy|fe{?_=*rol}^c>LOE-gM8$b6ReRn=cniUBu&}`u+?$ zuk;(}tmcx3$4TG2q~o5o`M6pst@)^u)Ysl>Ckxn1cGSiMST@u>05#diR{ZE;RPP8Rz{SR^(Rdg7S z8fe5O&Zfp*toF!sLH5Y_%qRSJ)T04yiqbIJRi$h+<_EriMLVao*9>hQ>E~|P`YyM> zL7PG;_xa&5{$rcQLH{y5>_6f^4zU{j+RrAd*55C_@;^~TwgML568{X!3{bkVb@FPw83isQkaR(taEvK|(A&c)u z{BD0a+FRt@@_A{E{tUF=58rL7YrYTt7;BYUU%+FwpEHEK^=fi~{G@o>Q*=|kZoAy5v%S_|X)&$ZYvj&=XY93|Qz{WwP zr_t=%)mtIWjcc!v?jb9rbMe~qw{-D1( zN2&1#2U_Gl=@W8ZrXJ5Y`Z~^TtwIwz(Y!*bvE#^AA7%79`Z|wnO%2ey&9jvnJNIv0 zO}aA2*18kTGP<>nzNV8~nTJY8o9-!XZ92%fiPqTE$J!zqSOZPhwA>tW&e_WBGli0y zXc5%d>1;X+(eiS8l}B0+%607dJBXnjlWV1n3D!qD#y7nq~F{zw2J6 zH_~N}zV4k(((*D#TX%cYbZC+cK8hjHYSOHi%y+RqEI_ zY76t4*>`1oPy0>P+S>1K=~32aGKW@ml*^4Y+8bTIZQ{}E=;+AU zlBe30uEh34)!I5%ZkbBXv&eaz)}Ye*cuR=(bG@T)%keET*B-V)Dh}pJT^gCOA(Twc zj*B(78flx+Xbm*#>Y=p3GCPtm3N=%7CFaM?ZPVB z_-)+*ZGQWHw8zmV%8j(7+tF7g^G~!9a;vObcY6)mct>BurEPAsE^Dy8LHoJOYHL5! zD5IL=*t%^dx4%NGwoPrE49&6L*gUdL%FSVxjOF%Mv?~pF+JaR3WBX8}&>Y7z4VT)9 zWu)tCzrI;k=!cHJwsZ0>(yX_J_%$g>_ZT%8khgx!@uB+pZMV?ENOwcuHvYvLYP(i> zNVPV650LIJ*2isU+H9?_?daycXn(LCY~HOsv=Hi1n(sKge(7fVh4p)Q{St0)`6|uP zw=r*XJJe?lZJJTZjF4Eee&%NB4c6uQ@XBT6*J}-QUea8qSOabLQ>&M_abj~a=^k@5 zHjHnQsPY9XWb?|LxACZfR^(6@nK`95a{8c&Xp3^Bv=+3BIWjwItUv5ny?L%$|FENA zb2#*jqh|B8%`>1>YoJtj0_N8oeVZq5mU+4aO?LvU!2$d3m)A)HrP@lP8Q)Qx$B=V9 z)?lskZLD=l|A6dgOCsb~ErK4u-XQ(_f}^J4M#F6=+Zw0~QR{5d#Vake1{!onV?G0& zRjm-x9j0n0RXb`8)Y>cgD_HwgtAXrxlu^dJjg6G?YjPg-SuUj`ls2GQO1b2+OX+!h z8IdyB`XJd*1A%Ess1Xo!3wJxsJ{$- z6OUtA%b}+z!^oNk@vNwMH!Bi~#U*umKqrU%{rf3Pwk0AAtfs^YoH42 z!G^emq3KRG-ZZ zfkrvvN=DVwHsieYPRWRRi8Mr?W+xX68hx63H>RrA*u1z-RzSUVzPY18N+TlGMATiu zmxxrge`6H%zU66KUgg*N4YiMGjwanPM_+43owWQTYp7-CMyWw9>*yV=A9bng%jiX8 zPS)*HZ4TPrj1DxOoOQeF#JV2ZgPrdRt)aTTb<%6Ipx(MZ=!7*;Y|qZkR!DJl#uBs@ zXp1$!D66V?VOC857kS;WRkaVp5 z;)$Bye6;cDwA?B{8>{&}iZ(i3X8TmftHq=0$l3V2)mc2EZU$N_>Fo8p!TN`9sBSVE zE%)6^m)Rac4Kx?iK@CQy%WP-I=(}7u3bL#r-$gBh*yPhlV@<*LY|DCR&%$ zY4&%S7H8R<&V?6D*Y_!fG-X!N~L$5JALZ=N@X z@tA;S$Dy~;W_jn6ju`8kp*b%=o9+!qBTo9JYPtMPt}o2XS}^##XLE?E|#8RVzi?pEeHdc}Gq4&FVYQWa~=x zt(uWgl%sL$=o*x1^5uRc(-7&6h`u9?XwTu0kqeHU%LV^wu;^?B%7>y7F?wWX>x zR_`Kj(au-zBRvAn;!&(@0fSMPzOjFRed$~cQ}X>}{w zvy{7r9Q(U^6G_8k8*z6(>T(Eb(8p5w%;!g(oq zXzV-+?K%D%XqJw`5o@r}p5yPKO;>Fj9#d1I@L;D<7^d2n&_YwDqjBaewCDJKwDBq9 z(e9&-)pQ@AjZU%9%FygN&gv-~k$e*^70sUGORSK!L&-8mU$X|*-c#RX$e!c>iuHE# zA*@l3^GyTX4a**LPQ$e-i3d@R51S6C#{@@sgMBuL3JPx8RV6(>!I9R`U*(o`K_N{| zRW8-mHteffp}u`hrB%yBvxXWvtL%CDX;W%dkfvMOP{mEE_k=&x@sKsICY*^B|Y?vV{7f)%6CPx zK5Cd+C+p}L$A_G64NVu`VE5lMLBX}7E9I&CxFfB8s8YuFnV^uGd)%aowzmFyWrJuu zL$7j^D)|l7pRJq74C{5Aue(s$4Q+DFX*|Ont<3TB<@YPwp{E^lnop~5t>eS;Yg+Ep zj&QzvlN!_p1(%Ia#%k^8U(6s;zDAs2nSrqpy5lpOSZY=0 z=qre>9ARq(i;HtqJ6|wYeP=u76wFfJI>*+6unKw3%(gx%2(6tW>8yc*(OLtZ8U>>g zr6+S}$HWR5^Er+=8}3(}g=!pq75gg=Lf^NBDte1Y*;@X^3R$6O`R9EyS~ZUI`2!Ww zYu|Uw$v;-nrP|i~0~OM1-?u)>f4gR%Xx2dfE-m-_R!IKN#6+~m9OpOmRCr~rI_8v( zuZUM|>xRY(r>@_R%B&h$N9>XE3)GhX zvD#~)&oN@tsZG*rk7Er|>wnNn!&62(8c3%(%NZ>1wp!;xH`r&a;7Neh)3OCZe5C>yNCEyyNcs)L<3bQPpN!5Atv1 z^`kwDW}jWY481E>*{SBeK(pHP>5o5HdF)N0GyTYm}bWIT3jemsfudX(4` z=5;GY(>8!~kD)aw{R=raxGT^?(P~8Fgd37q;g)&I=`&Dgp+dF(6KkG(Iq8J5+_Opd zICb&*W#&k_WKH*XtZp}}n-f7>o=fgC`Mr;jyw&b;XnX0u7=I%gX9ItkUus~XE!G=L zsk4r>fOq#5O-;HeU+E7vZhPV`BNdz z=bQIeo`kqlsOqRZ3~|F!T2d)1FUN7Ws={xH=2%pk?C%jRXhK!a#yhH|l`gO7R_)0u z=SIpPU4CigMkzzmE#7!BkZ#(>^H7xIZrx2kEhok8S|msp^5?e^fqObMqjY2j zH)@Y-X%!o#_EK6%K?(E+YapjeYxOeZSK_W}ZO*1+Sn0{C$pv;R`)coO3`JvPs_e+m zlce_2#xbg0sT|rE0ukjm85^a?iSm`VG(YYR{Wr>`#~-(@R9+~*Wshpb<#PH|Mzu!Q zrQFR`oGd?~+LfAP<;U@0q)Tp=?|~TUdV5`RGgflGTzZY0vHHGp8C7;Io2HbPNOqRu!&t=@)LTN}|f8y^nAYyi}}m zDlcDBz6_1KNWXg%vsmsTH)WL17tI>Tws(hp)?l`Jn9I?YXwK8o7M0U$vVODYyJSX0 zIofJ^H;sZOSRYp$-!uZMb=)l(x#2$av|~}-#SMeDR(xlJ^qOb`8|XFCwH06TGv>7X z#V0nL({wM??b>h#dd#t^xNgHK%4M%tG~}lYgEhF}$Oh@tA}b{8peqdR zh}D*Lpn4wKRckQoZLRZFtb1Lux0qxN)+KLXeaPMBhEDAbqFz=@EM-WGvKnJAK$on6 zEc=$^JX%$(l)+s~mS6Lm36&{vXSBhdiH}=@o6c;Y$K{49%Z^Q)^0VCfm60FKr5>!5 ztktnHZbV04UV_@jG8xp|Q+ZW@1Rz#8?@bC!q1pn`oSrvc@{u0Vs`j-oQG?dQf ziZ$0DMnAKB%|)y{tujm396{sRlj&RYZh#8bFx$C>9n9RhzANC7yk;LBwbmbsCaxL> zJz+h_T)Dmi;#`}#Voek2mf#oT)HL?jj_yJvfiaRKge9Pel^dJ zL)PH>80lxLigqlopogq)TMyRTt8p7vdo|`zmk=F~VQV0B+5BZDxCftsN3?C-YbxpQ)_t&q6?_AP{z3eYQW0# zlwK}ijEp^4Cl>I0GgerGrRPh}2pN&3r!?ml$3vwjN>8J`f$y$@8BmP%r@X0Zr40Yw zf{AGVZh1CD6)=M4NGl}6znXqAlek0fUM;hoxsg$@Iuc?8GjdkTSaK7ck+E7@$?aQ4 z>gt&RN?c9fOI*u{Up)!p{8s8>VaiS`BxCt%nGqM!maV#hhk>?m)nzp9+%lq8okPol z=B+vj%^_X*s-qCU5SJ0YYCk09PFux{khz;NW!0VlOG*A__N$R}r>?$uBEn0Va6|-GxkbZ8}LWtU@pIH^5T2uO| zbqDca-lv~f#cVf|q2sHhCz-qHM^}YG?1$3(SB-#(f9rJjWjr9~hE+jmr>x(l?_F1e z?-SMs>AQ72&Okj%H=%B&pF*9VQ@he9)`#gW>lh>BQ>=}uGq56!LG0Hkq}mHa{eMAf8L_S5faNO$YT&#ct+#U-ck z{h5`P9+`WBGA2L~xr`CNWca6a-LDz%qD^0Cq5S}wx=#Aw-=MIPdyv!eq=)7*M#g?T zv^4IE)6!?>mZ80GrRD9+Er8yG_T(}~tdBJBU~asvdGD0G106@Zl^YHDtX}VpO-<1I zR$25_;dboHsV-D)feNIXx@q0y$r{p7QROT+HPTNAcBSnb}{n?t6PwV-6Kx ze02=kY{$rq)5YhZzgUCCXSG~nySF^%Hu+VM?s&{utjuh0UJUWixNkiunXKtHSpW3u z=}B7|pOcJL`oNjvgnkUI%#j)K9xYl?TnF`_Eh}bK7I&f>0DnsISCVE*iT6T~Vs(K0@BKZrEMSJdk(W8+WI*Lg|jSvVFxJ z(3g2PyVpm#W;(u6(l*h2^OT-(wD=avw=wKgFRq&QPqyL9Y+^t8 z>*9$;cT{UEx?gllwS&bYie#R$$1J+0qtF{Pp?F`>6|9>aY3p|vUBb$Fq15XOQSD;M z67Egq{q(Bh5-FE-)!yYrj5O~i+SZ-qZrj1TiH}RHq5}}$2BcMKPtHM`>nla84SF)W ztY|0nv?ITKh2)GDl>mlQ>bMsL`o^*A0&iaKnM(u+lhuyTJ;G+W1#ciTnNi=aCB9CKg_YKI8_{-uc#ZcRgZx2HF(T?JqnAJ!E~%f3;jj zYl@?>u&b~~weyADg}b1~Xop{{>_$FLzgyUa#+&rQU4_zXyh$(IStv6ij53;ZhVg7H zY*m`NxPTHm_LlQM{~J`*1hZsS|-%FOh%PhlBCal zxkFBB(Oi-seeSc*8Az&AZ5tj{%jkQv4b89G4z#jm?P$l)N>qCnt#Fz2?h0<0-Ky~> zX{~G7GPHk^&ORTB@9Jgrq{Rp(#b~+%Xv>$)B3%*MQq_37l(b~oOf>HBk`}49fZm<2 zL~kTTD)mDVN>Y1!9nH4}ympW0qD@un3@9w%dnPHg-~=@YHUF5TG11}ShV-yl9o)W^ z&ewD?XnjiD&==VK+yw0v&EgiZK=)TN`dbX`(%rtnLE4C;tdlsr3oS_84z{ z;Enn&GmO3H^NC#r1rYayiFPjBzIjKAhh?H^E^@Brb^}euEwNOI*j}(uNNyVo>?Z{8 zo(eSPShJwHYTe2m@~nag(ltBYD)tt{EAmaYYtVDHKw=JG6L?N9 zT|$2BV?8IAMnNBQYkGI-Y^)Q}`j@h{=+h9-p`}t9w|Sm-wX|v6ZJyDbe`r1M^nOlz z)XMJ0v+L!XEwyu1hNQYho)ZisWdC;nyPknvaRagTE?bDZcHlE32Ra;(#> zuX>i|%e?;xE&AmQh;ywc>SZ?+ZvD4sUcN+-P1Xd@+$ujA2Xg}84~oCGJD7hPTE|`Pfug-aXm4}#&9C5EpXBW?N>=(?UT;2aGv+%U&D)cI zkX-)Tip<*;JqxYa`c>XedH%9ri*!dvheD;?>bB&`GvFraTBAonpOSM^p2VS1Xe}?% zHglw7tb2NXp3+G7b7_fAlmy0gL(UvA`>pZ)TbV= zCS1u|th6`b47bRVvm@bDUKHe|w0SQ{8S##>2}km-KoQg>Ja144YuHON<`IstypTK@ zj|l5;d85_$Nh>mW^-D|9o^*sIG;%KvS&<2KFEQrQqTC^A5i~OQPVQx;u-uE>sf!kt zdnvC>$oeGrY@YPcr;ab=p2$6>^l0vpJj%uTe(t+@GQ&Q#B6IgI5$g@8cgZ12TLA4_ zG9W}5yK<%F3&^=MZ@yZ;liQRlPtFC_-*T&R8=!D2GO2e7D@rK-%917_M_5uv?k#d| zb&T~a&K*)3>50_SQ>!D)Gb>>If@fOp4YfY%3C)%9c!*qfFOewFYQ66nl`CW3>Tr0B zT$vG!dG7Qj(}f&i@fEqfN@H^;<#q+EW0wR&7sw@JiA8>SQ0j}9AVwiRF*imjEPi$F zav`kCUOb|jBR*QsR*{aei5KP6W=1+jCZ5STsT7ttkR$yPX?>E|pF2^tM-va^jt^M( z$v1LX-%s3?BfS=7J)hH?)2G%i$KB1@r{qYi(l6*}N8Gg+qp9g#=*o-IyOCC8V(N=? z(T35^zDNz&myC@&mvdMtEbe#?YeB6?Uz`g45o>==k5X9Nft+q3eD}RLlKdEtxV?*| z?=L~S7he!^gvIsb6b7`8#nLZdw<2>w7E=a0{jqUPIrKO*GOkL_Wl&gLX%6v)nDa?o zUe09I9*s-QnG~?D%)X}9_v2P%%WR)cX-gL8sP)yjsBGd3xj5qHWuK@9+0v(#jz{B0Wz(m|C#$0D}K5M{z^fQm_MM}I=%AT)O2U^CKjC%I_`$24fRvr{-98B1gl?83)R@^J?Fq(N&!-xnuYIAPtI*KNj<%=Ro z$DS)|skS%Dk&`n&OL}9fH4w|#Km9MEhv9sc;AbKr!#&=}K^1Wm1^zX==5m za|1NUUA)xlcUFk=+IJQzO>kbx+ykw_MN)ncHA&&a7eRr6Wn za%LGbT5pdsOI(bRaSpA}#TXggP@ao1GLp@&XJ+M`gN|6K&bmx5#0{UbO7lBzUCVST z)mwjZYL6T1p#s&o2Z_6pNllG7Jd#y=$NC`C-e>1nXEJAIQd9GFYk+%vX&XCpr#;6P zkS=uLN_;P&>0VUciNxv3GiIC23@7o=x@iq$+!tToz7AyQERhp)#vRR%(^JMREw{${ za>k8}+vLZ6V#ZCivdS{9E3pTOo69CxzjnyDkZ~D$l{?ytc=Nltq&u&<97H>tL7X)I zj&@FcW6{oF*HdN2S< za?y;-8T(^HY;Dcz1sQg_H6^jKy79>9aNe`68LbPJQtnrn0CO{lX6BPt$eLLTreeJU z%~&82xQudr3#Op`#u`{NIimoLwYp}~f-z`It-*}s3|5};CgjdY#TriSgS5Srw#LX< zja6zDlq#VqO1xjq@Mkc?cxSjO!6et^A$zpMdRo&FOVW=kMMFoGcu$<(FJww-hm?rG>F)~3 zJKXex>BK*1ReE2#wEQohMJiYo_MM2{+5`m;WJWT}Sd2 z*QyS&T6-XSHnl=^s-1_bl=!xLm0!sG6e?5V9>iHft>s2!jWZ|x2y_=~vRW^*qOz2t zC~dS-5u~w+FB%8ZktmmMSH1Sy;)@FJZPhX%T|HJ7WUn5cVBV{0{UUT(>C2F=59uAqr7@Ha2U`LvC5ZcE7i*T!GV?b$>AcTJ#H~yR%(x1%$Jq>HNOF_m*gWLv@-a=Ha!^$=A^A*hHPZI+m7{t7B3Gg~t>>Lk4e7?G4JrM|8=OWw;QafscWRnEttR3- zDeWrMVuifA=lN+6C)`(eJx>|N|3N#SABRS?NIUxcC^WtgOY2WN5ugKU60bztmv%Hj zyW|^J`3sMnP3ec{!jsSJ){j*q`(&QP>sXVPEau2@Tc)c1PX~(~h(<;1I zu+FvySLqs*y}+yEB8h*pzkhX1BvF7^68UOyWIWmkpOgM$hrDXpa~III;SrQJ9%{qGNR#;7N*N8$9VQ(+^Ht%`NfcnW z9#i&QFLcX#ka{tdR&wV2RqCZw@}mZkG0D$0;vw~Or_z(wF39y<3G`=Z^>aDw1jj=$ z&&inIFs{Y8Qi&@39`ogx#jncDdDHU5ER4A;Rx2$gDz%gR9M-3)?Wv5%@IA-E)Q(j8 znY)&d)XwLoLo(Ytb=L8QEww@E2vnmqWPPyGFJul_o>%U~i0|W;Cp9NVo>9L*yBbpm z9k;H(ayd;(`>pk-S1zgtlxnY!|AKUVknT^f==xQUBdIb*KO>jJF$)F9QaztWQ`E$97oibf>f`FmbzedRV9Z>nEuN@1sJ zq(KcS*U9-I(p}Y@Z&H^sr2?!=FoSokQKMTHJ38Dc}ki4Em;d+w4O_uB{k(Q4hK_a zXq^YF$du{dve5WKV}(6h!;Xi3`4VDc%=g|9_clnZHTr4bcc zTF44tg!IOb@hym8Etm(a2g$pWC6|AqB}X^|xpW8W@^SKkWEm|YTylFvWWb{(xdUQ< zpWGTT4PSO&$xRWVtgSCtIVlugR>^xtCr_j&zyK08>`++(JZ z^S4!b!7S!)l!we<{{4mN=ifwgBx!<-cK+SYFB_P~HGZ?iH2$go4jDo4{}_Mc-&_34 z*OR6@X{h3;Qby99Bu2=bW~LFJ=?<34-%(7(ddE=*M@bW#y z*C?&t{8CbHQXe(wwWcNQOL`YN1no`QkF|?jdNscnpgl_8GuI{UQu?tOoV2sDg>+A& zbtN&spixQP*!de0Ja%fjN6fOME~Q#p*|AAx#sXt7skM^%K&^t4nku6q1CIttXKccw zMm;u|k0e#p&c<4XZ+Q|iz?4?{=Ujo#n-3?IB{6f&N6~aP8z0eLduK7<{3ywnREG5- z^L)t_-gWR*GwBMk+cmYVp=kD=<=bXzQsFZhSR>HvJxexZ@7APGy;`d`pkyWKA-51S z;D<>yyeHwmd`EArR_#;T7E>Xs$S}W>v|KdvDXbc?jics6710&T(ddKXyEV%o2iDns zKeXCtPnuaVS#l;o+fg%xH%6k3H&YUI-phPW)Ol~FL08q9OFEsM=4{iQ zcuut)Xm+_dls2|N#+;eBY_wRdFF>O--F;|;(tPr>XD4gxyMwANLTgw0Ce*UF2j3A` zFR3;WtwJf>T$fm$DE%_i3{LdR`*Gv{pfdfcd8+YNV#!R|m6Vym-|h8F%$tif!`}pD zn`0AG6SE*@>~~uez0fyF*W}NGo`xFy@`Snu)yS90=1k+Q?^eu|wJ;H_+`k0+6;$ev zf_@44{L+8nlo9Hek(P43{>jj{(8l=3L%YzN{$S`KG^>hvU_N37d4^^kwQKLWr(ZSS zGlM;M^=~wOVvh9O_Q?4D557}2o`RmHE|X{3t75CO zrc=!f&w1^uV`j1EtkMT&qUW^d9M)PhIR3y!dEyb1Jp&%e`D^Av&k4_I=&xueah-O#IO$JF<6v?CiAF)}9FVGp%8i7%f1jWeMvv_o3jx6$6+IEi$Oo97+XPNDT} z97(zf=C?ijJa1FyE5=_u`>|^b^XPNaTu;C3i(iVyczE`fpM{p1Ue9h%FBEK!_U!TO z3ut@e>2a&vxb4|pbf2fz5~JPIQz~_)y>Vwf-4N~dbZ(IG{XXg1JzWq#%IN7(YoD3x z>GbSG%QZtiT^?qg`LEPjpPS~F%`#7?*8U|ldv-3ww`HwCx-X(Niq$yH+Mil3eVS}s z^OPs9gr*u>J*E0p)i2D4JigqMXf?)Lo`R(dp%S#5oDAq&Xc(RDQXq6iFqK;RnIuBDZ2uX9WA2Fhdm)4$*+@imPh7B zl<|%y$TJEmpdBMT!O%0bW29#^lt^i#_%fXtOKBs*hXUz7^W7To{UPZ_dH-Hyi~_1hONeL%!?@BO@1yEh(2Vo~M_kF3xsq-#;%k(AN6USi4D(CSoshq_d~Gz;w=v)Ju-*Fbx*+HrRy z9_4&9%lB1KY1R<*72_SZ@9QN{znS1Ja0}H_=fd@qp<(i~pUx-HvfKq|<>Z&MPG*?o zl2JMcMUu{*_fL^7vGfYsH%J$+ExJoOXZbm_HMD4@TSoP(v}iSU2RqPWw^M5$Z_dQ( zMI-9D?Nw2aw#+T#7L8^<*(X8zWS3{Cdx`okG>ZdYIDDVF%yZAjd zfK|pLq?8FsRn= zeQtf+%m`Tj#n=(Bl5@a!hUreYtGPIg_JrGI-IQ??x+!0fnv=}(gzE_skywohH?%H) zH6Kd2R@_9oKbngYt|VN?8bQuiOY+e6nq>)>6Yii@LKoF)LFW@L@g(_#a&?_M-ZO&} z&XujEujbRXGxA-W^|CRTaH>Qi7dzyH6UDU15svk^&ka3`c2xH5)|*g&@kP?H15G%j zwdZ-6@NSvJx@xp{_{Pv-&Zky=>jxmI{XR*jHQ1{pHQ2qL80J_3^{kiKbdGf02{Jbl zjN1u26Lv#iF~=nIhzI?$BVa8O>q;4gW9EwqUD)|M^v`{#o5i*-{{@yeQ`Bnw(##I{ zc9~Yddeoek(37wS->Z1+k}}Mzl+l^6lhW=&UB%22&Rp#Y9a+?cUnR>(XkBy_I%z(V z(3C(7V|Jz_*wJUEnVQh}uY1wHYK}^%OOP>g(SHp^lOZ>~R-<23{*c;NB-D{^C1q44 zOAV%*UrO+o9*3TwH_A%)K?}`w2_-9K%>?6Hm>_X2&J0TMmB`v(iM1d>Vp9kng{6&@ zK~zb|(=Qv@)hA^6WJb8Dy|;7`>0YHS$q53!-KGwmoIiO}+C2cgr<*rn^v zLmyI?B}IpzKhW|;xudiOI}+xv+l`io7MYL=MN&pYf*<;S(Ch@6P3(9Q=IVEV8RR@m zOS?jTGZJQ#%csVU%t-#0Q7K_+LO8UA{H7(yvtk~;(-UUel+mKr+s2P=t5HWfwaV&F z2q$kD!Qep7oXQuruA78bZ$7-RDPbx(e}Xk^-9)r0)F8Bk89`jTlrS+tM*1IUlM;w} z#s$`I=)wcgNoH7L0v^WyQQG(tSv}IvV+&6}ix|t%3F9DkMhRm|`boExF~<)5uhCsH zJ7Ki=VjWc?>m!b_9FY)=c9JqiE?fagX+aB@utF!A%M*-*5v1EijIa_$LQQxCeQi3F zKwaoQXpvbKe_wlY$V`bJRE;NR{2iq)7(3!`#or~}TEUFKIR5F_vaRB&il;%q_=%7>Jb#*t2KSd{8Id$_HR%3XN~9HSvwmm(7v!b@9>;N!JiB?dALy-A2q z-}Lt=J?~Si+wluEml;^2G~K_Ozw)fsU-CJ^?3`I35#$e0c;O66n+Q!SoPzeDWyI_5 zhTpvGkDpvP2JPo&zbCAaRYpwgj~~1CKJ*$idhKm!jaeB#DqhkZvm9A_wA^RR-(>At zE35sd-mU(6DHh&e@A9oD;&^(l1kY55Fvdp-5wUtNBlKc$$w#|q!Hl+E| z%Ag+@i{g3;ZbH8`q7vR-8wI^#EQo8>o0Cgsa9mR^eaiW*IIcl!Puz&JNBXc?9;YMC z9`2F2a_J486_3P~N^h7Wj2&@4{Q~W$Xa#GT?M5qbE*_5{<4rqf**(}+ zbD8nuK+Y@iuybCZIny@I#GmE-SIt?<%~7kDGLD*GvRgzP-ydl2CiAg4Z(I)P)=@@A zoQ%w0p{%$9=ogG?PX2!AhfqfTZfL*xPQdp)Mpb=fu3@DHywwPzwX6>#$}EXXJ~BQs}tehlQrcWJ(?_-Dv@N!&81()>kS^jCRS7_XSe;}*v) zg`@^c^24aK$G(-pu^N^QeG(ZbMuY3kT{{&&?e@Mf__b}*(U<0nG!cv=QHP{IQvAv zO?liX?LTg;<3^~JvwfVE$#|IDnY)Hmb3^u?pA+*udrfmA?9!dN+_1Q=X*$lKt}A)> zD3{3Ux|DZ|T)6FaU2t7SVqCkD85zz!54m=_WY+z~c+1r@k6FweV~VTWwF}~|%C?$U zOs}iQMg2GjJmT6V-w|;h{IYAeiy0v&aBR#;v|!gR`I6JjfOaNEkaL&gORg?g5A?S6 z3p;1y9qV+U+#g$eu;I&Z(On~FY5Cu*^R7FO8St&K+yQHidEhgv`5&KKzY(Z& zmicg?&fMe&>dg2C>inN(f@`L+_Ee zLw2>Q#x1O?DVa!P{>ixJYLGgcO~zJNjnvtik5=KTL;F2im8${jq@QbC%wkSEZ@KCo z8v$`Y?y5>;^_cPI6E4522Kpgo*wOY^<`-P$t|~Nc99(`acfOe%F~e1cmSZNlN?hg8 zH%+&zRIRO~^Qm>5aW7!~s_}PMDc-WmQm{!sUo!t3u;!azh>ORYn|EWK%cr?aC0&80 zyJvb_Ib!85+~dk{5xE?RW~wVIgxTcaHsGa5^>~0aK1BN9Fji-X^h-avtmF#_G-l!o z{tTC2AVJe7w%o0|^oebDKuaYTi@V&wcaJsZqpn4o^BlDKN~_F&bw#=slFRSNFABRn zu|KnhKz3c0V~tpH3M;34*KF}MWPQwZGcvprNpXeq)ui6^x@KS(&F#{?Ezg+@SGbn; z6Gmp5Ylh}xxu#>6{j)n@%_o;>noeTGl(czRd7I{%tQz-bu1QLBp%5kBYq-WK{Sg|Y z6bc0^xsBVdk*?9?G8s){6Q{P+xzUfg(7s@%#NO9*#G%+hA!4>8_D<|Qtj`*^WA9>@ z+sjX42VXo(Pja&zdq+osw-0me{HRszRn3L?7kgRhgqaX~F?E3a-h$4j_T&2t=&XE) z;P?@AI&~k`^JZ}D$=EZL!5gR8Q|g<8b|UsP8Yj}&lbKSN*P(&5YfvS0EK@u_g^p0N zM#9*`;wv#R_Mqm%emC|&>><;58V@~YB_+!vpl%`hWC+75k^*z%adoY%o zvIhyuoHlVW)L@*BeLGgx^b^L8*muaA{iM;3?-8^JNUg?I%6KRB4%Rc~mty;3X{D85 zJ{$n_S?q4DeH7_>_{NYYJJcO3 z5tF<1)OS*)UzSpr_Si0{8|sLa^)UtNOnrx32JvW5^`gx%K8S6J?LZqsYt3M7nN`%e zDYjj$?XfMckyvlz+ZfB*;$84R0@kT$>MMIQd<*fIY`OwgPQn3es+kqr8rzBWOJ+uF z`}i{G>t<@eI?b%It^610+XHnj`mD~pbEeLom6ZE;^C8=6{MwunXwerbqcdIRpR}!= zuj*v?P!`*wJ;XjSwlV!8zMn#M>C)Z>=7`uT{k61ieElghZk*6!%TkDh{IykZY)Lw^ z&iW2im@a+FNjNr-n=^hNmNW5Cx?THqv5B$dXFQh;co9zhFFxj-&Ap=l{|p--SGDU`wLc|3M<>{KWmkMdZF ziBN1vN-wm+_WqZ&s=99*t z^NjO+fX-s)mpe#zPSSC5bvw_fM=qKjxvJ1kIO#Qslg^XaWfU@;r@ov8ZAUwy9>0W+ zEAjkr9-T?f7E#&R?>t7j7oa29^=*susHC&43DUc(%qh-8>gzKfnz_e0fc74_>{qP@ z>Q&9l6Xh6KpH@T(3K8oQ?FUP@S_0;%3a*pmCD*>#ULYl6*r@?5r5qi|4yK$-kHEzU6ud;EZ^nMerGwuFc%KYWmv>D+!alY z4EJ>|3@V~xnVBJ}skxxynz=LJhPcFHsAy)Url^Rd=1OL!=AXP{mcM5@$p`;m|0+7D6k zHp9@is0=k2$iHmU5B1wVE90Z6Ga(gwuoFwE168+;Mh)8@seearZNnZM3~38Wr$ge- zOMeqyvJsx-aPA(~f8>FF?x_=`F4Q$*m(Vfhha({f!l%=2&Ne5hU<))VP6J0CtQ z&wO~cGt5)M>SkCorRyMty%p9G!@}NbD5S8r8VM<^H%7uc6JF7T`x;6;^vUguDdF5~ z!&|r}yiRZ4{%-pM+!wpC_V<`trz_jvZhs&3>kH}K!zMz?>9l=5(&c&M{iRgQ21p$P z9d=5k)SO&d>S2gYaTiO2N zVIJ519n$j$i!>b4T)eS@6LmGd{i*inAbDNU{!F_>pBHqO_POmZKzd!*w7a`&0N#1Ktf(m$yGYd=&0B3;E`>%UIY=*S0@89DSr-N50wZk3)xNi|uoU z4~Fhuq|R!GzsT8UNQLgC(zTC4_h|c5NPSXQwLjjDxF%z!{fUF5fAKC(DRm3gQA#a? z4W4M1sJ9(#$`;|B)63hR8NLzj_CBO1aQcP&LV9#~Go&IU)(U@tWXJUv9U``xt;V+B zN2~3xcHC}<5%W>rSJa^P86)N)^-(owgc<=0si%vJ+OHoWy>N}%v3(*wDTQ+`NLP-) zs8#ptAGUXlz_^st!S+j8-lO`SgJ)%BY@MfPwvQcwc!kfJ*!D3@eMHY(f6Rzeakn0J zgZ9zwCm{7eTzf22N9*_S*OX8{tlUPlA4TbC{mu3x+EJdyYPkJK>T>$<^>?83Cf>|b z?XbN;Ol%)2I`bn)`!f~m`}Vyl;oZ0P-9=L8!n%Xo_k{Ei?z<~f@s3>k&XfkgraRFZ zc<$G}J#}yBAGC+D`dz(C`xfm3acv)cLi<*DqGHvyu$R_DV=^SE2{? zjgVfg9Ews7g7iuyY+!bQ^jzg2NEbtTrg9rdmq2==auZx}pFVu(qqM;sNHaykI{WaU zoEuS>!-w9^)K?&dx$$vGH!&aH2pBq1^uOhja#| zE|5+YNneCoom6opYS0_f@fEPR*%;DM6=y?w1JV%{CqtSGX?VqGl$V1vtl|hr-5?bz zhNG1IP~N^Q?;uEnc@ON%hBDq81BpFtc7epGZ1C3F&;h*SI7k~&Is{VaOFRP~+K0No z=)<>OOz8ti?~7z^f%GmVJbm5zHA+|&Y(06*(k#c0;1(fDNcLAldiU$ulw_M`s-yn@GZ-DeKNGFw-qm_3;!XI^kbUmb_$}k(? zfBigo$Ps0TD&{RnBg+s~?AO!{Lq;5gezPY*IuPg6){cd=??LFdXgf%I%9(1k9;87B zq2HoWkam!h-sl)e0}t9CS4@Mn)j_*L_f<%nNt}#!fzB?8*;|i{fm+%=JyeWNnfqsBp(cuO90p^~=3-kkZA*2po zyHoMt!ljv>XfI9!3Kt&m1nxFKT~RoH$W72qLh9KW10Bx83TG4~uH6dV*c5h=eR5$8 z?#$x$(>C^*`gbwS2!bycOxE61~7EV4u=9$H6 zdf|kE%pZ7nwUmm}RithO-NvZZ3Gx^G@Z|QU!m;?|ki4gLdExj1JPc_+^;Na7l)4kH zC|&#S`%1o0=WS8)Nn%qq3qBO?d*r`Uo%V&3hQQnLwundSUAS9L_dvcAM|2+x^(VXMN?(4j@WE+0Ar685!) z{)J&koe!x`VQ=WEG!O3J{Qr=c{dtC@t0x zw=EP2|I6RZw)fi*eemwg%(ewXMj{`c0kyq1L~QW1(QR*UDpuRhsJ6Fw#c=&*+iPv} zq1##C)AmLx_4^Z~SCKA%A5pixCe~0d>wDYgwY>r9PL%iRka9?~A-yt0?rV|C=!2(` zGuxhTdl{)ehx9_*E2V2+Y?}w^S(Nv3+pCanGZtymjwg}t#lqc?9z`jPTG8(DZKo?Ta(hrqVAD3&}#C}=*|Joi!y=2$>YTM&& z;(vFb&QA;&1qn~JN~yQ#2TG||;@T(L<|6fM6O~$Y5v0(f#rlJuoa6C1AKP{xOI`%& z?l#0?e9p(V-Pv|8ymK#gMcZ8k)K7m6(j6Rw8*AS-qwP-Q`?Ef|kg!)bfo^IWJO}&6 zv28cC&A=6i8*S4ITR`_y{e!ltJuiTCn?A9PrwceOOWG#2O@?kLr0d(JLb^j&w%yov z6RySkYi*O|eI(qYvhDgp1`^Kj+9u*^*;_?zlOpK_ybaXGwHeN!u4tQpUc$31owi-x zb|s|W;EE2U%e%S>QYS)(H%!~EY?}n>bUmu=>bC2Vial{CS>Adr$Y~1Jsm&?(qr9ESnFK6Xm7r41pi2)S|0K*5LHIl=IbAv$EK_x4Ml_kH z!Fp98aY!`)mOn9wGCLoGF^&441^kX0VAa-cL!@#FLGycd(wl| zs-E(WpewtRnk~UPH4>~7Rh!O3l4}3~XeJ>eM$N zyG&1EdNyU+BqP@As;a>x5-uXBVFgdh-(bN9yk-=?NL; zPtSp-ishFp_GZ~np{ZbtT>3oZY9)4dWzyp=^A#{wdCGqUt;$lq0<2JdL{6nv-RM8n zivEyD-?_3I!K@lAa{3xrr=+K9)z`_LM4#D&`n|y>`d*zn405#+pDCvWdZ=2+JybPV zM!JmHwwAu+%6<+xt9AfgEUotTW|1@Ok#rn2zY$F;cJTH|rb-=LDm_)Mq-QIX`Bb|N&jN@{NDEsg9uZ;yqhM)e2tYFFmjoh*PZ^OUem z?p3d(PrW@F%&TvLl^lKEo(gj)v6UVw3XKive&eynh)8@wSf-ZToW^shHknz#Fa&V+suo8;9nrk+QN1-y>Q`=~h%%qy{pw-19oLfo)_ zqh8wUbuCjLq^1IN*x-X|i0G9>9mLiGA;LbHp|%6+~4CFsaPVGRSxXRNYYqh7v?#W{1%v35*1yj zl{#JYY_-$lMIX`Y)WISrCrPU5Dstu&u$6x3t@uoDj&yJDfSjc_I`yXHj5w~-TOoVX z56mmEaF(9qV!5_4L_%{vWWy2NsQN(mdIO=EAhZ{OEy{p7#(@^KGd01l{!Ce-qPP1~ zZX!1kjXH<20&|S6ImU{-+7Oz&`VJ{0F|XuWmkHkWGm+EZg5G=}a+!E<%&WYX(d4Ye z{~AUBmx_I2RRemn2iT+<$ey6HV#7F$SuMTeGU9cOjHS(tA-ji+jM#h3mp9AaEpT<|k>2GzaRrGdK(4`!$_94oQPMPT z4D{xB%Hn(8ZU=Vd81(9JYI;bjStLvz2kU~LtDBix5UN3-Gvcw%deNAvB5S$I8`dh` z5pr3Gd$H7~h7r3~eOvNq`f4QB_Vx^NC(xzOP?pxYRN{YE`l?ICVtLLQc_nqOriVAu zd%Yb5jZ60FsG!~a$MJWBiDNK zUGj9$MN+0S5)E7;mdR;pmy4<>Un8<*PJI?+Z|)Qg*HJE!k?ZyMz?_!5=hTlRHR&xh z2MO&Z0u&gI36<#DF02EOcJI~QzH?{rCq4+OZhaRDFZ!6wB!26CAWz_!ziTtL#_)} zig*|EQ^{|{8yi$l$*IPWp|tl!Hf)z+e;FyksawdKh4DYZ?i|HVvrK&mHIlPC=Ngwp zkR4}=?(`oQW)RNE&T#Cj#ga!$4D8PS%Bd-kbHOHh7p8udsp9`Rbtfs2!IiNW(&I%| ze-}pdr9{SNceROV^eB@39^Wr=%xIi6iX2@aOc?X+txTofG&6NqVMeT>x$biK|EZv{ za(BZS)|*E~69wPfNn|BG>!L&$iyxX0Ij#6@x6+sr8+K#-anVr88NDHlDaYTTrYJPW zftoAoZuCRVQQ(sQV}9|~nB&eR<)X2}sJ~s9v0x2jwKMeFj9A8*Q-t<)&?wPlx#oAt zM995VE!dqSx;50$il_CVY=R~*(+7H&h|RsaSE!{v&I}+I2(@^oi@pVVD}L*h#PAl* z@=jkbsrFJK_j+DW5IL#IAa!#eje~; zsecdj>c>Jusw*i6ub3*bzM6SXBcBGd9H(AiM9temEm6YjQ-wxKaOOVBSBb3Ynfgx3 z4~bsiMbh#d1)i%2uLg*odt|R2^T>+DhdV0TmSe|r*7NEBrcPnbO3Ket)}YhUc2ECw zoFkn5HuGF3sh0DC6+1iASM>V3BI~!PnI=@fCF%KLb)+ta#_QQa^G&AiBTNkS?IK4~ zlP+N=ZZ;IXI+>gWIC1rMjw37FlU@n^L?^e@~}*2E`eM_ z-*#%D=*Icbp zg=UhFs~1-qxl*gTuo5umLw07cFqSf17_%nWc~{Xyv}!Cq*@YiSfq1aPs`#OpJK+#7nsR@fRzP4*SN`i;n; zze3bC4~SmhAbL9l%xTtKh1TsM`iNIWPcUaWnCGdfOP*rtWkSyW-be|)w8H$B=;LFV z`V1K&{7~lEUTDXPKDt%Nm6D535!tZL@hHgNJi^oy$diQ8>%#b6@<`C@mxW<;kOR`^*Lm<~Ej-dE->hA_!+=F})Y!2%OBX-C#7P;sxrdEUAhy`5y zYavgEvY~E?_?WXl25VHS$T531K11Z_VQR!ryb+&q@&5^vUsCQ)zDCWTNQnS0`2~3w zISZ@{H8Yeqs5b*Z3R8|#ola0%@v|C!PD-b{2)0?sHLy7 zT>odeO7R>iIiBX_^!dzlF6ekF;&=JBU^-u8m=q6 z*%%sU-zMqR(GMVJRS(dIm2fm#WW5i$FUcM;(mJm$0Gqgeb0MbH;Y{o-_ zr*4v;yYfbk(;U|cUBb*|x8hZsNglO`IUk`cUgvB-us0*T=gKp$cA{SLI~%O=EM?Jq z{f@{~(7(MQLC-fT(UM9t1Zjw!F75;^&~(Bw(!HOJW4o$)-Uq>s9D z#oj%{F0R3xk~=ze7E{Z>98ctOT>UzAq@)^pS2Tn<_X2A|uSK*{Oug+XsrD3Mw5d>k zUua~cxafM&^DMeXab!h~dPaNwF65r{?VOU9=E8Y?TqSwpEx;^Kr*ryjYPKVLgWbX` z6Sq>+i`<{wm3#}VQw@~GGId<}xadyNMD*L_9LP0cy^*{IIU8ocSk{?N&l6gyzl-l7 zet)j>$jbC2wKmg}{YkmFpO(*u|)mTBRs zLY{FxPv7wRBXC$E|QvlkEF%YR?%x2JLU8ompn&}*wAzT z64Q%XL;qUwG;hR)-kt!~gk4pb&F!Jk)UjW@m9~4XZyOjty_G)oR^}9MTgelJ=3y|; zy48j!x#=BDJq2{>qr#-WXn4Zu&0j?hPu!9>A!ozxAbpkkaNk;y%~!y@67S6`=~Iu7 z!pkYBA7*!qCx*2Jm*EsYZ6Utu| zDjCJzN6>VH`^eknyIaXp%FSCm}`eH2XB=jKJp_UWqEQckIW0BMvlaR9)X#=iA18VA51I2=%JkJ_J;;vrbP0PZdRI~{qe>*H-bze! z30oT0nOr%zNY)R|iXB`cG1D9A%{=FeJWo{es+F33z$~LgEn`|;=`9P1Q7-KZdQ0E7 z8&b}JwTxZW!LO1zlG7d`OkN<_A~lKnjX=+c>g|=3D@32^FHA-X>9^e!^>#m|iv2xT zR(Ul@H0oAi+10{ieXyQ3tmb;vS?S-dtiRVAGj$hg8bEJu2CMn3p_;p-7S6vpC8;fJ zOG`KvGpIV?N;vMQfY5!zicNg!3FgU= zT{@fklPI4Fws2O;aWv()Li1KeflHqN>%&Qi9Rs;JMAYJtHG44RS2jaFMJ!>eMiilUKo7&g|8^%Ikj6 zc&`6F&%S(k(xIhp-pE++;n|$6r%XGmvmv`k#(0)}4Nrj_a}7`*o`t2-r`|jxIWxV< z;PXF$ToEFV`G1g8C3As`z5{0IncYk@)qSiNzMqVc!EpDk(`?nwl`^Ip2tYBwo7jkTDeyjMip=G5lv?QW1=vZZLkOl1Bg8vVL3-2m*(zOD;v9-a($Q8J=k zd;-bn6tRZ!UetUa^yaISXMuU{GV)w|RPbp+PD#x4igw^`$Qg;HIrR?ptgYEpG^HmF zk3w#u=etCrS=TTloBw0}Z!+gjpi5*0;?h~<<7DX5Cq+&)SRZyh=`oOds0eha^ifW2 zN6I+$Mta=avp|>GmYSo4`mdl4aUfxP`4)!@&$Xl8NX18gK*z{a$@W_2uM4w7B=N`F zNb*?vRkWjMj6}H{pX22Cj!k2TD)w^88A)t$c7o*85))iJS(t1@rX(XwlA-*PPluYyM*O5Eyd#l32sx|70xq5+%=}guiT7qz zIq20dM586O7w5s=DiV#Y1RFS-@EHx!q-1m^X0%7^nYYeXM?9n6*9ggj6*W#0iC=~td_F}YOq^|Y!>#11aGL&*2O zT+Eh6GJm=F3a0J~S`~p=)e2Ur2z1fYpl1(eg0~y7c}}kUjGvsZ)XY3n_z>ADBlC->Fs&O8K-7JQ^)sIU9tmYm&n+338PB# z6UsM`GIlKIFJ~kUbYrizhShlNs3`;MIlH;!XONv@WC*9hR@RU%lKOiiedqM{q}(wZ zd`6!_&B^2sh3X9QbYc8H*qtNY>3v1Rv$F2o`*c@*ps5HkA(qJO(lNqt@}}84+|hSe z4bbP*b0qyx=Ow3>QPZ6@$*G%|I!*M6c)K%uGgZcvkravTm zifnn8Na9#?h(eheqK_p0JNqwEO0El*kN*U@Ms*W?^nfrui?aAYJ*`^L{Z2i1E1u_~ zo_nQwwKMZe?>Ku7ucAHUdTM?Tc2f~)Ko{L7%+PKbiB2vNJJ)j*)N^)l@l~QvHCRP! zRD`<4O7yYRvsKK(63Q+r^JSuI5=yb;)OF|L|0c=VmSmEtT1=p1oPm z6@`mrEcBvfdNCT;^L(IHMbNuUccFO<>_gk;d0yn~A)-&jPn^0K^hU;oQ}=^8C0>zZ zRCmdZ)DHr?bB1-Qi5iL0hS50XSWBsIC9=L2tfeJg zdbem)8(7CZku#G-lWq@oRT1d5%(Gt0nDt8h->dPU)8hG_d(S-I5c52@^hP{6A5MC$ z^$qiE^H6Id6YNc^9EQk8*!7&lr_gGIH}_Wf6mE zUBhTn7ee-`H#t~nZ=@`CQ=vD*`!<;kplJ#7QFxa?%SiNQKOs+w8W;yW*Kb~L!_?iG zD)Gc?8G~M*F0^+F%?QfVK*v3c(_F)78NXg{2;zU@5!s9dyN3D8>;t)laU&P@xf$^d zXMX|u(&sy*wq8pt_4YREccLuz@k(Yu&ofxBJ-YMZtqH}VPs&hIW1Oosf=zP<^p>t^N80)!Ebr`*T~*)Viau(y~fe%^|8G6 z2VkQTFY;Py-nEpcRW#u_i?K{Sj+)TR=Tg2Nbn1^nGgWA>18pf%-2>U1V??i8gy9Wj z_PC2CiYA;wl|zM@cb}V(!Y*R=UpT#2N!Kj%^s59{6xqn zn{}Lhn!@a(bI>=cR?u-oRF-zr5=)&Gi&e9~oE00EaXsubM=^IXE^39|n+SCF0I*&S z0=tI!&NM*wMq+YT&h^f+ufzFmQV)G2TV2ie=D7OGDbeS&B3nTh%ZSLSF{F&~oT8tE zl{r5#LC-lcQ>xo&XsWsP$a8gdyFSOqxrB7Y>%#`_!$QedIBeBR? z8BH}R%H>Ye>JDaAEtt|8&78Hp zmG*k`j*zQ}EWOvOlb~^omOiZXLVN9#qStpzel24>r^S~l!gGHmvC*0D2%~GLXB#8Y zR|Nk|WDM4a9j>|uaszv|u5=nNeUax|f-V(rtPe3HK9KTGpf@LgT~#CKG7=M9B>v`j zvgGxjAbWe4(8%a$4!s|qM+h^U3r%lf@(@@P_EYKWkn4i?n&YYe zs^p2Jv>J}V7CtGc4JWAF&DGI|ojqT2+M|VG?H!9JccndDG!t?~SlvbEQT~eLjNb$; zE$`y#qKPh{ei-#BSjV}kj(4vPb&KUL^LEJ4CZYHhHjtqua&5hg`uEZy(;WGrKa+D51WQat6$^KF)jtay`AsW!{2ZQ+gtB zIAoWhhoqblG7|9|J+mV0MB+_ElZsb(zHj4cLvOYf4W9@%)56Y*tvo-u(1rD^VPtk` z8B1UvrMp0`4{sx+2QmLGB(2J)A&s0Lo5Ct9{vJ}}P;+}PWS4%x{1WAwSWg#89%m#n zxadk!##hAAQ5SqN77usPY_bWgXKFThMYONzV`))ViHB!tw|dS{E_z;4qqE2!Lc2&9 zZ$%CSYf8RRLyeT+;vbW=YH}##im+;p$A~`t7rBklTqTSTrY4lUH8tbGY>0|VMpV zF`(m`u!1q)C0`RwD)-81@&9^0*K>x}i>{z1jNh9ed-F8d%yHq;9U!|X$2@zAY^5)H zgch0WM3erW`hCC}&ay0k9~8!ODSs%8LX2W<6R~G~Sm&6o zl%*!#Tn09Wc|WdzT*rv#Vhh=2P7p?a2Q6n+7js<1^s)5Mk{U}rUHn^N!kVWM5ku(Jkd$i1kd4kiP)l8=2MscTA19-JnMnkQq9GZ z6(!&Mk>rUl1?x)ZsNWV%^rFzd$JCvLnIBN@AlY~NZIP`4>q?REa?u#}rj|(JG)IA^ zefTD`<4LbG9J!2aE|m!8A{n9CaH0|q5>4DpidU2=v9^o00DbuMUwC6AmI&$W4~2ZM zyH<^49vM5{vSfaa+w-ZJx2(C5=;8F4U`2=+(P@zD7-77c1G$-Y_WA8V=I>9wU)>ZR|RRV#?U*h9?*)HH%l(M$OjVosk*%~YX2 zlKd0c!o9XvcTtuSs_8ktw2qbW==pg!AD(U-1C3KfVOV9QQd`GQw|U(p`R#GkoB^U< zpjUqp+AAp2dOUZk;M=F(^kwSSOqE#e?N(rgia?igWMxG5_H;1Eh~$mohA^QH>2vu#2~LLWY{!Y5N+|Askxf?j_W z%<0gINzDJWP)YecSd*MOTJrF@r008~%^}v=??UhOFt9nSWbDsG6V?oT54Lj}B)@{}*%wX9QT`*?%vj;gt)k%y zwjtP%C#&AbOysS2RF3cM0M9)2fx95t?_t_d0{Y_1P zrfZ1I+%J3fg-hz>+En~J%bZQDNkdp8+2f@g?iU(3ep_h=A3iN^B!bne9#TTcuZxgt zL%d>Ks^I%eF4|J^WZnaP=}qZfAV(o)GMbfz9!X?0RfJg0v)KyT%|+)(3HEldiudy7 zNyy$#p?-7nr{rNmbE7aimYNKh4>i|gAm?~0mE*gtKIqLL=o`bRG4#V^duW`cciEFg z=DUtHTv7C39eRZN$I>J9!OmtU$e#NYXEA(VM@4T16rUKg`@uS$e!N?3>gNA!oySGGbfe>!5LJo{(o{G1p5ijAjjt(p^I@ zL=w}SIRM08#RXeORKLlS7zA?4o4uaOq%b_917ACX(6QMe9@ZeXxNm=N#V}YT>@p^SM$J_eY*9@CH>Q`8h*1 z2U&|h_%ILJLnv=1C33!67=TVLOn>R-VxeMgxs-uEB@)CX+kTJ-0_)$Gct>H zrAK-F9mrnqN`6CVdQg5wNc%Li_gy3&;-dawJ?rW0TDBI>$s|M=9iFNrmvKsL~h`S_B`oorpJ2oQ%N-w$=`v_ zJ_=g)QB7%wa+>I4iH9y8K|Uvpo)TK|AD7%so(Fn+71$7Fx8zF5W$Y=ZUXnce@51x} zuqL!Lb3No7Emp@U>h$j=kNLAO9xKeyhS4ICbygU5yLxNLIW6AkjNHABXI3tAuxK); z3KJb5*x%`9p^^xeQ&K`si6vcl z=EyfQ9pAlihP726BDFhXbxz&D{8Fnd*Qib_5q>Nw3wV&ha*Qs-vr<|!B zq>RKI_bfTiHNDthInEmoBs+mcuB4UMPGJ?GE{&KJ(I6`7Gt-Hx0C zHq*ykv^!+S)kr<(Wfw_3^R#MSjgVAxv@m^F7>UK4krMJeYt3{1_4+Jm8W^v<-U+g| z(wlYkv?lh8x5tZK|47KcveGroRz~X3QhGvK$vo0W&9r$_X>7{a&xZNh$_Ub74XGO- zH_-lBwy1*ptUPxFo@bQ}N_^PU{$1&Z&bEt&?egK=BiaNSXT)#oRacSimdta7$b2U2 z%stc`E7Z4vT^I>nv<>wIYNSu|st+l5anTIQqVJ-zplAGP2&bvGhvZ4e3nPw*NM?3t zKM^EZ#S%+0bEbXdOlIo&=3S;TD zI-cO=xz}!Bf4S&E<~dQAsTU@{1uMe(HknPi6|CnuLzSw7?4s>S@tL|XBJB4d=kz&X zgiGB<>Hnh9}Z4-T-nf-_h@+%se_B(B_~kBF`iruxk}ZDK01JU zwwiOIRpRF^`aM_~Y@5($;&+&H6R=E0V4d0xbn!&cmg+1sX-%o`&X&~V$6z&MQFSR! z&JewMism8@|f8ms4F6iW|Q!hV* z=5}5^9SkLZRL*}&OI|6mTz5OlcnklVB*tobOL0Em*cw{zl(MTv@@Wc0qqQEXHYvI+WFAVhju=+^Hq}GjM8r@E=X_1 z&l&i>jdxq1Dwda$&O(ld@jV;gkKlU_%4tf6p^O9YeIULM!uN1|AB^ws;d>OmkHPn7 ze19L`m*M+ze2>F-2foMSdjh_%!1tB-z6#%0PPAV^<#CddQi<$v(+5+sCryIfgXQOJ+EHC z|5a75d*T1Z?2Eq}zBT^l_8`63B&OVKZx)z^=0mf{EXMNF*vKX}W6N!&t+rWPXB%vz zZL-a_n;mR-wY%HB(reS{=`Bi6eohTS2ktTM@vG;Kd%RKo3# zBI?+tV{pgf@q;=RUvc(?sADv~wi$m^N1e%3#!Q)&7Fj~YLS*C6Nkw@~s>xl`xYxO>OV;vENf3`PoAy7KA?(S+!Voumfi=8r#0 zzEKDHx)9ecp0Mu~&vlHvvX7*8eoL-#kE2avN}N0HMdZE-Umw--Kc#=yqg0=N*P6AE zE0_8TH3>CB-R@e}*M!mI-e2PD)p7iqIIv^3e1+eZ=9MpBJ9pfxS4ZQ=TzSU$G4eI> z&W^dAU)K&Ce|hH@+B>h~-3ia%`2O`9T(v{T;&F@k^?vDR_-(D(5sjZZVXKaA9hDO< zy>9r`M~$x>-#o#0w2t56s_V!18-MSF+dCR2_z7DfrCIVVGY798U-_}?mXn{QZ870e zWu{FRAH8YJ^!wBf>N3Q^&%wXRPkjz5u^LtQqSg1~O)Jiub|JMRr!M?>>JplPh-vHo zeR(ag^W+!5XpJu}n0EOWtx{%r5K zc6aNH{hdFhv?b-WD}CM7OIiT?kx5JbzNEY?zrmViXUVf<+LH2;*LTXxOJAP8^SUK} z7Vlm`J!efVESYynx%hmzuCv~fwxq1ow2@2ZUs8r`uEh7h(^sdyOP2HBl8diT*>iR8 zy`*i>-rYN|$M`#=Q~o4=;yz&?jKYfZrwm-O%;Kq2c3SfH70Ja})6T#*eR9cs==Ys* zX1U7$itwT0)zc=g?1D~zT2?;T=-f`d_{yr<4Ec8Gyl#0vSEnt@D?{|C*DCkps@8u+ z_xqxzE$RFJ?KX%neHL|C9p6}$`YbudS0#UEo@I^a&b0sL&((=bOV<-)X^qcDikB`s zE*0lZ8NBp;mi)aqV;OPrGxDV+>#;2P^V-MDs_Q!4ItzRn7Fgk0Vj1IfMfpFC`gNAM zqWi9BZj$x0l<^;H%95_L?9cnpFY_8`b^2y)=C{?k&#L5Ikx#D5^{blav+xb>K}&mX zsTcN2tF)(Ea?Gu2d)6c$_D$O_d0l6$ke{-rS~6|5<%VgaR`;6D`>*V}&U{PzZKr;D z*MC;NwY>X(9`#Gx@RP1%@vqZ1TG2VpCw;$Vm4~yG{g5E{4W!BM8J#d-&|7GQXDZ^ISykS#DtT25|6L+5S%{9Gr-E|*X0PDAp zows6*@iE;;S1en?dTzC^S-PbEMqF8?^-{lS!y5HB%0;^>AwYkN>Y1tKC-fvp8 z!t^g-VsXLLBffyuMwQoY4Z5;D(OTQ&3+yY1ssDcFw`@Cn^!#|)>1(E4lkweo9=B$9 z{A8{|9U4EGlGc^-Sy*8CJ~M5zCGWrdd`sr)l&77$s%sH>?k#19@~4$|mazIirM}A= ztIN`@y!2JA|H?~Rvm77UWX-PsZ(LQJF?G<&?kjO^Rq}O~!~Co9Oo8ut$h#iPc)rqE z=4bu$Q=ea#Xwb6SE%sjPv)U!@v8H12g(*j^=vth?jh6J{+fz;=dgvRp!{YP0dr_5Y_&d*;8+BSPlYE}HjwEUV} zx4dgmkH?pn_Ic6&x99oKiyhY09_#V?Um{PP5JepBD>Ed49z;nexm^(pPf* zim(1Mrxrh$y14kkl$XEEHu%KaUOwg3<(5@9<*ntWeG&=TDetaoF~#?$;M8K>zfa!+ zQx<(H_eiIjPo><>Lc34Rbc(C?b87Xf<@@sH!Wl-x+O>XabMb+xJ=d;`&;IJ-kIFJjFRmp1q!)_Yx@zgQOdJjAun@;SyAt9Sl;wf#JuQ5Bz2_Ptqj-1tyb<;_ z9H;nwZ@ErBTf4l^*Wzz(T)3jLmzUOgujQq$j(&M{Th%hqhT~V1cX{P6y`Gi*;PUdW zsQk4}lX~zyztwmz@IUTZ`rPr-?U6i7>pI6>Xa9Bn{EzbFx+Olt&2mbgo0h$dd@r4U zZGK<+UTam>TGnmpJ6g~w-K8;0>(>3g&I12U3;cV3I&bRPpKU!p+4aFEQTLV2+gO8qqHCI!)fvy? zFIZU~NyonN(pAZ~ygYb6al-P_*6BZA7Ql0iHTJ>(h4m87kJh;TpRb<$64a)A>cq8e zCH9y%u5B6Xu3u+?br$%PEa0c!w8D}bK5y?oO~wD;J@w9I*Lmu_%hvy=7S}&mTr_n~ z&`x~I?swYu#_3Ckw3jov_t^zv1)LwiVT-bAPw|JZstZPx-9!liG7(FZIf@ zY=AW}-)-r%ll=V1SC(y?kJ6V_;yT?LTVM_Tmi!vu>%V;A+I$Y+m!lh470D|;UFIjG{gD!>AmKi25opylo3q~B5Im-acs z>a=~CW8_P;kNf-#z)#s<8{C@n#pA*gMw0#+Q|3~7|^5(5is*~Uo>)xyUq>TARE=Q{k)xqu!rPW{5 z85{J&&kfap#zFjj=M6l5Zd;t+xO?gM2Bp)7iVGU|$M1R7(1`qHC*ybI$Ip392(R zZI*irzk&R1fqM$Sfy(IXRKN9a((kAScOyzcE!_3#^x`~s2h#BO<=sZe`MjIVI}C6q zq2zh)K>jw+HSs>@gi z4Uea13i;c>hFSOxM47Nu!+YsNQU_&fFuvB$WH(cF>sRBqeTxq_OonY{uAeA_pAYw6 zoSjho_4*Nio8Ny?c8}ug>l#+U{)thSPhC`We zUjMhG{S8x*?}>)l%HrpOhP$LE8ty}l|Jwh)lI}+8Zjx3sT%c?X-X-gQM;3o=AH*}w z{&zrkdGXQyle60u-{?O*yBp-&an~574^rhqL)ny36QTEx?teb4v3LKA(S9N9+@Nqx z8Sc@I^~$0?&o^uYkD1qyR}otMX#YdAa-Sp6_Q(4lT|1=sWdCEC@@)SRxa-69=Vs3@ z{-XXuq~BeCIqqMhRQ;W*R%jBkoWx&Zgg#DZ6&KWxNFOF=laG*dget~8@9kfSRz2Lm zPRj4!l)be0RDX~1|J1)#B{ln^_2uX#)jylv4s6Vh0lQ_-2lKUMU_X_jodfHY^fNfC zIKO@{?kJp1K0?kBs`B(c)U026KRJ_pfP9dY`u1ae`{8PlrM~@Asc%130sHN|-bA!} z*m`%u?!roS!g@Eso=2~DquPP;2%(XjGteu@V=|P>n7>MWx45A0c2g%zZ&#{rX!$@pqL_&U0WOIVZ=0eJs zQ@(+`k9?VYMW|}@RZ7*)(s<_woUBy8=QZvM8Fz&YJ3)Sv^4la_jk+?(8o+?U*s+@EYC@xPJa+9BjnAx6!D+B-37K$T5* zEzYQ|Om`!9FV3qSf%^#eB=;isCifxtCHEuuC)>yZIi&b(ZCyH4$U6+f9d0f@o1Gye zDZ4nmmGTVoHu6{0-&dTUeI>o0oJl@Fq9352#XJv_v&l!uIYO01RDP`Qp@>Gm?0YQ6 z#*=-Iz}R@Q@6p-asTl+Lr0j*1FCs6d=F;N4zGG^;7mw+CcI{ATE~q`Acu(I;YY!w( zAx{;mTC`z)&3kCWU;Au>Hi(S3F~HkM_)K=Q6kY+|PtGJCARi<#!fF=E2m>*~K#VXD zBdlg&*@3VE_)pm_~( z<;gztvlme_0h;%+KM@(NIYlXU(r0U*eUvhKFqqk)0*5pEJJ|q{Bi$!k-le?1eCusKKy&7Z=uAYfI&#!(S zcV1BaF77PEovRnfovRn%&Pc_bg?-7*C6C-0skk$^keUz4MI`QAy+G~^;?5xM3}Tev zUUKJ=)jQzM&sU#;JI|{=8Fv;Aq~=;7?kwz0_9Zu$Jh-#yw)V z0wTJAh%TVq`AFXRNLg7_9VuhK>I~I29adaWxhOq=Jdiwy98MlgevceQ9z%{MzfWF9 zBKo47abyQMo}55lL0(B-MP5x_Lrx^G6H4r>T%>x!I`bDCUx4Tf5PbonFF^DKID{NZ-b~&~&LD3i5igJv@d8A=01+=h#0wB} zDu^`zh&dI+oC;!2tsJRZFn`UfI05sQ5c5}lA?7cU?}a>HBO*bAvh(j@E))H4l*%vG z&yl|;UnKv?oNrM6i_m<7Y?o_g2Fx$S42Tj8`T#O44m~Um85V~Oi$liD2%@dfus#Ou zgXTGEenJL%}KJRAF{65`T>V^1kHvNS2Ug z3E2~<`7wDZc^Ns5WXV~UoDF4Sc1CGf6M$IbfWIbxM~a;WX5S_MO8!k)yCJy=xhc7Y zP;G;GVqSS2=7|O6m6#_)o&Px-6WNs7G-N~~u0WF^5nUix3X_+LcW0(1FAEWA=4Gyy6&JWC zxfh8Q7c^LLfmm^YSaE?^ae-KIfmm^YLyAv;L&@n%Wv-XK8aRu5n4C>MLe3%K<;e3W z`55`QFr%ebYHx|#=^%;QAmTQNxD5^`5w{^DZi9&1AmTQNxD6t1gJ-B=-S@`sLWmd+ z4dMrg7!D$agNWfEA_|Cz0wSV-h$tXpIEWYyP9zb-A>UklKHVFmOE`nPjl@ba-4&xt zcs~grg$y4B;iKRz=6sl(O+G@-5n@C=pBAdRkWFM)ay0pU@>udX@_6zG_PSZjII{nbWlV>Li+sy0)bt1Z>mY8#v=3{=~x?bS|d zXVtETsRPw;b(lIuovzMMXR5L4EOoXzN1dzAS3go0s2{6K)#YlO>QLj=1a+mlR!vg( zs|VDBYL=REV%XVhHvoO)ippkBlY&AaOF>O-|iEmlRXw9!?%M%U_k-Anh@eRN;F zx!yu=skhQw>uvNvy}jN^57Im9tMsq+oBA!iQ2#@JsQ;-K>3`|Px@aO3o5W;HnJG8* zW?Qqp+0lH>EHDerhh~vkY?U=OvWd;ua$9MuZPwP=2HR+xY_siV^S0IYvHfg+yMf)v zZej=6&FmI-E4#hj!R}-S*`4iRyNlh`?q+wld)U3w-P1kNJ=4A5iTkAcru(J)r)_B= zZBK`#2c!q42c^T)gVPb|A?cy%Vd>H7+37jydFf^8<>|PzBORYkNUun*Os`6>POnL? zO(&(-rPI@!(_7M8(;4Y)>95lJ()-hy=>zG5=|kzP^x<@N`bat_b5+^svg6B6C_Aa_ zl=6`k*H!+js=BJCssp_ zI<0C<)#+6;s~)I&u)4WASKY0;d$q6bQQfn;r8-~TtGczicXglYzSaGz*Q=Rc^GJ3~ zc5L>%?D^RXvOmsVn7t@_arTnzrP<4~wW?h-Y0yj) zxoiwrrw*b1F0fV|AaX`DS+%#wWuwVm!AjKwRB9WtiR=Tqvct#&g=sCARU3<(8A5JF z{guKpL(Naf26DDAJwaI3jhd6mN67Ki??(0pYt?YdHIxqmQ`HE@s=w$nXMh!I3z5@i za$B%Y?F<^Fs99eae*ng`n=8A6vK4(9>s)p%y+5UWjt7;q%RcnRH}N&m8y=Kex%&dWzM85*2C3gB}vPdImoVT7gB1Dr5Y)Hs%U3b z@&U0S4#!BTk5b*ql&k_>ne?Ml(#uNqC0oc|q|{KU0i@Jlu`NoiM|n$7t0T~tnKpYmeUrXb-=*(G6r8W$*6--|OdTTLZf0+@ui4MEnNeo6InG>cE-{yy%gjVG$-I;t zmyS)(VjMabk?8#NN14sbjw$M%`R4zg!QB{>yRfs2uCNpcg5BsOe3hY< zPs2a{fv;v(zAK3KJ))gx42wEQqtiPnEhWnh7$RXMEiJ!nShQEEL{<5<-X7CBY* zhgD8f^{~ttYI|5`tlAb9I!A2|E1d`Z`TBe{5Z1atZ2^m2sJ4RDE>c^=a+j(NV7;qU z0t-%5y0Ay3oOR4-WbCRGiK-U{BO?@}o&d#~yP>%OUKVd42|V_5lZwH++|j@nee zr{7bxuy~zvuzI~}gynZr6|nx^Dvuu67u?V6r)tm>ZQv*~3aO*bXqBQ@j#CZjnTu5w zdgl_=f*!gQ@@3{S$P*3DO3_=Bz?aNRsv$WpIZo9{&tXUX|Jl11IGd{PzxF;e_uM=8 zweOf2V+;+(n3s7l9?APnNRlMUJ4FadCBKp+RFWi>N|Ilx{N(Rfk|au!N|Gc=%#0za zq?g?PcdvUd*SPaU>6h7`S$myz*4}IFefHUVf7dx@25Sgn^i#|!h=Sj1-U}XAkqm1+ zYdx~!THc7K7Nc#WL2t6%M8f`^{X2@lwLMB{jz1iKP&TeHQ8Rs==>lA77d67w_E2rC zACc4m^ZsJW!j-?5Dr4rKia7Rc#MI+43Ld437zvM24o1V{R0kvC3Ch5zc!d%$GTx-B z7#$y>)W_;$l-iCMd^|?VmnfC5@}YBB9fl4@4OP+OhGIQ+Fm~{)z=*~yfS50KBZv;; z4tG$0-1%1$5l1U#R8MFz>qz{n{zGDsg1j(RJ zkqr6_$)L}X4Eh4epf8aO+KFV+S4gdB7m`U|BekO4NG5%Q)Qa{XnY0(F73CpSpE^xStb6BDKd}6QczC%_Q)(L@n^iA{l&& zNTEoPDpFB4O{9TO7wO<@i`w8bL zPHZh&(_qm?v;p5%v_(tXiFRmd2hjoTx=dV#IrMUIIcP7@i@J)d#8p&TTrIA~tlCHP zfxMsS2dd}XVPcRN1f3yb2qeSAFz|Zj9mX^7L~*0I5oJe-QIL-oqiHLeUEB`2p0Dfhd_79sA?|?WPH`tR_1yg+&)xTnyT#oo zHCarCrk=;|6;s3%@Om~M#k2VXVw#wSvU*ORD((~a;jEt7!+2(&E@p@su=t>O5E4Dh zPZAG_haj0HWco_B17PBFFL_7k?95Dy{qvBEUdOc_?o)Aw^A6^x17f<79>>Xmh zm``1Jg=j1m;)zaEu}Cb!O0!rjrq1Fe@eM%go8nE%5^L}@sIgcl)}idX;$8ZeSTEL76!6S@beGs5-pA9ajbbBW zd>7Eb21a0ai1Q^X;02>yI8zK4!p7rTic#gE_*i^K5YC-D>bpT*Bu zn|~3%;4b)8{ECtPoA?d<@8WmxN5xU_e~3T89}~x@rX(q;JJ4JhjRT^?>Ht({p_V{) zR!D3T&jo?-A|P=|7pPu|NApTNMmCX6$Oh!slw7izY(@@Xz!q3{TgsMzf30LIij=Ko zYv{C-?WmS)FWY1F?I1f)McGkyq#nGMUn0B6E>uBYA}^tfcwMi?>v{#*L-v6D3V8*k z%PZxTlqIi{SD|cg*&FNn)$(c@BKycbsOK7a4fwvYFZh14A9VW5{?Hj92Y??a2ZA3Y z2Z0|f2ZO&>UJHJR90L98+`3?w(po57Eh z<0w(yB5$D-d8@n?zTGBoqk8goc{|SjOJdI?@053<>_j<{`pLWGUDQC{E$@c>9(fPw zy%PH;IaN-D-Dz?f>`s@{!QUtE1Ao7~pBl>t-=AxkxU;KIwV+JS2UJ@`4Z|}B9}n2R4&C; zdquuN&Ezt<4E+De{{z2VE(iZ#`Css_$=A@X6>wtOx>M_ay-U%=K5 zxdYdFr`!pzzLHQ8Rha2JGErtcWX_(-xh84Wcuz`;-BEZ`XJ9s4UPQwY_ZMexWJcb9ff>8l9 z8hc8^sAyCKtz=XJt!z{VtzuLGt!`8&)2Lz80H0_ig0E@R1fOJJS83ETYJpES@Q#F$ zVx)jiHL%Y#(u_3l=|(#E+D2{g8Ab;9Od}I~mXQTM+sFoA$H0!%sB6>(pJQNOYSc68 zfv<1W2j9SG0KTEo5d4M4h2R?*jVRK%$he4XMq{Hf_$CHsFhrf2f^TLt1K-?e4!(ua z0(?uOCHPiGEAXw2*5KP1ZNRrR+JbLqv;*JXXiqf}tLi{8h*xz4f3a~f_)bPA@STm$ z;4d*Qp(aLGqbs!!`y%WMs%9B#8A?vzja#U`>Wi4^#e`>sh#AJ4SC~C%IHFru z;vJP<<~4XTp|3d{{0MV2_%Y^K@Dma9)hKf&_=n7SkR!4M{%P}R@bk@Q!7nsl(9cTD z7wIa*y8Z*Y)Lcnb5${?<7bDWOo;sQDnH%Y9GtbPU&St)uPhHG!&2PbfXMRWN=27z~ z_+#cV>S7gEL4B=GJW;A;jj~2jHEXmrnl7`(SYya(jkCr<5^s&Cde#(c3ivc@8qPju zeT-u4^X=Ga+ZWguP&@kz_BY9DKV<)zDm(0s3S@Qkb_}2k9Je{90zpl4%%m{KLylQg z$MLXZ0ofhTI$nolgX2S-{mAh#UGCWI_yqhG$EV=8I=15MXO7RHxy`YSIyydg>;V6z zV<-5p9J|1O?br?epyMDke|P*&Qe$uuj$@8v;JpqnVWSJQHWM3OghrjxDanH&9|k_$ z8BWq^ahl+5P8;MAPCIyw=^PcgCZJD$WZa zPjEH_f1&eQ@I#ys$iK8_qXDS3B20{UxoKQ`ndbx$zfl2U(f;W z0d$3XpnD+r!S2D-(|xUb2wmwO>K;l7?&0nc)X+T=PZ?9)qwtjRLibJXn<&FQ);$*d zIQKYe>%QB4H$}TAyC=ie6!#R=FwH%UV%-n8XMoPcdu0RMv+(9ywEJQA!!*b}+dZ2y z-E-V?=oa^*?nmiX_X76uCFQPd2zuo_aKQFjnpes~eRhI^;9K4B@pz5i5R7o|# z`&d0yQ`MBNR4r5ss;gS5R#aWJR;{V6YNOf!QMXlXsf}u<+EJ!zui67|cTngJb+Njb zqE#o=iIP=k)tQo17u5xIUV3%5~~GSQ)B@qSP=o3|4MXH^9npH5^t(s1dL-QjLU_ z8`X`lG78UJ)6^I>2KqOtn_y+E8Vf5otDDjGad;LRr*2WVLi08?9yLr*6JYTUbq9Lj zPIV`GV4|8xtr26MgnqbN-A&EaWHp&;sC(2s@N-b0;wM;F8=l`ev51#*5{TJ3>Rj;DX*VJq9 zd4*a5pI=w6!{?QF8XboS`Wx_h6`o0_A(Flt`fsVX;O!c<27azr>tX9XJgbgVAE*yt zeUsV*yC13#VOK|CGB^q|NNrY|VfPdD3G8lBTTsuZ>Qh+UsgKq1v}GE2llXaq^#FK9-9V$Q97(r+!TkM9=V@xY zhxuoiZfD6YpdRYY65UIR^fLgDzn)iEzCcr3b*5856$jjpIn2MtbOqDbK>-dy z!?~B_{-cQJ(V->BcF;h2hzk995A5GoNOb(rdu0Ei;|FJefvweNpqevMMM>X-pLW}m z3kIGMM~kTBO!Xz|*%``2pnp!}`|+NLZ>$9JQ027DyKVpGqRthTqo0oymW4jvyE?S| ze_!g|6#5$domw6k6W+W(w=E@&)xT38o(W$A_nY@fe%~`u-}yTJxjhgVOJ}PG&eXjd zsva$a{}Z(DfxNhO1m>^ebc#B6w)?3lyJu2<*8djMnRNDiUH|AF_+Pl+%6b8@o)0Uk z%$feKJk)$zl*Th{N>%2JF{e)C+69*+=IdO>OE80=Iaxs^}O__-OtIP$HNJ4 z&MmII&KtJ*jYCKvvB2zP;}h)(;#Pp5L?`%s+fRz1#L4-!uF4 zirxoc?kL87z*k5@^Em zhxV3ht@*pQw>ZCxy7mEiATO?tf5N%)?ww2O8}ILXi+oq7q_XGFm#+uT)iDjfN;NN? zj{m1qws3EkR99dvFI?{Y@!9Wz)4_42^6o4@Ln)OH{{SWLk-f+9O{iFd_xlr=yQKTE zxbD(*y~9K!QVZIL-YzRulch2rhW15F1}o#&Vb+Lu~XR3(jEtFmsbCr z(2FYnb4l;_MPrTNF&JoPsQnUTlkoQ;OaD_9m@g^>?yI!7pr}epzApPm6;<}E$_MT( z9;-FZUv^gQ7gIUdl2)D1#yRdwl*cL$SX^_5Aamzogs$7DkI7 z$NMK7Uz`1Fbf8gzXZF~i;_pfCUlEW8=iasZ_XHo8mJir0t$uNOMfp}-nc#D1L$Q0z zqUsMdpB1GWZ0~IF-X;5I{~5LedxyaF^W~+B&lT0~@~(45)pxGT^|&cZ>>#*3=D1QDcTQ8xm68B_f9nZ(_si2xe%`Ii~^n`ZN`@xejQmA;viCRj>mCElT z@IYzoqbC3lhq#IOZo9;U=9u5&mGs% z@0*un&wadnnZ8Xp{q8~=ip9`+?;Y?hV6D7+qd@t>xxPZwn=YLPoU-wS<7qTCN%bZQV zJo`2Hd_2|=TpsN`qixZBi1_k^Q0*_v9K_FK4}^HO8`O?dZ17!iiuCLYl27BAf__eU z{^#%41DMzTeomL(<51sl2AB5T=fRS)@S*32vefWr>*{9#XmiMUtu(%z?Pm$_jn~A| z`0{7#l*PBw?u|;*2CQvm!aUvsxphiYZ$PK4`p3&*|6U%vq095WxExp|VEcbLFUvS9 zb3ZiBZCIuY%VSHZbJ(}Ql7hUr7&UiPK zuY9PrR^Q)$hR@~mxcE|kSHFvI)%mmk8$FQQ`hTMx=UZ|1dLXys*{l29t=aoiZr5|y zyZ?R9ux_66oAs9R(D)w&+kd3^umi+L9vEA)Pn+ar|i;$($= z_AbfoU7UV-&S@LP?OAybxcfxAg7K36TaqZ>w>Z1OeN>#@SwB}?9QV(7W`3r=Z9G%; zob?VrcMM<*>w9*Y{tfnu{|1%D2Z3Mz|07_z|7lt9y@7kY=x1mVxx=-cK>Yz*-W5TA zBT+vCg`Q96#61-#6Eerx48G@%f4f%b`w{IkMd2GLJ(lr&tZ-caq&i^e_;KOqvTOO- z=*iDKszN`gZ6WCyMDDF6E1hE+_S`$p zF^~SH?gXt}iNN2g#Jf9_gY-_>?+4E5JoFxv-&HF0 zvs7MRgDORx$G_Xvd*q-~$5|~8{4Gws&Y?eeO$>Y+bX+lrIcdM4_a#B^Bn7FF_e=lZ zQ#e2G26xMO{&aevPVR!!DgI}b#l2VR`!=*s<$u2;bbX` z(`ienvL`(U41rlR774UJP`)reLI3Y8=^Z3rtSV5$$vMCO1RNY(2j2HB@*UliOP_p% zcZ5$V$8Es6cCzOG&XIRx?h>Nh<=$1fD?_!)yCHXtmU}Gf%;l$)LmcKW`T3ju-T2@>I@8xbxbCyX z{~diUO#biOp#AQ-=tM*mFc{1rA&$8YaPd3_3(_kNu> zFd*~h>r{DZvvA)6IAUsUehlQ*~UIq#2o zPZgH^8OLbbLi{c+tu61tyro(f?R>SgWlE#xJ(9NyziUgQ`&a5@ zjyFHQOMnlRd$;6w4<$caveK>xXUqOyU9T6Bi}OF{d*E-;10mw0e+$3QJNb|6fir;* zbf*=5r;BB$`Tus$*2OqeZ9dcf1wYp~({-PX`byf9Aoe=pY}h?pb(SZ_SKRZev*l-L z>h*3bjn=uNQ&KHO(m;lE!E=#$k&d5yV# zbCKslJW&n2+kiR`1((AdTjZKhoc-WBisQWti+QJFchTpHtJ8O`_;=#b-XhyoQr&3x z&XRP_<@2HT0ccZ^D^Mu?K>G@x)Bm$M@Loyqx#H>%)OEUfadQmfV!ev0Kj3E|*Lo$b zZ-Ki0jCKWV1?R!XQUDNmWwUZ3*ReJ0D4^?#lhwvF+%@e~=} z{SEcM(F^OH&hfc??N6s&Z;*r|U{r+j(KmZscaH4l}>w{t}YeZ=p~|5g5+iF@iy z)bUrfzr1$!x4}h~EovPsO1~ue`TMA(9xDBL@9*XRe~!UcFy_Yv9|w5Ic@KXg*Ktk% z-}x?(`KNrpefF)MTNZR2xHufEy*)AC;eUpOnCA+Y5B{#B zxb-qvucTh_|4q?lq4a>wPT42Jr@lHa0Do5p%9Pfg?>mw}DPLZ=jVGTy`3SnF_@gxf zaf*|*ArJcd4#7I5_P2;{IN4?(%7Xu=%XUKi&4N?>@s}y89fkGJ-f{lwkab7om+IX| z%t(b34i=WTTyP!b<@4VuZ^`rJ&Rh>*-a9EaeI{zgd=zqSI1_ajTSrv+(R$&`o6$(h@!tUE@p2L%C}H5)ITZI_zk6dURJsu zIQg5Ve2&?Bm*4KH%FiGH75v{m)GC( z<$OJW>$dt#^abiUWxuNH4ZL@HB0sU77dK|kgimFu<6Q9NT-r4RpEy8A-@Z^qL1 z!M^m;>z>#AU+e+z%6)ZoyS#7hYj`^C^KRJJ)Vpq9>+;m$UB9nmdCHxsGU$V@rK!ui zX8xoLtzt}gNXx|v`r~7UV$bxh4hx_gbJ`V7Z z^WT$1UDLJ9yL;bE$mRsj`|^GBPCka->-!cImX+n$yKmp~WzjEA7r1N*d|r+|SXrE2 z;GFlszBQW1eX~9wI}^Eg^}bEsE&H~diMq~(I=t8I+x}Ph;T^MY*I!}xyv?)M1KuP1 za?f7vzM3)j9Vn{}?~Z*xgersk_?J-fvdA!(9xIDJMHGaUN&kONxgg@yCKagTGD|^> z=Doib#2=RhGm!<=gAY&PZ3W3%=KY}{1AU!y%K4K71&xRbnx7=%gMzlF%FaPaR6!@7 zR|Vb9sCVH7J?rJ;cYndw!m`pF2kP>! zE!geNFUSv+f&5^AKbLdwrv-=0>Yw+^g5SzorZ|0X?ta3rr8u3x`doR|1aDsG82w+~ zmLlGH{Hy&c%6{;-m!WjLWt<5^)p731_B&4BxBZc)U&r|x&eb09KDs})IN!YQ?XOzw z`M35b7I!{y4u3m7)%)fCtiW+ua_{#2^~<7vrgXhq_ct#5H}B6>-DRx@?`XF#Yni{h zeyDd5fE`zqr(LJkwZ9A227V5H>bDD_zYEiLPpzjs-V|R3Ho6zDQPkP;z00X zqH6v#1^uyBnpAMV0hjP-*K4^mI}B{4G$3zZ_;(zkpD0}?AFK->il|%j8eCN-uo#K2rf3BFd=`Ze_0KPdfPT=c# z%v0{GQr`O+eSXRuf_Z+Ab_97rX&nkxPie~r^!_2&zw#Zr!O@`6w#J&84K%e519ed) zrcO{I1?r%1rVdaS8O&=MK_2FlK%;H-nXk_LeV{}af;y-s^N~z-4McWOlL*vBbwQ)8 z9YKlGndUH!U>eV~B51U!{c)0DeyOImn?b`V6_iL@Cu+zv3p9c?iMU<1&X5SwHALI) zWvX?eZMvn=wriR8WvcB)+jP64t)DPIj`_9BCxa4YF!i;%7x-wKZez4f_iD8DLr@R- zYGcoBwOIZj>ojBPW}R!8*R@4kC$r>g&`54ev~`1)o0sre-!wmqS#^*N^NSi(JET?yXFV=UULYlt>?vyQ%|L1@3`p%V_YCJSHPa_qLnbfkxYW zJ(J43&u*0Ft$d|yzP@e6XGgMpJJT;TH3x%+^W70`-3(rlPha;{v~>ql?rqxz;7zh= ziA{SFZT+0-^DL>Rsd+6+Zexkblt+bCw=UYY6jV`9P$$K*z)w5^c5tPt=4d*KC;tKH9>b zTiP?fpXmsu+zJa{FAMjZsjqdk>+hPHK0cS_?3K;QydE2p z!ZdGv9h6Al=|r_a9sYYE2E0jnCc!mfT7hXY(~Fquu|zzVhOtf<3S4&k-{m7lF33D zlu0(KgJh>1BnLI1CKyevsSQO@d!!h;7^xz4rOPOmE=P)|E0C(tmDG!>Qg5ULnn?Fi zHJXW3n`Y4*)H|1+q`EYp7SVpz79sP!MJsm|FO2?3f2{e;#5K>4QF2Y4P zjS!|VX{3k{5p<()h$tE*VnhtxCSpY_jTdnuj&2tCx*#)<)`8X`I-D&jF(@?9pYbdr~F#nDfh^4#oh9I`Mr2R z9yY3o8Af%Zkyv3gHX4ghjHX6svBkK==qmOY9~vKu-0<1qvqhfeddu}9-|S@e5c|wt z<^XZne8_x495bIbpO!ZBMe{`&VZLmxly-BKxkgqp*P0t;Rr6c(TUpEe&iqa$n@7!~ zGR5k&I%TT0g0+H7vqoEEWV$uZ8YeTX@z!{mX-%=F$SiA`HBDw)AG1Ct>)5B;r^~wb zr|nP69QzCQcV#{MA^Xp=o5Sv?DSJ6uIbN4HIo3Enl?NT4Id&V;anNzla5;W={BF1% z#~jBD<&;ioc%0$Ra3j)bbJ~mwPP@}?L^<6~w-N2E=!`RBobk?hBhH!NY-m(=4sqUT z)!^RBth?-+Orsk@-#uI9unrF;YPpSFFlWKulXv|lO)QiTmYKi)f@q${WRv9m< z)#`2IRrQ|QXslG5)Q84uwOM^`tWjU69mWQ=Q+;D>RC`sfv03d?KN?%qPwHpmD|J-; zVeIy}JZ@u;r?#iIk?YCwWEpuRWpAFd(s<5F!<>ax8LOP4j+nhX;Pw0!f%z*5Gfpie zJ7%(E%v>2r{V<jEcMtrTg5;okk*d*D%!Ur04edM|+A$l> zg`bbnJoxY=QWeaM&!Of;NRsDAiTUwAm`Rr+NuDJo&yo_eCJhxWkxz)~ds~vOe7WnxolBBIj4*Cp9 z(l#UqeU2n)JCcLGK$5fr$$|O!OYnL|4(Ay;foJ3do{{_Uj9i^(Pe(;3GvO_zI!|VgAMpE_nv;!83Rd zp22%y2CqTcB2gq#BT-Y-1fL|5z}FJBz$c4j@F|$(V|bR2;aNV0XZaYOIxCfl(yd zVr{VV+F<3i!OCkxMXU|IsD-!+D@3g5gB8Mx6`~(#f2x32S#860vVYO(1 z)#66zkHVVK0&B+2;Kzw^WD&QBTPR-KDsCm47%#??DQ?G#V!?`X2N~i{tSj-nuGn}* zvG9sw@QPw!MVSHp2eGagSXUkbKTFI4KU>TO|A=@5{2Va{{G;Mg@N=>DWMb`koURd1 zUrYK&SBC#^Ph8k9g z70`Sgt5j92Qg1+K71pX~tW|G;uEC1c3@g@J&~;e1BC&3*rvc(U@g6zF2C;#9i}%I* zR99>i8>xc$KzsoCCb5a)#E0TToc&0AOm4ARY=-0$@hSMNVk>k$6Q6(jH z4{EqZUIV_b>`xcS0dfE|2g-ra93%&UA1nuhzgAugeux|b&FkcKusB=}r)W7s zj-U#9Zvjt6%hAvrBgar5>@dbrQ+bQLg>vMr@>Y0qo4k#B%kgqN8P?Y?a z{1?T^I{;>)^ySlTq_M@*cVvdzWdjHC;}JC-=$w z(DwV~{nS@JARoZlS#lPvJS-oEmDzGOYIsCGf*R(?Ip80akAlaJhg#_!59l-U8CYB( z7r^3k@;T@%l8d18f_wq|V!0Un%kpLLOXL#pOXX7Z@GJ5a8X%X+W#Io${vY_|ayhQo zf8~Es=d1En@UO|&z^{-i(0i}T*WvR@xf1*v@(u8-z_X59Np8KawBentm)l#?{;` zH-rB~egb}r+yeen`6>9%BRSveJ(#ok9{G(fMkcQ zWB@Z6!Vuu4A;IGZe3%giKHLDRGAxD#ylI%=t%eo6&9H%wFo3oUyI}|KFdX2Wh7-KY zaFN4s8*Y+@G8A}^0X$|z8j;{D7!|-r8ByS)jcD*OMhy6hMn&+kMlASBMkVlZMjZIc zMrH8vMm+c`MiubYjp}4KY8W-ZCmM<1YZ^7dCmBiLYZ8hjh04fwW3 zTk!3ScHr9^?Wu~X zueQHS6*V59SRjF`$l~bj7(nrkfex(Zj%g08#g2y^3&?al>v$df8pqqvS?gFwtsU<; z-UYwj@gDe(93N8`#}>z@pr1KDgZ?(hHoD01xnl?TFC9C@W2?T4H$!j z#ux;s=al5q7y~>o26$i$x=>>b3IoQd1RCdzgB(Z$IzSqrL!2WZ8R@(cnxmX|LT9ye z4d~m>w;>1ifDW(+31E+k#oN zL`qh7sk^ANnxrOCTi}y>sH>WyrcigFlxfsUO;^*Yy}D1`M-A2e>VCRhJ)j<-PHKjl zL3PxF>OpFwW~!OgKs}@$qS|Vfnnm5z!|GwW3JB*B>Z#_aIdp}_IdqxEIk5PYdJ1Kq zR!_r|`D#8qS)dl6{%6&*sCl7UhUrqApk6@P#cDCUeNnv#Z*{rQyHc%0{cor@ z;O#243f`_(tKsci>MeM?My-LjZ>zUq@jdk(G&iUX;NMs8!}>FaA7PqRcu=tt!3>LSkZLsyZ`W&{tP+!2-4z&ZecB-AQ^_BVx zE#0Mdp`~A|uVHJq+6`OZsBd6vui6V+xhfa7_NjfaRiFxBYroo$mL5<+Bt0lKS#IMqnTjV{KGCZ!^oj1o;m zy>h^7l-Pt(VkD!)Y{rK*86RGX=v8yntWlzaQDPNp3!G?B2c-HyrX8sjBgQJ!g)V_T zjT>#ijoqMg8Ip~b#ZPWv)9V5y1h4aSxRqe_GEq`^qipq)r2eTCGDb|IPcHBu|ujbzd{NUdlOl1Y1!S~2phLcbtY zpBh7%6f@4tR}7vl)@bFe0tVh%|-~X-%OK>80W# zaS_l?W5gye6-`7F@H#?ysc0sefo~~Vl8Z5_gE8u0#;6X)sHSKq+5z2l5FOAi9m@>h zRgF};GE%LKSmxD0xxsjKfEa*itBz}S_2X5IRJ)21Vg%$P#YmdSsI@Yq)~;f-7>#J_ z7%_(KWCUB85o{PE*bBsM;x^Q;5v-jNY?zoJCQu#mFYzzLYwrM>4P!KWftV;JBJw&( zOrrZaRvIBDi^rkF{S7zx`M35SV?#l!GQ<6%4F;V{O-cE-bD;xX|UHD)B-N6ZuR=yvh6 zc$)42DxObW!~(GZXEiEr%Bc7v#>1T%2`7q|#mkf~UJ&Pcc#BjH+%gi{y^*8>vX zjI*DJPv|nS1xVP*NVpb|Z~z0>Vhr4XF>nXQz_l0yr!WR~0t0`A=)*2xU?*eX2Ef33 z!0#1%sh-F^j)CuC3|vd>6Z@zeBVi{a;acK=IDp9dL2(cf^zX!Xh^!wHhv3imh(J5V z4+1Lz<76k}NIhzr33?t-hM#wRYkZVefjk^OIhtW704usr` z5pqi)WGf^#;N)J6lUqucbWuwgDI;mLtRO4U7)H)EM$Rrq&JIS-CL?Eqk#i&?XB%VY zT8x>UjF~G+jhTDMi{-^Yuo^8_kQyytB)iJ4R84l1-5}{9dw^=>oG!1FR{~pV(revF(O z_%X9a%N69k@?OxXaw`1P$T^CUb45nZQH-1$GjeVqXUG|JgM3gvNVmzEawhnPz~VePkFI5;JwiSup8~J(_6Ww? ziHx^XGHOd|o~ei4S$ZC|^XKFUgls=Lzh65o7OWjJ+>n?A?s9_eG4o zn=$H+V$?m9QFk*&-9s65H)GVD$f!GoQFl6{?s|;6os7DjjJhi_>W*U6U6E0D6r=8n zjJl&3b*D4xuE(gmDWmQVjJlgL>h8d(yD6jY4sxs9ineI%-GWhf1xDRYM%|Y%>P}?T zox-R)kx_Sw+%0$0b@Che4X&C-;MXw%k75LVJtOd&8G&EV2>fP7;MXt$ug2KBf;=b> z;<|q)fsW)Md5HQk8gC$fls`hEG5Ix&$*VCYcQGb+FeY~~CU-C}@dWHW+UkjI<5L*al;4lQFiz7~5owZ7{|*8Dkrau}#L<24ifKF}A@N+hmMw zFvd0+V;hXIO~%*;V{DT#w!s+NWQ=Vv#x@ya8;r3{#@Gg9>`3Dx<07&#(vCEm7)`)y zydBAS+s1f1lJT~U@pdHRZ5!k5NXFYX#@msMw{48KYck%BVZ2?F@pcU3?V60YV;FBY zVZ7Zw?2E83sG4P{Whgl`j#&(JE^bP(Y%<(GWL!)uP}SkaPvy@N(yHj?gkDY z4t|6=n%w3Xb1e9Y=3R7?Imw&}{vmT7;V$U=4sI!@G=2I6&@0}UFr!#u*Y#uX@Q5UPQ3hK*9zLqu08b#HB~Fh=syan$jLAJ0pN*Wm^BCMVHMJXpa47)JOWgrUN~Yn(5g7AM}9VYKgY zMgZ*#r_1T0`xx_EoF1o#?si5xBWap5${B;RItpOnD1e8f0Mc2-c>&})79gD$I7Gdg+_T)Xp!2Z%VH)I~?Ve4U?m6x`bc_2@_oH;Hdx3iarMVZn7g3!1 z-|m0IpBLOO0R7fgb!ni=Q8|>L>Zy8ENi|VTfQ_4~rgWuhp;}N~)k?LZ>Z-MB4IJJ^ zwV@2vR<#AXZl~H&rfRR+Q;zDO&>QMvbumS&PO1~oduP>|l2jMf1$ADcE}>M_RduB} zb*Z`(wz{cql%~3??$EznT~4v8hw4E}4NwDMYmgcQD}&WwSh-eR3oAp^5LmfRT?Z>e z)lifgriQ`F4eAD18Lo!I$_OLyqjtH#30&FW^f zeViHx&0Ey1(7a8JM-3Cy1X$D&qMjTfx{@PAtvNPSSKY1drsit0noKn~PE?)aL~Yf* z>Rxy|RZXQq95c$~m{Dzx8C}RRqiBv9C3DOuiDO2UIA)Z}F{3z+86|McC{4{)vuOZF zj-oko6ssOpkHTjiKWfPFqt@z4^(1_FMm+Dw965^S$Wby!j*>WXREZ-;sT?_q z1saum&xqgaj{HB{@>df3vDqd4_}`T*8-w5U2qi`uG>)JL%UvHBQ2rXxq0 z9674Zk)vpi93^q&s1iqxQaN&zz>%XgwOwsT|LFKpG{=u()tBl^^pB1rHB@`l9@y2< zqUtJ7<-tn6%17&T%qWv%MzuLw6wT41WR4akakQusM~hN9S`^38q6Cf>rE#<TuK7*j>B%o9ee7Xt98V5Kd+K}YQ<~>8PY;UqT;aKray(ag`Xk1q-&ECa zS7qTDrKNS-PTh@F18x~L%vdvU(AYZ0FQEO5-Pev9G}PEUtlya7VNukoU%z2v!Y%#! zj~#89(QoLG;o+|S!)_iN7SFUg=;-kE1L}+(5SBck-{?VM83P8~FfzOw(}@GFA222? zXW;M=H-t4BJgVP-@TNoh4I3OjgXuh`iy=eX>xK^w+c5fu0VBgc8a+CzZrE1PoUk3B^}}|9HVDff zeN+F@VFyRwG;(y<;W65)-)i2;mUK&wrLm>8rIV$*rMG3EWte4*WxQpQWx8dS<#Edb%VNti%Sy{y%SOu<%MQyP z%K^(_%TY7TbeK_QyqRdGn>l7`*9%gsgqwMkaM0>hD$KKf9+TO|0-`?Hc+dj}f%svLYsb8E` zovoeM+sE4{;mOM^$Nl!l9m5*%#ZF*;m@v+BZ61wQq4uwC}L*u^(_8#tX6| zNp`-tb%HbFvTiLCoWosJNw(ie%)}l)Sb`Coz zOiR@=EmetHs)k+GqI-gScI13Abq#8FD;#^O>v}x>JGW?`;F;g~l1>Sp-CbJrNQkW7 z?UK$3k^Ol#d5Y&OarU^`IFnxq+D%09bW0}_S9K}4C?)eS0w&xen49^kJOg>wYX(gtKOw&Lm zb2@*RX7h0*-Z<6AS0M(j^GLjDtn+#FDCcuHHz*!a-l~uo^b_K~e}D^v7M{-HeOAps zP4f`}U%pxm}yoT`OwJkhJ^En)ubO3KY9i;E* z5dA=z-L-vg2SNkNjH$0b(8{k2X&(hFL)LbBfI1HGzT;rAn0A75mIl_j3aza7!{uMuzm266Vih_L6=J}SW5UDIef-etR=9>CSaTG#jh`VD!# zQRq+Pp2NO8s*mqH1|#c5P4MTF_?n2Qj(+`(r{t{f-t5zNf8;OM%a_MB_vIDW`p+-- z=ga*0QhyG7q5X-<@*gks<*_sTxxZYcJAB6t;(YmqV|{t@bogaOds_RB-NSr&g@gX% z{=PhQg)gr+$(N@k`P&oaJFYO?pO5n8QC)nwJK2BS)qh;opW|t&_S^0E#~tfGj`8RI zdfk!!W983X{@mfu_1oRL9<+gTi$4e6<74U1p`(voc_49F&!_tHDgHcg-hZ7j&UwD__^+48 zfBhSfyvF0c<7(Ud zdaeC=TfbiSlk*zC`HwrDoG1GGsRkk;`Z`y8$CoF(7a;4e4HCwJfB zlRKCB^{u|#dDO4h-=FvO=Y9NnZ-3s)pZE0VJ$$)q6>{7Q?mGUwu|IDMd$@<(%d}UT zi)sWejJdwxq~<(&Z>8HW-SgZ_{M@VV4e%LftFM3-b2acrvY#7%oLe8@603vr)v_LY zMISdCaTd)P?j7!f*s59JrJ*b;R;9As8CfT?y=RnXvS+U6rN};!V|x=VEb=&{jLqvu60jeaM3d-TB=850we8q+kUTR7z=!D;$IpmgSY<~1$|{TEH&EL{IM#B zs#>cKshUuAV%3IKAFtZAs&6EZs&#$hlv)#N&8)Ss){0u2YVEFdBsn6vYI2?Awuy5S z7bmVt{3vmE;^E|8$-|Q;CeKcOK6zF0=ClpTxyirPv?RvXjIEhkvvJKXHT%{aRdZ6! z*)e$q&>5kNSsY`25 zO|PEbF!i0(?WqUTWLivGYFg8@ZfS$lyQJNkc7NLZr0q!u(g&vBnsls|s#U#KPOY}J zdZsPM7u#O!ru7}5$ASerS}XRD4&Heu;yZ~Xd|i=@Zzt;G-5CAl#6@@;rYSX}=F|dj z)#%byiYQ$fZ`+(s`Rb=xKI$~fS1e_DjYCfKo~_83wHJAM@-*b`5oE16a7wG7k}7zw^QoLom-kTppf)GQDk)W_wSMPg2~eC%nKuXLK_<4?1EmD4PLK`G0hJd2%}g9^{# zMa)0~ks^_V-&*(ulF1(UGxmkq11$qc)SYL28+;#WfS+mo0CXb$7Lllnucjc^I04k! zT~qHd5_Ou>&7h5F9B2;R0-8a$f+o{#pw($S)6t;ucr#MeiJ_Z76^#Xr;Ieq{2Yi^2 zsPmY>lg;d3@E)MZ{y|_Tn0)~62a4=md`qS&a9;K*CnLB0_AX5{mc ze*~YCkmFqDY~&O0`wo8B;&%gn*W-5+ekWlB;3{QJ#IHVwp38*)Su2naMh<+O*&jK6 zGj$&V=Vtc8@hap!kgr7E4f!(UU63zE-Vyl%T%6aAI30y+9C13H=LuZ*S0G1@brn~Cd@ z@jUYJ$QL3XgM2>nVffW;8i?cB$a^E7iC=AN2XfS#1s^iElFXcdT4d%HprsAKNHTLX zNj$->i?bh*%s7;B7~Cdszv&jkGnsK9BOlxv=yu8M4sJELuKN0-Ju-V4?hTO@MMn0x zI@{}@bXFu8nT<1>XSODZo-y3%I)TUExp8;Y34Bw$+u0s(v(^xaIBHB`mbGRh%R2KS z95uqx8p~T|mUR}68e;AlhWSMQ%B=bnW_{na$hFA&K8|uI49@~<<4Is9?BadV%psY> zGsk4!igSthe&J?c!clb!Qw>yoJf+7q#q|rz?2*|!vpSEO{y3t{uuN;F1Dc4HsK&m8 zqoowC`^lF`)*hUhoZ0<~dALKVJNhPbH_kudxzjVzbC+ildLx}I?#vSj5+Fr))`^73 ztjNYVs-3~>I?+Rr;AO~6M{SK`$6}v)lh)DKA$^x$C)cNwk&jUu(2>~@WbxeNnc}(E zGu1QAGacUk0?B=z`#leMW_TX-%!DKtl7~FAJP&(jdmcfYN@fov)AEkl*z&H~#IoM< zp4k-s^d~d3Wyai$c^UIF7G}1`y(+W&lIgkKGr{vO&mEpyJ-2x<=Cb=hZ+ph|nYo!i zWFE_k$clliH)L5^*Jl)9?DRr90$(xy>*Jnijr#$77`JCD+MMHW&jnhdXOP;y-3?(z zg`_s_U5q-E#&0#2=sRjpkOb#2!}5#+Db}5=gJjK^m@&Eb&f2?c=hiOBn2wRJYu`;W zZE@OD{<1w-hH;%XCv9esOy8+fQ77&WNXI}+OSYk2+;>3|++lha^Gih5a#)z5b@6*l z*PXQ+k_mo^S4*;IK{CuIfts#a=1jpHhaA6HKlO;lx?@)fs)kBbNvfv0Kvh%KJvV!9 z@r=W{sbt4DIFs>)%(ZyaWfY!bwa2?F3-Lyb$eu#>jM;%}mhpVXOBqWumS?Qc^GMbr ziol4rWI8eWvVQdO|srva^v~n zAlow*57zN9bd#(llP!@lMW$LR*q)Fvx?K(SkVw^W7~S^owWQuo*o^Z_ZYS9=i7Ke7 zDo#~Kq@GFE$ds>HP*NBbatKf9qYT+_15>S8?67e zzG{8Vy2AQ8p1QtaU1fdKig^&@AjW5fKp;5%C+5MN|Yt#4i?IV~8=XYm8xy zF|IK#F~%5U3^B&I#u#FZFR+F(s;)Y9y1J|C z)S;J_04aa0`nP2aA!CdrPb(1D}{`oZn|!U zZXd?Nf2h5z{X*NR{gL*H_Qx2_{)w&$W8J&8&DuTM7VTc`KJ9+Aig?Bk^Q_)6$76=o zSj?juhxt=>%${;$)>I;9OC@2JRI+&z=0~Mqe$onDQ4ae>_tak+))-bBDhyjN+Pu@S z&amFF(Xh!-Y1oXh=Us++LxZ8wu)#D05?;adiAan{j!21YiFg5>mL8EA*%s*?8yK4w zTNm3oLLZSGksFa8Q5aDivD{Txkyk@<6(xZ3h|-4;xg_PXTqqZ>5rL6e!^T1CMgbLT z#%n}bBr^hSH^eoL?5Z!X5jhbR;ZM+Qzbf!PMrtU>h@wcJ;B&ypm&^qMmK}8|nAD^k zOC5ecxJiN8M>Ga+RA3`xQ-X^WSVYX2;0y&8FtjAtsla@OJqwOiVBXP*!9ng=_>(u1 zgUt%;Ui6j0q(#c|9DXBW)Zlvx>{4XOU{VHhzBAG7gF6&hd-#dLM-9B8W(|EWRPvhCT@LRbUq) z1Bke|@tqpFZxGRy@@tPoJ{fdffi*`z8${ZIoUbNo`5@93t9YorK97`RNJ}AQ-3+*0KJt!I2BB`uGZ-F>$; zPR3jrL^OpQI~>&!_)vj0g+C6wp}?x6iUZFpu=0qDfyWeB;n2&0q%FwP$cju1ByB;C zrG%aeByB;CjT`bfkhBFk78e;7NZNuN3k!`7ByB;4g`5k`3=9KSD3w*ni7@{_^3;%H zZP9Uo-U_TS=KjEL1y(hzb>K|}Ru;K^-~|O%5O!hUaRrtcX&>04z$S+`53EvPW25#B zByB;Szu1VtfmsSHG^BbUX$x{b|IiBqNn4O(d;~L)v;{fFgs2CSwjg47A`DdHDKMNq z8Pe&qg$=;FKBPG_-Xnp`77#p5@Wp~4nF4YIecM8c%n^`A zh8@yIkt_k(2%a#Cd>|mjcoT8OlPw^4&x`~gVxB7?$>_c7DUu@~@p#UcP-LEfMBu($ zedt^P@kh*f%S1f$1q5+e@w@|)2ZTkh0$tBQqA^L!5TBvwO%Jx)P7i!0;LC89^f|nv zW38ubTJ*5kfwysv#6xiK+jv{uz>5lgm2G3dF{Ic9obWz(<>K|Vj90{!h%0ZqN|@xt zE5t9PG9&=JCuF={)@!zLAtcXd+|Uk;K)nD;w6GYjm-VpC-_`+?v_A>mZd2P(DpsO} zB(%)hZ95N?$e)OkyM8$E)Iicc$UWih2Y2VXb8ro~%y>umlmAHc>2RLp+uIsrOSfII zdA{g^aR7LW9fQ@FHuo&Bt~P zc#a#M7J4y+w;lkV(u1>5G5vx&g3kqC2)-2D8GJSPdhpHQuHZYt_kte;cLzTXej5B7 z#>l*_TC34&etnG9*V@s0CUkM+bMsbz6Ob ziaGiV;T?Q2?uJzhG+E$%O3~wS=WKpJi8dgm@K=g9#~ls63zYN^2>Ohmw$8Zv0YN~` z0*aOp70URN99n~{HfxwQ3ZsIt){)kD>lo`etJ9ifoor3DrdczrS+C_fyS3Q5+?h;!MGp);Q~(X*xPz*MC*|3*P?+B=(%SSPnq@ni0Z+|fU5=E zm2S56=!oLMsP+C21>BWxqP1>BIwXzle@(ziIeP~Ux0a0=oRE`b&l{2y*d~zpg(yckb59$^cr;E8XfyA^c4EPZ2v;x3`wQepiXPw z*sjo)!F_QiRXFnudh{+6Kx?Ahy4JeUT4k-VZnxH3o2)I?1E`B4)IvKgd6c&Gob`hB zlC`t{G3!<9b?Z%Qm-UYIo)wxbJc=1;ePn%NeTJ5X*Kv$+^Jo!%wtg7t4zvZ^LeXNQ zZNqJGwo$gx{zbO2HoGm+mTXJGxOciO)0S<^wc#6GL=zJjd_VYM@T1@-!Ot+ptg@=D zdMj`BvHDs2*>bG|FyeCvB%~9kz3}3${zPPTN)6b=yr_m+g-2p6!9H+xFP@6jN{6$VMhKBq}5( zBsOGZNPNhcka0mrLYyHZ6Qa3I)cuHw1*rIImxJoUS%R)_Kkoqd>Q&Oj4$Gg`4YZ{ zU%{{BSMjU)HT*h$1HXyi%x~d8#8;}UsdkJn{F8qnRpGIb!(;s3>Kb|lX)t52{a;8U zEL7!N&cxn+oiDUk$jAOWY$pfgi?jZCi?x;)5r^Ji+C23HL^9D z^gC1`S0|qMr>9{ID~Y%pQ#SG*zBwTce4lzteG#iNe}XjzU#Nei{<-?P`iJVDsei2g zf%=yAP3>@Ptnr!V?^>9Cz#{o@^);+S_@%l_eOcY9{;Bq3?Gda?xT3zHc}Ekkc~>)9 z^Bz_syssIn`HE(oW;|KvsriZVO=GNa1l9|@WgKaI+c?VjjxpYd?}D+*nK@V!X*6<1 z-e@wKjTWPivA5CJ*vIH+e8t$;_^Pp=vA@yZ_?mHm@pWT>aiB5KILH`e9E`PtjodD- ziQCOJb9=ZJZZEfw+s_@qYQk3TBd(1*#2w~7=8kY*<&JV+MSkKy0v$MRp{$MNHNJMZ9~SWTG7PvDdIiF`6YiJ#0*;Zyjj zd@4VUpU%(V)A*TuIzNlg;Aiuh{2boZi&gnKW6-mG>p9Am^psS7i81Jl#^&`LkBWgt zj7{q~j)=*^v9srRKuiXX$urw^Js*>TV{|WE$9-PJ#NpV#=lEt!D5H8a2(gMBH)GU5 zd}4ai=yMU@)>LmYG4>vwlfxb|s^Je~VtbI*VfTRCj3NC3nsT4*!)^k(7(?C?Tu8+* zjJpg!8ABwKAYPaimOczUr?>bXq@vHpVdz!9S=xgX^eGtP;rB9we?${4hK{-;C)&Y<(hz6#@zDLHzpo4@2MnP10+j@%Y~8qxZeauyN!~ z$%UNoed>#+bDUTMUcLu>?+!Bpncl-w>w9$=^mg319;Dp&EE!RXBYg%}Jo&!u(Wij~ z35d#fc{EBa`k{YMIr}d6Edp}Wzo(pibA0jLDEgwmSk7L)Nx;ze9o}=NzN36oF#nw$ z-gBqEvA$z`V}bPCsjshZv@iO77~2r@qw)>teIH-IUx-NW>%M&N>p&ieIqcmLP3n&H zBiiX*sCpkA`dmQ1E+EG-X71uSCL+C$3dm&v+1I;GK#1iYNOkX$q5A~nihyJftrHMp z(TDI%#wda-=BolSdgxjK`H6r;4J{FnYXUN0D5)2c=buu+_Q08>Rdd$1#x+m<6ldNIoB;!{};V^rBI zYC!Z2j9`k_9=Dvb9LKdsF`g=7Etb~E`@kCMhz6}|OFl+>z0B7mZ@(&*vkIdwcx#Wm z99@YqUonkT3%)Ewo{BEUSgweTv5dmCO_8myish`rxax3V8zXDUvLIJEn;%#rFm~^f zjY9%<-O>;1P+izz0Xt_=M}`U5#{$-FeuNQM7vB*9Yck)8BzHw*jab4$I#?Ne5##4B z?5Kd%nwLjh5U{TaSS9SgiPHTI0V~Fu;R=E8xPWEi+FAkorhrYy3TaWsPYBppb8-aH zk0dXj2v`7Ca|a06NdYsOLrsqb>{AzJdTREIAUz#&?I{7fWLB9j3D{`?J860tp%$=j z3)ofDjUMbX0qZcG4}U7~ofWVnremff0`^@2t2Z@=i)D3Az}A{7!^N`to`4mYio;I{ z*Pa)!G*f0cd18?~e_z1HnG(aZ1?+-=#hBv4iPRE4Vp$Az#6K|w^G^hfSQsPNZIcgw zQ@}0>*k%3&9oZ(=66<4xufsARTqW>brTq-9 zB^rwht>>Fz!LU2*S>y?_z>V^H^TlCz`0Zh0`M?$<&UmAjT^4pTOw@|s5ztINC+t#K zIXFnZI$S8%9Cn&d4ihEdqQD!<2k|4rCJVfs0_qE!2f<;Z1oTJv`qs`YkGK=@Agnyf zKe7PxEUF?KF=})o@?7MV$gZ&UVfA5EVYOjr;WvjJ2s<3s9(E$^bi`vI7s4)wT@AYt z))jU)>_OP0u%}@!!o9=w;pT9^i09${;ep|{@QCo3@VM~!@Uf9$;m+{n@YL}1@T~CM z@PhE-@Y3*#@QvZs;oHL-!&@S~!&}3TgdYn(8Ga`GT=>QC&hTrPU2qfQ0}Fe#8wC+W`6~(bY^F>`9#Az5{y_pK)hl zPvRV`Nx+f>>_~jhUF3eiUE+SoUFN>vI=LTlSGXT@SGk{X*SMc@*SVi@H@Kg3H@RPM zx42(&UEHs@+uX0YJKS%$yWDTNd)$}YeeQSM1Mc_SL+%e;H}^;G5%(wVG52Tg3HKN7 zDfd_I8TW78bM9~43-0ec46DJ6lo#*K_u|#OhS%~sUe6nNBg|>=ya~21ExZrkoA>4W z@P7O&#Ht1Aw?FUCzs3*XU*`k(fqWo82$C?E59Y1BjSt~N`5}B5AI?Yck$efqj-eu*5nvrHHS29nyl!PwCC|;reRMYQCfSOmhJ%qgU!y zXxcSLxYrF|95u8gbT)^KaNb=-Px1Gkae#8q;exh-4`x0S2qwsG6J9b6r^lT-2A z`0e}-zK-9?*Ygd0BfpDp;&=1S{2soA-^-{HMzTqgj1hVHFUc8|F-X{v|CWq>UnXU< zUMgpc6_WPPkTVY{gN%_qJX~`2>VHMXT+-HE2Z(G^hSk5*I4STm%>CA$PI= zN0R4&>?LrC9`ZN!r4pD)W$*(oo15z)i3O0wLP%o~8$2H^pMbc&d9y~A4+MUDv?O3st@#_yA~8R;6K!VZu~??%Jt)atQ-G5o%r9EcA`}i zp;d`qP1g{aC)$eM>a1sB>NIfN0ze(6~hB60J-0 zZZ-6-OY;)lOSCW1zeEEQ9Za+^(ZfU&ABH9-x|nEVqK}D2COVmDWuljfWVwM4vQVX(B9JiQg=wv_UW^R|Jwf#Pn&<@lf^h3 zPurJ09skGcD&tc!cTAXL9Al0(k05iZ8CJi5Q0#;PiZw)_x`PyXmrzp%!`jclb-*K{&>U zoFfb_3N8ljvEUvGHoN$Eqn&3}{pNjPGCDcxMNt_t< zvLl~%TrcAGQNVGGyKN%W98JUE0)qH~;A(_FrSue~Sc?HG5zEDMWmpk!4A{u3z0 zoNtEJtf%4ejLLq~ew&2NPiYuALAV^@dv?rwcbs!PqR1OSF4{Yhr@nCha40)+AC7d_ zG1AH=oUnIKVpvDRxPKsvDAGXbT8g|+X+1@-4h1~)tZ6h2r(txS#k|Q5ydkMfZQir(?JU<4HazT)lz>By%QDe)S=EX&;Jd~h9u{Q5xIlE)VvC56~UFkZG^*h z_5!#irp#f<#x=lwO0^| z9I~)hy%M&cYe)z-W+u>@@-l^+B1}k?@j@;fCe);f)-@0oD+35c`>;c{5D#ldz1XM2 zrNNCfe)MVOA!xK%DU}q4e0UneXwQYwI$L#)fq!#RJ?UkUF_8QO{dmZ># zRUd{OhcdBO*=s>-$6*b?xCi5&(D<56drW&xu5@xu3rJdwmr$Z8edG@<3w|`sBa1x} z5F_?N(AzWZIre-Pr+q!*zKqy)DA|qnYWsG3BWkAAe#Cx^(K@}IytA(}&>7|&?u>Vm z^6O<9Zi+X3YB~jZBGPwF`%79ID%|&eMi1UlXS6fUIofG=COfA)GihD-q=v^pgR%{ z5L|r^6meOyEpsh7u374g(UIxMa}+zu9hGQr&5kz5F{FRq(TOu1j*E_~j$4jV0^4+Hmf4m}S9%07 z#o%t8rbJVcX*O&v5M(qgVs3_|%34Sy+5@A7eMMzVTG+_^*gV>tNop8&3hxj;(u!ZT$;ooySae6aePCaBi z7=9S!7W+9k6P;;J%pr3YILn+>@N1ndPJAbJ9(SH~;`^NQn)8nH5ltWWLH#|n9rCa^ znvL}o8&NiIW4`!I*ujMDO7lu{nI#T<2G7#4ykhA`&wK^frkZk42F0)V!uQi;`2rw&o}MBlYnT2PqY_ZIvTsXEHvSX1AUxEHI!<6+jxwb zj6XX5ILQTBD*_+S9ZFAA`fW-{4YH>1P})K1XOxoG$(p`P={ZWjN9lP=VMP{aFHlN* zMX>QmkSI_io@7MwmQt-uB@gRIu#N=hyixkaw9LI60pqL3Z-;yYjISL}p1ms4Mu=~D z10xnB*Q+df@S(dw)wnZ3p2_nLT&_B0Efti9=pGiUw+MAT?JpwiMX#wwX{lUKUpzrh zU^Og`&8rX(W0_-_Pp(1yB=+i_oN6FNv@M~H1zHAy!&_|YBwk#XW%+=FP~NU*kC*vx zuz`tkfHbpCw0wIa9G-4=JiY$Wv(QdtD-$jYE*mZfE*B1WZqJ7+fGdP6f-8nAfy2r; zMh&^2$uQ6OrHVz2G$Zp{z18QR&#KbeU9tBD@6Xe?Tb-tr2~2PrYCm2u<^yRM(XcIgw8 z6zZ1L+Vx+Dk%OBtH8Cmrv4r7wM8G8o|l2gX9BgJL=$&uA>=l9~?>hu&XRx zCFnQ+1Ua!EhC2d>9O3!O;@QsH(f;hn6`lez4Quho^(w3r3x)(PwJe3515zg2VNv!v z_UIwIM-$s1{7Y9L1z^7$XkD~_P9mPsTxUVKBe$+6*(CD}SSnsj^tC0H;;tu`@Z1vHn!^tz+7Awz)e#663>OL)0T&H7 z94-!S6x?XIv2b>{M7U(Q6u9Yd>2R5F*>JgV`EZ4B$dghQ#5%{b0Jf|eI@}Gon{c<_y5MfZ-GRFccMtA9+yl6WaNTf^;2y(0fqM$~4DLA`YRp=Lgppt{=*)kI+Wm6DJk>lMJ;5wk0bgqAZ+RVMqBb2NqsHhtwxUe1Gc+uJ ze+@f!(UsFosU_MH&6FeW&2TMn```}1ftyH~7`C?|d>HNs+)=o8xMOg~;ZDHnBqUD^ z+fO2V3hp%A8MqF(vvB9&&cj`Ry9oCW>IBc9AlNht!@E%|-jc@Q`H{?|de?dH^se`A z@NR_t-Mbi($iiqBa)6Q>jb7MT=rz)lU2Lj?tfs)~d9h4)QH^CG&o#e)S3^4J-e6>B zut^NrN19Enf@_4s{U_o+6VEaJ_LKGwyz_M0uiLxueWBa_)WJBkFyP+T5#X>nq8zb~ zc*i(Lk|WiT;mC0m*yHVE?M^(+{T-tmV;zZTA?c26^oxrfWq6aXcGThBqSbK}Z#QSq z`@QVAhWCoQj)#sX_5t=Fd#F7MSDtfRLcjQ?x8Ap0mhVI{rDfy3yKs#$SBXbLKh=oy(mS&Pw!{8=d={hn>fqr_g7<=)B^* z;k=E0<|F5`1l9N(*+yPWr&-ROZb=zp3M`X&S<*b<`fMIb(59QvTC z_%4u>P>@iPP@b@H{K@fW#-AIHnq~UqiBMo#1nc|Tv10inQybQ6I_T=m$>ub32JFx; zgthr1bBX0u%WD=`-L(vYEpO60)sxloXv49lSoAC2GQlPQ-iKzRzl7F~7G7p5gG{eQ zd)Jr_;%k8x?|zAl4r}4-@!TWw?$QDIrhLfz+px2*!rRFdJjte-XTYNRQdq7h?E-f5 z=(iM-VvH#UDGoOc2O5vBQY!Kuh7^-bNr86}0;UbhYbPtZ^kPT$6DZ)1cXAq34#1_m>5*(~tKT#NaRJkI~Q{$te9)w1q6Z zu@F771hJK%E;bT5Z$JSw=cE@vQYQH)eF2wt zBJV^b{YAJR(l=O#dy>b{3cd9f(hvOa#DV)D`tL2~RY#n|iI!F1sKDELtK%fz&~G{( zIvJ-ATFG$dIDGHO!#iUQWdFGHJY@Sm^Q!X#WdDKl1!OxgAtqrgBsv#wRMiPB3CHj* zbuHmu!ZW-@4M>bi9Gy5hF*~t@c{MR5F(+|(VpU>uVteA*#H)#S6Q54dPw<}*F(H0J z@`S7j#S=D8Xq<3l!kG!36K+pyzq}4kw*X zx}4ON^k|~@M8Ao)iE$I16VoRaOstr=oq2U);l#BQ>n65MJT>vs#9I@)u|1VaN$v2W8B)^zso)n0(4DKmQQkS0f;gSe>jkrq%ZLRdF@2VT? zKQlgjk!7)02a$CmG4E2D`A50ThvX2samg-e4es*io>ObGI=OFhX!6M9#N>?R!sNBd zb;)hXr;;xv-%9SDq?+VADR@%sB>SYaN%@n?C)G|mFzLjk3zKe4dNAn)w$cck95Z?B zs_1pHeWTV#@X@ zty4};xj5zKl!w?X(kCS-Wq8WCl<6sXDP<`&Df?26r<_l@o^n6s`BZ*t0Ao$Lo$`39 zdTQUPp;JdrO`MuBwQ%a%sdZD^rkO%~+=;P0O5CG;RH~`e}!!ot}1iTGzBk)4iwr zO}9;to9>*RKD}Ui#q{mdTc@9#esTKE=?`ZxGkj(Q%@{so+>Gfn@@ACHsF|^E#_<{F zXI!6gf5vmhI^)cY&Kb97JWf-m^-T*+8=01vmXTJNwl=LUtu5_T+NHExY2Da1+;?X1 z%-EUsnQ1fgXO_>boq1s9iJ2E>-kAAd=8JT5dSH4?`q=c;^jv6Ie^s7p0X|l@d$;5J zTBtgd@lsDyr!n68Z2dAutKX|{W&HJr^+%XMeY^e`Gg$wL{u9QgKczp#gutTwx0z7= zck~@hnEtH(9222Gum7AGs{euh3+4^|kMviWIQ=#K&zVvB+xlNKWAu0Re__Vz|Em8h zlM3te{h4X7JU^IO2HW#7%nC!SA(1IHBpGs;ZH8RKBIXExjQ=Kcod1MB#h|x>+5IoE z*}zW1TmMm|bq9Ps@vsHKFXorc)N7B!vcc$M?e>_V) ztM9DPStDm9&dQioIBV^!x>;?rPR+VB>(;F93{{42MsP-KhCL%KBR``&qc-C}#)*sz z88WW1PdW=3Qj&FILul5r>F$!zWHezU`7kD8q{J9Bo??DezjXCIz@diLenU9%r$ zdT07&+A`xZotf#G1(_9@+cR4;Pi9`syqWoM4l~DRPSBj;bH>e?J|}NZ*_@g=`{o>< zbAHbCIrry0&*HNJvZAxbWTj-~WG&CC%4%jtWR1*9%*x0r%vzgOm(`YaD(h0#t*mZr zA@BP^@CUIU*gr`7Ape8%4{AR+@WF`>E_`s~g9jhHz*aSZ*)iE;vs1HkvrDt9vsEo^wCv`8rW9FsI%bB-)Ue&zj zdF}Jg&bvDA?!2eD`dt6qh}`(x;@pk7jk!m1&*XOI-p+lD4YT^r51l`9e&YO$ z`Gxb>&aa!_HvbeeVt(rU-1(*RtLL}OKQ{l|{A=^?&3~3>%o~swl{Y$Xa$a^`NnT}M zQ{K_Mj=U>*ck-Sr&@Sk=AZ)>?1xX7s7Zfd6zo34>;RUA`Twc(%;8DJJzF)pAKQ7;y zpPpZkUy;8(zcv44{>A*8`41N|3w;&_EgZgZ95X8aZvNAS`i1@rBNoOlOkS9^uz2Cd zg^df3EIhNYbK&iUj|~Hx@lu^a5M`1Qx~=jx9_r%q=V}tS)RRJXUzF@LJ)$!e@(( ziw7)@Vn(?iFCM*k^5X2pC5tN;H!VK8xMT5^#dj7zDbg18D+((bRg_eeSyWWCzNo(F zaM9_a%SBy9kCu2Z@mpeB61T*;Bz;N2l8PnUm$WW9x#Z%Kn@b)RGsQl|LB+$1#}!X6 z&MPh}t|{JEe7yL4@%7^S#m|@W%qaKcr2$K$myTJQvNUJu@}*Tvo0qmPJ-hVk(z{Ea zmgr0TOCn0*OOi{nN{UN1mNb?eDLGTpS#rDN@iO(YzRNFCnQrP-w=rIn>krAJFUO0SgODSfh1 zyRzTPu$7}$Caug|S+sKf%KDXuSDs#Zd1cqiM`hk+er2|@xH4y1dRakPMcMYU*0Pgj z7nxD+$7MIm9vzxQuz%yxY8+SwnXdT5Eo8d5u|bc^!KM zwONMZ>%s|QLkaVGSy;mjW5Vg)2sO-B?3VBVdqKE%g7`B#jm>6@v9IhNwuRlR+Nb)u z*8r~ouWep+Uc0<5d0qDYjrZMN+j{L#U%-223Fa`8*^s4}7g>fGjpdlvh`sPMUl@Ll zy-9vyxMldIq08_q!)?Q_4R?&>t$@W&WP}z{T0kk@tAXIn8gCf$>8LDgg8e^WQz*sz zCc@(>9ZBgZO5Y{a_4V5HhHC^JJF63H2cf;5Gb-Ia9jxPEKbPH%O0!gb5wt@63)Ekp z#>uF(O&Y9K`GV^O{Krk0ccK#1)j1Fv|lAY#@#=G zr9N?tL>z7RR?k$Yt7mDp;+}PePYmB-7{e9A4Mt~F8TE`0=F!G7{V_LjDr3d`z)7Gi)8NVV(7`3#viqU88*3h{d9l{KHgIjs+Oca>*XFJ*U0c1jW$m%G=hj|ZdvEQtb;flA)9Zl>~$sUD%UlwJG!o8-IaBB);(FTUEgng*!ofHlh$XhFIvBTef|2w>rb!0yuNGw zqYd60{5IG&#BFeHNZ(Mfp<=`K4XqnaGRYf)HVoe|Zo~8qc^k?$)NI(d;rNF08?JA- zzv1~teq+GK=#67GrfkgFxO`*P#^#Of8_#aMy7BJDrlrj45# zHyzn@W>e>;+nXL&sw?|ehE|TOOsvePEUa8xSy$Osd8+bK<*mwYY@6)6Ie2sIX8Y!} z&H0es&iG>nB=O_RgiQ4A@iZnhe00>|8U%g(?87nuIZQFWk>!q!?wsvFlXW!c3+SpoqZCY)9ZFy~N z?Sa}8wHIn{)IO+vvCX_Ka9hl_vD;F&PM{OUy zee(9~?IqhQw>ND+y1irjmF;)7KiQ$((QilCj!`?3c4Y1-+Od8|{f@&sPVcz9qie^b zI`2BaI$K>_owF{zuAr`>ZhKv8-O0L(bvNrC?qqi2%Q<=;u2EvK<%#W#j7lh5rFagb zW>_D9)n}NWc$$uEE&q4F0|(K51DQeOprepn^bmU%f26xi z{aKuq#2Uz4B{BUPmpN!SsLne)%#h0{R6n>wEnBZ=!78j(C)M z#*Ts=@clze$zO@43|v$JJq`_7J?ojbdBcGolY=K6s8sQUQ&r235dg8K6Mn);Ud z_WF+c&ibzU?gj>1aRxL*HN-b0HDojtG?X{gG_*9dH*_>~Hgq*~H!|3yGoUf5F}^XW zF{81dvAnUSv8A!Sv7@oGv8%Cr7qiQ}D_~dDuJ~O^yE1ka>?+??v#VuS`>u{%ox8er zbvH3h=B9wAsHXU)q^69ff~NAOnx>Yf_NI=e&Ze%W?%fPJi~+l&cE|5d+MThxV0ZcM zn%ynC+jn>D?%dtAyStfbHa7<}M>WScCpBj@7c`eQ*EF{@w>Nh*cQ$u5ckf}aacIDv zs6Fv}lJ;cmDcDoKr)E#fp7uQ*dph@Y?dfh|TFfm0Em1A;ElDjIEd?#*Ej2AIE$uBG zEuAf0E!}&Wz2?0Ed!zQo?@ij9vA1Av`QDnnEqmMdcI@rk+qJiQAG6QAFJNEPzW9Af z`!e?_|_v#(`e`@W8So%_1>b?;}eWof|vsQvN#llEuqFW6tczh-~S{`UPH`#bk{ z?e9LoU^CNz15pR!40YQduvB)XKPn$_eTu2 zMh*BV>ZACNl0M4#sNkdWk7_<@`KbM)j*mJ&>iVd=jlrg=0c}xj@oh zEp6>>9c`U$U2WZmm_z160f(Xv#UDyKlyRuwQ2C*nLoJ8e4|N>sJk)il`!I9Zd^q56 z)ZzHUNry8I7aT4>TywbPaQoqo!<~n_4tIadd~E(W;Nz%|<3CRNIOF4jkIO%<`MBld z_K!P0?)y75!{xS3lj0Vs!S<5E>d1LON zH_qwtCqJ?i9ibZZT*x(ajUm0(o1S?YamDS5-?diJ6^AP}a+c%_Q>tEeF^!v~r9wXN zDGlTM|N2QKpg}DgdJes5y_4F)`xV082)XKyM@?bumDU-N4^p0F#wZDCa1OH-s3XV! zmFvB6otox_%$Xo{O{~6}@J&&RvFBc}0_zVNj3YmcZ5m-0){J9cCIFUUU&lU)M(oit z2%JIS=#A@o;XH|<7r0*m7x}#`M(aO_aWIXM6JjExA}3TAdGeO;m#t=_b^5PDgzm5E~6?a7K?3B(+6G@Q9p~BT`F*my|4NfyCFL zM0(M(BYS)hjzIj$o-RH(E9n5jZH05SXi*1nv>fEb)hdZqBZtHJMIrU7)O23 z@(s`gq@DLh`|pRg^BNF;NU{-nK#Oa5oHJ4D(L_)9fs6cJ79-IrFN-mV#z^LZk(fxV zbX^DCNk5YOKcM(AU(o@$9ZJRucEmXP*b)6%5A#Kz3)bm0Om{I1W zy?djUL>)j75+*T_w(rsf3`&IPfZn*ur2~lOVNmWCaJlOM&wjxFP8~q@2otpcEzti_ z#8U@^|CidZ*bn%Z4shwBf9U|Jnf$-h4+xjCEeri`(*fk&?mzz=|CbK=&AWT|pNytC37SqMtVeT^b+~+GXf5AQh&zTocVJg-eHV?EIUF293Yhin{ zeb`snSK0pTYZz}F$PQu$vsN~Q9m0mQk?c^6Kfb}f$&O&-*pcigb~HPN9gF=JC$W>+ zDQpTml}*Li_WDHUBnh* z9J7dBg0ak{>{Ip``<#8D@=^6x`Fc%Imula@4Bxr>9Q{0fu718gPrpE)uV1Jy&{r8g zHXJd0)o|4CHAB1M>xN^7Zy1gnzG*mtSs*73pBhdXzGXOV__pDU;X8&7!)J!GhVL5A z8NO#YZ}`69g5h(+MZ*samkd8NTsC}R=rsHYvqpYwxN7)`;hN#6hU04F6_$Zupzw zh2if;#>iqmikH#b*vqIkYK&T=&Zsv={`=#r_*#`mzc(`UYZVz`FajgrsJ*c(`zU<1 zipO7#ab@hL2sz5Y8BDXq_qo;h2Qhmw8+kA+h<=8hWxtF6`^@+79}9Z|-)Fu8>zkir zHPjFA9}jDqKV&1F8S!^%17xMwDfo+a#R>$g?xh#s5$zfrP zk(tMuSu>N%`mjFCeAbusW%5`*){j}h_GSAr`D{P7AG474XZ@K1b^tqoS%gva0H%-) zWCNMSY!Dm76tTf^sbA_C5AJrhG`DD@kECvNPG4%qF&kZD172D8aa*|C^WUdDa}v&zfaahO?N!H&o5^0llTGtAdxQ6VO}uujZ0 zuVfQ2+q{ZR9%B9kJ+zYfGrI~FXP&d$*ak@19(FJE;^+AH z#oF`VLqGlj|9;R{e`ouXdSVBW)y`}%=6>#Dt*Wo9zRub(2Xp`%f_b0=*-*>{-NuGt zK4={qjya*b*a*xEy~IX(UG}=nMqwqpmK}=K>_OPbdYbn%c9=J&aQZ(Tc3{20zC)yhjaPT8yV-Y%tgxdo-xM;a z`Jv{A>}1UsnlIQX+BdXsuqoQ<+Ue|6vR0l=#eA|a+3C82x`S*MWGj#T06MmS&C{>a zuVNPxIb#c;ZEvuP48Jkz*}cYKV=()DBQ^zPFA(`-KPU318V&h-pnA{vC*z+~@0)^6 z!K$&QiKdCFufQ74B-J>qAj?vXC-Zt$c2kk5NaY}V>Z+V%=B_G%?80mCM~hdXy^%4h zWtvJtiR~Fv8fL_abh8DcBc@hMFVF*6zp665YY7CchkXPUR{IBoF0oia3oSO#0<4-Q z{6jzwVD&1jQ}lWc>qW#$#b)#0sNZUSLH%qq_FDx$7efiepJE}l71B&oEm+eIzrcdg zKl3`Ii%}jN*ITsIZ?IrA634BuV?z7}i$ORxQvZDmMvQ=uvtaa?@{!$)$+1N^?nC`4 z7C-7wg|z~5ezXM^yy1_xyh{C%upmN?M_Kw)zW{6a$#E;@EEE3#R_PLdktKlo<17P( z^I^z0R))hemI`YVF@Mw)Pi!$@O*Lk|nk%sm8?%TB#hPHu4K?k+%6OC@>^G3Tk4Z^A zM<@+z2-7SkSP58#a4YOg05ex1np$teE)+EGyEba;Y8{$FUkVlvQh{lJRu%a78qG8axV@>mDh#Ym{D9`O^liSf2>Bxe4)}|)QWYE2q zDKwly!?S5PlZJl8=UOoP8~y^zV(Ra)6j6Ua z_H-tAnuX-P$&v=T*D{mb3HBTy(t;ffQDRN7j70ps#w$qKmH!_Lp?SuuG(__C6CpIu zh~4dk{C^>Y<{3L_i17VL2+cEILI^!AU_TT>^Nbg1XaTSv2%&k#Un1m6w@V1kGyaN( zNPM@2&^+VM5ptE=O(8VT_zM~$e7A(qJmb$0a;1Ai2+cG8l!i#UE^GnplAUK%=mFlK zw42iJQ~GmC|469%H(1B<9rbSsC2K1T(PUKxXgQ^)2vwow=*wAXGJTZ_Z3bcJGsLVy zDG!H)41;t)rg0Q69HHF_=VEXUT0}TUj-XA1b3<_y*K>{>p`8imNSx9+aulyZtom{< zv~1*KG!3I2%kn{Dz%xroiyWc#lD39ikt4KpS<28@GETHZ87J;o;Ecv~!+SW%5!$W5 zNsdPMaFRU6_HdFTXb^#u9HHc7aZ33lu}JwOM^Zk?k(5tzB;}JFN%yyeAfDY+NVC0!=TA#U=e>ENE3YN7@NV zftGwvEUvN^W5KgS77MMFp1e$Si-p#7Pb{P9IWd-TZn01)=!pf-B3WK&-S))dk|i+~ zJkw-(q4nMq%LKPrXe;fB1`PZ&;upcXf zkNzdi-%`O}(9@I6?+MNB3FY*J=JkX!dP2oLp*cOFMLnT~Jt4fclRTi*vU)=EdqPWk zLa^K>@MZUe=JtdNdqQsuc~21hX@Z|9`0olnY%9`K#|!>Df&dxD=T z_}EE^#xqgyCkQ_6zvHg#!twipKSuB!g6|akDS|&)@W%@NR|G#<@RJ08y5P?ce9~V_ zGash(V@h3e`c)eK8l|M~nPw(E!8G$RO20uV=~1ScNsl$ne1g(XC_PE(r31nTN9p${MLz)7;@J;+fzr<@Ju0-nvw~kH+{;S(UWGR~lpk6? zY!E`ffli|oIs{?pI8bN_&^$_^uMnO}DOx(hDU^<;6xsy{`nI6ZvY_ddLa!kVjRFd- z4GN763e5-#T@4Do2nt;SI+IfLArOXU1x4=y6nX~~S{W3*V^C;s&=N`uD9xmFDW%gX zok3|Cr7LmwJ8(q}Et?ifw^F*6(sh(pQCdN1Go@=NZJ=~Lr5h;SLuomst0`@yw3gB> zly0JQBc;`pen@FOrFE3}uZP|$kaO@iz0 z5=8d^v_bcX;vI|^Y-ly=KBN9l9b^p04Z81Azg~yEqP!b%<$3Bi>b_6?ow^IuZ_s^C z{dygAFD!A@>7bk8H|n69;qTNz2g7gBLFdA+*FmSkT34M8I+a-M(m{8_->HKxhTour zu7_W*gU*IsuR0yx-QhRtpnKu()ImoRdtW-}X!!LyyyGLkb-HKNZ`9#i0Q&Tl(Bpd$j_dWXEsK2C>3dPXQIFZ;B>#GRCnEXR z?|pQ*WexgPx;)z1{>L`PZAN->A1xf2ZDu`VIQt)UVeMg^&E} zqp9DhA4dJ1`WWgr=-;4zz5Y%3B>%D0Z`6;V{!V=y^&9kWQNLafy-xEFeG9))4}A@P zryhD5euEx*9e%wY`kCGb^env(=v{gr(5LVl^w6j9>-Et8^gf{f;Wz4`r{V9^LodT` z(D#8)@{jLb@Ei57P=BYsFZCPruTsBW-yc57zd!XG^{-KXr+xtS8}zSJzg|BOJ}Lh| z>Nn~KQGcgCi24os!PKwU2g4`zV5NSe-bVeM`Vi{Z>xaN6>!N;x?pM^W*WHFs+QF}>zf*UI`VG3@P`_UHTlhr&?@_-| z_a*gr>h4p&LH9fA*Xw={pUD41>No2CK>eM%Zt6Ga{z(0L-JjqS`F~9PM%|yOzf<>w z`VG3jP`@7E>s9zFWv25P^6}jZeGwV5&)n8pTRFd zlraxRuba%uknUnI?!+DG;}MVVOAuwuu&Stt2U=2r7(C)Z%U1B1Jb2K`6+FE?c+k=n zJg8It13Y-pQWQMF9z19j3LaiSVhu`&Sc7sznU+|C5|3De5+c^198tz2)}X{A)}Vxl zH7G}v@sJu+wp`W&Q7I5ogYH+68dM_6m`NK{@+e~_HR#SmYEX$NV;YEX$Nc}NYq^N<>JM@S7S5hV|)L3bWfgYF2aK_#N(5o=JcXLAz}?m zh**Pi#FdsDQN~Q#AjzS`Bi5jVh&3ojlrf7nDCbeeEY_gJBi5jVh&3ojlxc}IDDj9j zC?R4E$`NHeVhu_>Vhu`&Sc7sz8IM?l@+YIKoaKnCG$cf#6Lk|WBP#Tt}& z#2SWm;klN<3l>N{Cp4azq)ASc4LeSc4KG z)}S0w#=~QNjeB2$$LO6B(I^lfw0CzNACJC-k4IlZ3!UJ8mDVF3Sb$dW4ED(3V9W+` zj|aVN4@4PHACLU_dc^GOaqnb}vU^$vk9bTTJSGpG-X1)?J$PRC;CbDHr=Ld|_Vc*+ z0Uq%T@Q7!C$GyMi5i{OJ6!-4$!Gre}4<2QS`Fo@u=n)UzYZUPiyI}4mAM6p2D7{iY zL6lxO;*u5#5v5m-xYCj%%6^n6y%LWoy>dhuk0`wok0`woB1*3uQN|-muf!utuN-l; zTnQ1SSB@y}OO#%TN0eR(5v5m-DB}^OSK<++S3*STl_Rctmk?2U<%lvZQF8+MXuR9NsUL~T8he)qG50PGXgh;OvQN}~0*PVw*uM$z-JCR;@9-@2Q5hA@xM9D*> z*PVyxUU!5@uM$!65b1U2A-dNcA=0Zvl<^Shb>|_{t3;GB6X|v5A=0Zvl&KTxb>|_{ zt3;IX5b1U2A=2xPh|(+d4@K#fBQ9x?5K(&Nh$}5Q;z~TWjvzvN<5P|)5+X{k9C77Yjws_1rB~t+rB^~k>6IhOctq)y zctq)yBg%UhrB~t+b+3eo(kn-l_by7W#3Sln2@$1Njws_1rB~t+rB^~k>6IhOctq)y zctq)yBg)zlrB~t+rB{w9OJ0;-iAR)PIigHUlwOHPlwJwxizkSC-?*>Gn@eAhx1_#U z&8NJ|+XK-lkXJp@detMXS3S~t)gvt)7DwDu*TNEsJA%<755(0U%kOEYMvwd$J@RAp z$WJeP|94NT7gn9PBd>Vm`4x|=Uh%l9zeigAJ>u!_5zkvKLH*xAAsJMlE?K1B((xj14wTZq6Uy7 z$~Rw81IT$?Ig}%=5|a>71IQ8Oo2IA%h#EkSxHN!-h#EkSD0xH;An}MAK#sUtlZ1#GKteon zhz3w1%C~i*0hB!69*9nX5Dnmd73l*g5oKDW58%#2G=MuoG=MuoG=LIu^{k|?8Ke)O zw&o5Wu#UhY5?i2 zR@4A;#3c!G#Faxi;>w{Maowqeh#EkSxTH>wDAN)(fW#we00|K_fP{z|K#sUdLyovw zfgDlhN7MikkEj9Ui1JQF4IuG|8bFRHuM#zY#3O0|Iif6QQ3FUkq6Ux)aAm>rmyQl#q9#I2Gh^PVNh^tjfh^PVNh>}Ot01^-B0}z>)Bd*pYA)*G55K#k2 zh^PVNh%z2g14ulg29OX@1IQ6&4n++h@rW8gLPQN9N0jw0Y5<8x)BtisDf6Tc;9g>) z29SRla7lt3akWZ0;*tb8;>w{MaoxLwh#EkSDAOWu0VIcV9%Wjh29S6}4Im++29P7J z(vTxA4IoF9`4KgM#3O0|IikE%Q3FUkq6Uy7%Bw^TAn}MAK#nNOS=0a$kEj78MAQHh zB5D9RqP%xe1IT%lbs=g1iAU4`5+Z5ElsizAr(PwFAon ziX4(X8QkyP;E|TWBW8ogT^KxK_VXwolSf)6kF-o4Y4!HFs<+2g#NxF3UG(mKot9pK$##<~s#GQcCA0Uq(Z<`K_p9`U^95s$w|o&!DN3G|3(kVna52EQWD zgFNCHN9w^IISlr=(;$!3v2H+-dXPuzqHdACIf%MNjwruxh`L4M@ey(;N0eVC zMcpFtXoWkKBg!vbqHd9RMBO4sl;2WB-6HXbxNQkIgu`sTh&wBXEmdM&K4PV$;ix2;3q@Y^@@otkh!N>g0=I}|q%{<{#V#Xoix`o%s=zIF z8G&2uh`=pkM4FGlEp{1!Tf~S|FM(U^G6J`V5gRAi5rJF8h;%%YYa+*97P!TJl)x=w zL|Q|ETkJ9dw}=sG=>oUdWdv@qTVMok5hJ$IYexib5hJ!5iV<61*b#wS#E6Ys#E3K> zfm`e{0=I|}TdUd;fm_6gtu@4m^eBN_>@otk*b#wS#E5OoixFvy3EX0r5x7N+NLx(c z7Q2kVEn-AkmcT7`8G&2Gh_ozXZy_U7EF;ZX;1;`#z%61#+JgeO*kuH65hK#01a1+_ zNNXr?i(N+G7BM2#RNxl7jKD2+MBo-NBF#tO7Q2kVEn-Bfm%uG{8G&2Gh>ct9h`=pk zL^_@YZV}5!^AWhkE<@}sj{Pohi(N+G7BM0%UEmhG41PC+#3tj8+0W6^<&IZYj)(_d zBS{fyJ|4aD@#vM04&RS+%twdsZaX3_y)1Yxy=;u+JC=?|(Rf`aMQm5=c6%?~D<8U7 zKIHqGj`^^?v{3yQL~2b{;U09%N7bu_s$QD9^~%`|uW23gaqE?{Td$nGdi8}@ubjPl zLugUt91PC6G{6Rd+BcMrMtdYo$>p4 zCHd%km5$%kE0J;SCF9d8XP;h2`Sd!BjpzVUO5N-7ercCK(BEa(5v)-UZn^0(o5iQyX{Nha4{ma;0YXVm%;A`>ef_@ z*v-RmF%jAA!T|G6IK-5vdjehudXT zJ$)fYq?Sp6!^JXEo3Oy)b{T=g#fUU#fy3=G0*8wcsTKl=U5Tv75;Bfm<0*8wc zX+8pni)EyG2^?;h5jb3oNOKlATr4BaS>SNHjKJYyM4Gd};dU8;!^McSEP=!AG6IK- z5ox~*9B!8(98OmFcB?+&a490Sa1su8lp!20MWp$Vb-1Gp;czM9CqW2@JIauCxD=7* zLpa<~hH$tPk>*1<+);*bxD=6UK{(t|hH$tPv0X{o+nI2*F;Zj6eI$4KHWu#>h4tJCx>u@O|&4;YR9c2iIOA%?#WF0P*k>*U+;f^wd z!=;EcXa8O~6ApJgig36Tk(Na`+);*bxD=6=PB`3AM&NL<<<>Ul#fYseJ0ftn7_rSA zF(S=J;BdQ)z~N%VHh%1gz~N%V)*52OHV*BGz~N%V)~aGenvcNYb{T=g#fY>u1P-^$ z2pld(Y<(d{Y<(d{q%{;c+%6+&E_z^hVE+cTb7?J8lY$=2j#4^&B7dYH5Lu@IIM+qD*mXVev zaJXGY;BYY_odp7i+hqg}7bDWKDsZ@1Mw+w0;dU8;!^Ma+XMw}TGSZv{4!6q$^_(y4 zh``}u#Kz%bL|VGQ;dU8;!^IYI+n5(4w)t*H1P&J?HVzjf(tHFCx623|E=FwQ$Bqab zE=Fu)LyXwQp&b!8T#VS-S&T^Y5jfl~BXGDFk+z1w;dU8;!^McLFT{v#7KjmP4FwLj z%Lp7UMx;3l9B!8pI9!ZKwGcR5EF;ZX;BdQ)z~Od8;BYY_ZD)bQ?J@#~ixKHa5IEc} zBXGDK5jb3oNXMbT;dU8;!^McS&H{(qWdsfvBhqmwaJXGY;BYY_JxbtkyNtl$VnjNA z1P-^$2pld(qQtwE=Ft|E=HuK3mk5fLHG(= zjy&+cc*)oM_TtSJS9Hf;`A?jDXCC42LJR3~Nu27Azxtnaog}W7#L2sh5dO-vke^Z# z*GS^zezI7eyiZRYXC(0uhqz~tenS1pdx^yQkh|xOaYy~gd=i)EiQilA7@t18K(;fBmM2`CDd-Qv)r#GrszeuNvv`syY6x%TKM)R(-Em&gnC zA#bp9jNA0Hr`z-s>gU>{pFM8V&mOnwC)AfPwYdJ|Uowty$NqDb^dGU26M130yGrz< zd-N0POWyk^)`z@t*D-F>PpB_>R+^;SkK6PU^r3skr#pii)sviA>_9r%1$8^W>N&Yb_ z)}K5X;TU)9Kb55aR1*DE68+pI`jJ&X$zRZi*xnuEj{1@RK$CPqA9sm<5l#9 zF42#?A%(~b{pBv{KX-|K?h^gnCHk2p`jI!siS;qzn7DrAt#OWVNBv9^{m7N3xV|RI z`GH(zI;K17XOie=lITbNUF&$fosz`pg%9skCo_0 z-Yp>3hs7~*{mCzA7Q+>;h1CGrk_3Crk~J$Zaw5aYz0n??xc`+tVHS#ZAI5ZW8^-8xhL; z_dxU)<{Kx`k9?hiqzn3yZ!|f^9mgjp(T_Y6P2`2~!AZs^`5zZa7sdm5V%jlo>5dEi z%SrSj))69aPj~D;Ux|L?JqJWy(AO8oNL%yL_c4Ne!i0a^Ofl5E78wa z(to}Z{d^_*`AYiFt4BYf{^SXGas7#Xi^PTYCr^7i#%=lu?eEp2pFM8tKYQG9{*iZ! zlKkxHj`Pn;qMw&UKQD=XUK0Jt+q_8rLVuBOayiBw`;WYNnxqTuL7q8xj5}UGkpK6S zbfJBGB>hKhQY2l_k65i7Pj_5jlc#}*yf8j}B>IszjF5DpzT`V9j&aBSBj3^> z=|X+U8-+<+DBmm@pX9v*j_Ho)ck%?0W4dGinI-*amh>O7k&)vC{mc^mye0aPuX+%9 zL0|GzzGK|6|A>8!qzn3bOU5U$wvlu}e{V_u5lfq6x}$#H68*d-`jPj&kmCjYye0bi zOY|fEPbBh!e*QQ{;zIq&|A!poj{WB^(T`Zvh`gYmzeGRs))>chNB#UI`uR)rBk!6e z#|!%TOY{rq(NCy9d2@rf{sB1V7rBFF>LnvDrDMJC0BC4qK8g)Q`N~#xZV@ z#2x2ffJDCliGIO7`U(7kzg*d!pFQq4K7%Fv5-b^?!IJqG+@qh+e!-Id3zqa>utdLL zN&f{)`Y%|bU$8_!@`fkUUPAeSlKvy#mUB$E^`9`_0ww(yDCxgIN&f}*=qL0S`A@jG zzsTEe9OI7t7bww>+*fgwcRauQ_2?&*hrd+nAn%7`;^X~#`p+(J8=v;Lqy5vbM?ZVI z=6om9-;8Hc)N*E#1n)f-$bYni_1~s z)?v<~vsgy>4MKy2-R{tqD)teU7=({G+npYaKWc0Hkv(A_myKgK85`asufei1q$n<{ zYG`TgwBpty{f8~J)?2U^o?!bu>TY5DMPQ_?=}@WK|7t_+9@#@WGn*2u&?K`$n+#Ac z0#t+0p<-wBtD*({@x+48W+tOsP5n?!R}Oko>Wr-NcD!{Us7Jbo0V*Ta+8+AXBX!^1 z*LBI~?#l-sLOQ(ZWw@=7s=HR*Wqum5#~k~`pwp4f-^{rea~FGYcfWhCNZxdG)i1t9 zKfjQ1yZz^#|7>aeb=|AUF~7}grK*3Y-nKaZ?zG>Z{oQoPtU2kl-%oo|d&oqc^dsJw zbX{%Q@FONw+S4zo>P}gH((6yhoV6(beCDd9^Ni;&-t1ZQwp+imPyM?Mopajnrad?7 zC3)+)*@rc)=}SM*JV{^meY-q;)gRWf^9#P`wHFpX%u`=XC=V>SIOFp+)y0M1H+Wwf zb6EkG<{hkay0m6rL)T@$3U})Aga_ra%hNI&3NBB}sjs;_t)!&t@~q41+RJO-%y+%K z?c1WZD~WFyk_UGKH{RiI#XU_y*BW&s`J{=TB`iogsUgl{T=jytNQOjR~5<( zr&ryy83X@OZ^{^)NjGK;x#`@PG4v+YfIa7ij0xGw+KdUeTI(_<$>% zG4-al2z!R2j0H!U8#0!)&=nawcQskB56MzBULX1`I9(qBR2}xzb=N0dYnNT0(#}*| zpO)42_{Na0G`bt(-hhT1%lDusndm_<%H(t8o|*hzO#IEJGsTVEPM8+wH>#7bBu~xA?2!? zTccjpP`9SMCabtLdzY;B_R#OWuiYMTxSGE`;_DjM9O^S?=bX5YT@*R-2a$75|Esdj zoWTdXDC{9BXUIQWG&#f1tCTro_R;M*i*8VbIh#LfEyo^TekW;{TybaCZfpCUSszi# zJImjtn(juwY^Coez0&G-H|f3_-5qkgNpp9}U+FjR#U7@*?j;`T(%&0)%YNFPixo1)_YpFhap!w)ei^ksWLts@kxjL;rR1Z*~5vSKy{uhy(2o0P45WI z3w@yI%8PmBVRT+xd8<=i!rM@k*Z;DnD=+nxTDN?+w-u&*_m5;;e#nR(Y58Noz*sexG+JDo}xQX9a35(^R;A z*2z@_zWOM*{?EFCn&j6j*qYSr3Tw@<_iLPL-5bjF zwalWy-k%^{ef$U3<_5*rRlW@# zM>^Str@n4(Xbk+M4K+ERXkm$`Z3_IVQQoY>+}iAVs6MQjOT&BahpGdcXMfw)PP~qm z)E`>wTlQ2X zHO`$0c}*oJCz{%{1NU45L%@+Mtn!Uj>Z)cn7V9 zeE+pW zrh?@sBI=gH;1eU1TG)JIxs1d9N|_5xIkC#49H#udr9%Vje_gD30&9L&(gPn=lLCX20-$K5oQZ)zc5?ZYAwAuGiN$%zPJXOAm!2& zlP_$$G_%a7KTZ@Uu;lQaCO2w0L4pzy={(UcFY z%ZPVY5Z_Y)i5XLi5@AcmG6wfl#x`{)Ouk-cSb=?u9$>-sKJ6x0dp)5#7}i}M&}AS# zGQgJWBTG#%@A|~YW_arQ>!Oj~KSS!rGu|d-aD>AR} zJ7H7i)y{sfBvXSDVO6H4dI@aIG|2nH+RTB@yfr6tNNx;9hH!Y!W{#~fz=F*2T4c@5 zoLKub-k+$o!m`ZCcl{tJb80~(tj=6rqs4hX*LeZP-1Kxa!1FizYMrdNZ^jibgQYh| zJ`92NH>c^lVC2nZEg|qiR%E?9?8xeCpkYf^qCsUnn>G0UTv(GeMBxHUvqnA$fz4TC z$~>^-B$qPSo;9C-0?Ap+)qb!n+nY&(P1)f_ci560tun%b?AR_I7G@_jdgJ}1E)I5N z_jl=n5!tDz114vuHgPz0U?UGpvIjN0z>4faxR3m@2Y0d7C)q>NmgCf6l?LKBVokG$ zmqil4Q3>m_M>ZHB`c_-*ELeCeu9Ji9x8fcp!^T@f3$+g$ zo$_M5x?wr;<@+m{Ez&VrcEYM5CNSKG) zU+eitKIseKsX}v$AJBz99kH;e(5Ep3`@W6A827D8gp|UN(qx!g7QbHS%9vz z7HQ0Z<_~1Rr;Nqg!hBmU13FKNTmp{X<&oBsdM;~#^_P0jo0DNmz4_Wm zm|btaI*9n?#1DLwMEt@em|Gv1pMv+JAN8^3HPlutB7XHE=+mIZ?K8e{_J=cJR1;m| z4=bAJWnAw_QD&1jO(}L^aR%mXln+ltnH3faZ((HV5FpO^Iiu^DV zNasTS`i zmw16kTi7jsc)l&BBoMZ@#g^i;VOwIc8Md~oY64(F2b~)S+q#suC&31*u4o^uK=l{r z!F1GkHVD?C#&1_(Kl)sNwL`{Nq{2G6=Oa9dsJjx<7wYR8l)3PH`<*G}FxUFTQVZ*? zH)D0!&-TJ2+nU|If2-TS)9v5w_VaCistU{0;r$KPqC_2Rv=)qQw=PE53IZe0gW(2P zkFF0v*uUBB-|hA*vAPSBs|Jnh1*r0I-?~g1E zT=Kz}Rm=L1`E-wYm9gcsSNf)UYrfp=q?q>f;oTbLw5Pv1=2}1dsUv&6fM`M8z8W=Gr!pYhwSM%ujo z^u3)0jQt7 z?aa3x!6w%;fAYVdby_Sl(!bXk`p-@OKEA8}+VgK01|>|pu&cr&aq)%YE=hr17pnP( z(GxB-eeRSLd+{*E3?FszD>phk{324+&6{^=SF>uw#!Ig$`Wd_~Uv4gpS$_F)EB3GM zuJ!6S|LXpFg{;rjX3)e%UpvBf`uD%qtkd-CbFGb5=Oy2(0V zO2!#oTkz0~zaqP)OwGVHm8iiPnNE!%gEMaFs$+&`+>y&h4bEs#$fE{d->Z*mhU?z~ z6*21i38&VWDcA4HeVw@*FVzGDCEa+n%bKw1#-}P1=bQN@>WrS4c~luiX)>{?#F@{; z#t~<4;=6cf>YACbv6$~#zdbNGh5L$^Dpy^x2^6iPPlLMQTx%YQRR9=|sK zeP^vPApfHdneUK-PYa!r#ut2A+U-9fzLU`y(_Y{dd@m;9(GTrxRG&wNs>?Gr7Gkp_ zA5-+6hlUO;0#^%D^Z4B^9q0G>&rWObpyK!Bw0lVLBYBH&Y{_etCbyuHeQo`;EhTUN z+hfS8l6%FSUSrE%f8rSwRQAT>2jiYD`$zZwhoy$V)UuDPt}IvfQ&(f`@UqMXt9xi! zW@i*w%j5+Yht00|vfYU>S6~x?ci+mlN|Z@MtM(Nq1?sByRV9V#s;*qub&jvPm8Tdv zt$KfGN2J#8WIjD#mz%3A)atOo`QN36&$GJ>8bil@2(h@ncA_PEh4In_KAZO+ zdgnnDLfDYr&86gVV{%?lf3rT{qtWoq`U3Yx{n6#vo~rqEQ@y%L|J&w9szIMN@++Mi zo3^@44*JvU^A(MTGaG8Ht@^8Uk(WV}x#-mv6iCJDX(@0*n&XxBiwi`>11~>>?As6ZF{m^IDx-U#M z=p}2-mqsPdy5q1_jSj%b!|wIC66(YE1JL^f>_i_}D-M^tq7Pug;r42@55|6FO2#ED z{VJ>g{RP9ncKr}%{pL5dT67coe{<3Uy#>?1D|JB!taV3u75dm(@dIVTB`AM%=|nF> z#IZIO=Q8CO*M;+(_>)T+`j<8LCu=D#cH41PDF!zkud72pSj&zZO3~Y3`q#w(vG)3|zwW%Z;`8fZ3NDa?yKMxGb;6nN7Z; zYQ$aa{P(X5(62D`=J`VO2UOp=`w_0h)Vq1b=v6D+@94lvznWL|3(oUNLBn6&LCasb zAEs9o^JouzQC(Av&Orvd@85V9kn!KMs_6Qz>pS@@)b*Wpv3za|4qlgSj_UdjW}u@Z zUSp9+PaeO!x4qE=Rn+HkC8z`tXW^Rr_5grQ;x{ohD`>yZ)Du`E!M7YI|q(fZ0-84 zW6+4jp!%+PMpS-~qVgN?r$Zw=lE+TTitk6aB2 zzsaH|j)wuiJu%K$2ZMgAF$~%YYk!mZ4<8E8{^nXgVj-;k-P%5EJNTc>jTpBLMxJb> zW<3YXPHMdp2Ey8tO|nJLK*Ap`egVV4kk;v)G6CBSmEHj<-9caq3`HVLvv$DD zQ!S?Pqao>Zv1Zj)81ZLS(3IgY;m>LlR%PO!uKt7j!puKA)PpvF>P*qRqygY`rU3>% z4e@8>mO*o{(Xcjrz#?!z+nmHj!P945-3Ls^fg1@np6xIVNQIcc{`QL-4esY|M8t0b z^SRP#v^&I{yEP4KH27RsTigN?XyeA<07x+OTvH$(QX|gYw@i2zHl6EGj@}Lt>5oEE zmO^BDQ%&F+7?9o&(|Tm1*e z<3LG*t?6w(g9pKc^La!+=0fQZ|2QySD2YxQg>8vBeTOcDp%;{76wJR+Zwy@sFI=F# zbdlD~i;olIQvh9*n-WIAu!~Ka#PKlVVufkPMi_Om)@jBBn0T>8n=k_htS~IT}kgVrkr8Kxx7hi3P z?3W7LueKO!$3WDzR^GKg#9gZ{iQELkt|8gPEin69qi@V;Y-;Q@g!hNV*GBoLjOllD`4IYDm=Ikpv+9a~?P)EX}U# zt53#31B#poE3@0hopNQLtzfvDGca%% zgx;+mAEAQ8yLC=sgJIy^GB2M&u<>qNlzAj2ablPb8}tX2f~Kj2G>6E(C2=0Vn7H)-EWHWGQs%!by2=UVbXn7 zQq%}+2F&${S%58uU0$3oth!$j7lN%c_e(r1{UP!}YhP~@SRVec-jdQC;Nczpu(6-J z2gEY@>YGVDh)Xj)#xTQ*r<06^&4H;F^Cc zc-SO}%5U!LkBwLPPa=XmU{!ur%d{;pqu^oN)P>k;_t-Bo4hL;vZbodkD{1O89_AHP zTikqcP!oikd_h57jGGrMwn?rmXtg+-uywG_;zELUTdbYLHWbwOyTrnrNB@lUn+dBQ z)#*Zq!kR~I7B92)Vc~^k-p(K^Jh#+kD2ym9_ccersKUa4pm3N{*f~;O3$qFfL!(o$ zNw6^(H_xI%Hz!>RtSGFZb>p#xuqsjK3mXa_YE2{I`NFJJQ!+LZ7WqZ@gBJ>O2I|IJ zONtuCMtVbRQB9Ny-!3XD?yL8J1x3|#@L+hls3utH1FIi5dh!9-DA<^wF<<$jav#fACl`c*j(D>@52LKRxvRs3KGjY^|=2=l-=arC&0L}{9tn+j4#WHvc|y7 zvNkWH1se+MHD2-Efgd(Um*tr(iP*N77Vb9@2Zcd=2+S(K5He;VHXXKEaIFVd)c0ZV z4W^2!_!t9>tju%m(+}oXmPGkt>v3g6NV_Mjt1S2M#P>ZaD^+fZ*o4@waEZ6JRH=wfMuN>b$Y8*w|Lxicj0Hv$|Y~gPAoM z$p(KMWRqZJO#_7X$3Y|b+X5V0S5wmzIvqCDR7D#!u&Jid%O%FzR$DQU9}01G=L>^3 z!tlE6;IL7!s4mwt6dNDwu7$5L60!s&4k-jFx76W@DlZ1U7NgJ;Xp4XUSLV@s{l)W@39db;0$cx(|YjqU8j zL2W=Mi!FeqT1ztcwBMP;M8fFysvt@OOWQAnsAFJ7`x8GEO@e4;8@2=1XsxF1KyHE; z+Kc@-*4onX^B7YAtnDcDSNo74RP6zayM9}$z*%=yIw{RKsImp^IIvb*A9~|kpCQ(N zkCR()aESyjS|2FlG1J0TS8TXj3zxkjr&tS6{VaE*wGN$I(N+z~=y-+aGcX3-n84M; z1eEV1bH+g_2{xkqu`+yf4Hb~!B&yTM$faD{W0MII<)`{u+hDyadtz||wmaS$sm3Np zDtn|F-{qzLoKS*qWHASQ{H9uKH2KMH_-wB$chefJ_w=7d3?Bk(U4Cw=TL>yXFTmGg zt@O;AQC0@qe2@AuL9iN2mk9VJSDqD?6P`(;n+jETnaVvW1qYpf5 zr=dL`eHm7^0PX$gu&Hzbdh>8c2Qve`jsvF|B-V*zFaMN@Dkq~~|Ed1IbP3vj=3JqA zG1`~DyE=C&dhh(-t!KxhZ!+%PfAk#sJmZn#-%)7)%}2TI)6qLw`&#bJM?XF&Df)do z`ndRUYvxMyR{6El)q~LIb@y^J*CQ|7Eb5*s2l5v}HKLDXdkkL2%6@)R{SYmghAn=h zr#)`QroH&t9j)hIlZ_ePsym((U9DGsP{&Pi)8F_?6EcL+ z<=o_>#)a@fyJB@?U9h;$>lxKdefp;Np3RZGDO{qmCP{x&@F z()OxqN5KH}^(!Hbcr}S$dDW|JjS%HG25f+T`RHSp+13j5F}}Jc2KiTh zXziK=L(zvnH5H79ap=|Km7QDQX>{Ot8#NZ5MMsWTKJtMV(Ej7HrkP+uZ{y4A8K6dc zPo5l;3d_);KRQbmLSOXfpJ&i)>q+$48KZds=+M5u>h*IW5$#I9<+cUuv+qJ{{Zf1z z;EfA63#Z_6cVE2WF%|})PcLV7425av-Hgh=mgD?)UC%X)g1Knd%`E*`T#vVMO7Q~> zW6?Y9pH=opDR}y*doD_Qh9vmB>Aql{YM9mfkCyq*Y6rml4_g+l$)jQX7p)`5HUxt5 zh(2Yu#~@hpt#ax%B@45U-5b4AtA}Tf`Jt}VMEn?qK4pcT$Jb14eb-JN49}dDv2lKG z@Zuj%Q4@Jza87%e9HSls1JV@J*WjDdDM{9tY7n}pa8oXiE1vMY-?2R8F z$mugP1z)~gc6)et)J%Bp3hx=~=?_7FKZ+XTjaOHHKZ+f18Vbw)ZZs_$=VHB)adGmq z0h90zcY}Wv=Ywy#%Zve@;V>?}iU$_{R$ zXm}ypr5V4lLEb&>Y=lStE>1%NdgnEEeWS(3Ju4L|>uL1cr$y`d5!N;6yDzV;NST6Z z@%_WiixeKX$=~?4b!uB7{Eg0kTeJ1f89c+^{J}cAjmDJw`^iU7m+Nt{SI=gzv1VD@ z(W}?1r*%2Oi|FN>)sq_-ID_7}Ygw6H1XbunW8wDSf5TPV+w{%k4n2O-9pCiB)$6|b zhr3V(*C7x632E1(tW$C4e}KXZoUM!S-s@x!0^mM2D%KR0z)-k~-auTrD-47W(dWom zVT7HKjoa>~6Nx_V3koarTQ@}fmP^v z^g#azmO?Ok7oAh$%M0u0Xb(!G5@5A$Pn8HyTX*1beo^ZL&)D`@7S=!jdJBE!F2{S* zQ3CQFumGNg(fGewEmR9^vc7?~qtBEvcvf}qDey8ME}?HwP0d-@i|u|tpzp1n@Vd1K zeT*_MB*91coV5oXWZU5|PJJ8gkn7+azH#{``X;LZ(#e2Ecd}38S&5D6BE89wm}$L= zPM}8o+&j#}qw%CnY0fBtwbt|K8T3Vjrzbo|PGsn;x?Ks|0HFiuTH8YfY`5M;ThVVh z-ZNmQH4AOVremjY*oC|7ZB*J`a~+M7PZeA=$?#_qtxtmrpN`_iODe<^Mdp_yM#`oEu4<~ns#G0unRP5yzxqgovq}>`2g$l8&yQzF{q6OqpOjl>Tuov<2V_!9P7~Sunygh zuB69f9eSLGXA<}cHixxP(E;>+yW^K&Eymg$m11-BOWisIV?D6b@VqD1!sgroNE_%nvJDWL|ZBwYw$6u*kx2Q zJ%bD7LYb9Rf3op2*ul(7!z6x|QBRM@$M$RnH|{B1<9J-#o{jh8KcG)hZwVW}iJ2+h z=-s$yY};af0-g5XHf{|qr{`g9anCawgpGYMfTf4iZ*el*atXXA$(2&EEVYI8rbbYW z)W6uJMlHqo$_*-NDi_SDEIN+0I2kl-AKYejd^A^$d+Pw#%*3;?^bC3@9Z8Sp-I#c; zm2u(^(z|h)v>}yyl}^X$^O$kWTl8tR5BDwJ3otwJLHt^?D}9=Y##ksjh8b^mGW#&W zhT-&m-kBT5eQV;)-iC2zm+oVNxo_#E%y#ZeemAp+e~wCU*Rad@m(2;>Ws4{GI*;hN zTqj*??$6aQ+f7Dul-a_in{~`H+z76USRVaD0iGG7g;@)RJWp*+zutV_ZOXlOad)x(_!$@-&{W*J(^n$RF-oP}Aokqn@ zW+zj#*eOQJNE@A~FQ_ls>#WQ$o&DUXqZE{!)oU0kO{3Qs3?ntVAcaQ3uQ03WbVRek zYzP}dc_SLpcwTiovTt`97iy{yQyP?dDw r3#eyi(5i&_}rG22b3o>A3b+xJGU` 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

    E9pJ! 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 yDyo;NAY-@%zpkB$w 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
    JPeu)#S>b#z>GbX-zuYD#8idRlsHJoK*B8oA;Y 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%0Duj56*t_V=f#P^nL;P=Ec>;WjY`+F75- z*V7V&5O7Q%E;HgGqA#(NOM>;80v8Pr!{n&gVtu^V0QVcE<0Pa3d@%z#J^f-v+G6fH zqa`IPm3ha);^LeXE2NGjjgk@0gn38!c$^fXb-! z8Z*iQc9Ve&C@Y;*!V0}4H#dthp{yLSND^DNN@%5}sAXO+y#&a71qCJ0#oT&WJ7$GoJ*x*>G)sSrPZJBEHIs_$n*ntE`A+n#j<_ zmWIauKBOc&##j;OP8>V*-hm@cXD)VJICuQL_Xzisox`KiSv=$sYhf|akExjo^O|N( ztciX$wo^xu#T88rw$bT|DyqVgRAWyI3S`GSIs{K!W!Srnb8cjE!gHdrseK~gLq%!n zwbx&_al_{8u3od^%9Tr(Zz6ku|Is>N2j141FmLRf0 +|L6T6o}ljZ~$aDXH7H?wp1E(^=?-b&BN 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
    _8l?nVRT$q;1E0AMO6&^=BV_{JEE2 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�Y8 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 z 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

    =+EIEfrunt@CU~siC3Ficl415YSl5 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ⅅ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

    !=R!!ahG2U!{c1!a3?- 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 literal 0 HcmV?d00001 diff --git a/assets/fonts/OFL.txt b/assets/fonts/OFL.txt new file mode 100644 index 0000000..6843f31 --- /dev/null +++ b/assets/fonts/OFL.txt @@ -0,0 +1,93 @@ +Copyright 2022 The Noto Project Authors (https://github.com/notofonts/latin-greek-cyrillic) + +This Font Software is licensed under the SIL Open Font License, Version 1.1. +This license is copied below, and is also available with a FAQ at: +https://scripts.sil.org/OFL + + +----------------------------------------------------------- +SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 +----------------------------------------------------------- + +PREAMBLE +The goals of the Open Font License (OFL) are to stimulate worldwide +development of collaborative font projects, to support the font creation +efforts of academic and linguistic communities, and to provide a free and +open framework in which fonts may be shared and improved in partnership +with others. + +The OFL allows the licensed fonts to be used, studied, modified and +redistributed freely as long as they are not sold by themselves. The +fonts, including any derivative works, can be bundled, embedded, +redistributed and/or sold with any software provided that any reserved +names are not used by derivative works. The fonts and derivatives, +however, cannot be released under any other type of license. The +requirement for fonts to remain under this license does not apply +to any document created using the fonts or their derivatives. + +DEFINITIONS +"Font Software" refers to the set of files released by the Copyright +Holder(s) under this license and clearly marked as such. This may +include source files, build scripts and documentation. + +"Reserved Font Name" refers to any names specified as such after the +copyright statement(s). + +"Original Version" refers to the collection of Font Software components as +distributed by the Copyright Holder(s). + +"Modified Version" refers to any derivative made by adding to, deleting, +or substituting -- in part or in whole -- any of the components of the +Original Version, by changing formats or by porting the Font Software to a +new environment. + +"Author" refers to any designer, engineer, programmer, technical +writer or other person who contributed to the Font Software. + +PERMISSION & CONDITIONS +Permission is hereby granted, free of charge, to any person obtaining +a copy of the Font Software, to use, study, copy, merge, embed, modify, +redistribute, and sell modified and unmodified copies of the Font +Software, subject to the following conditions: + +1) Neither the Font Software nor any of its individual components, +in Original or Modified Versions, may be sold by itself. + +2) Original or Modified Versions of the Font Software may be bundled, +redistributed and/or sold with any software, provided that each copy +contains the above copyright notice and this license. These can be +included either as stand-alone text files, human-readable headers or +in the appropriate machine-readable metadata fields within text or +binary files as long as those fields can be easily viewed by the user. + +3) No Modified Version of the Font Software may use the Reserved Font +Name(s) unless explicit written permission is granted by the corresponding +Copyright Holder. This restriction only applies to the primary font name as +presented to the users. + +4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font +Software shall not be used to promote, endorse or advertise any +Modified Version, except to acknowledge the contribution(s) of the +Copyright Holder(s) and the Author(s) or with their explicit written +permission. + +5) The Font Software, modified or unmodified, in part or in whole, +must be distributed entirely under this license, and must not be +distributed under any other license. The requirement for fonts to +remain under this license does not apply to any document created +using the Font Software. + +TERMINATION +This license becomes null and void if any of the above conditions are +not met. + +DISCLAIMER +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE +COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL +DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM +OTHER DEALINGS IN THE FONT SOFTWARE. diff --git a/assets/fonts/source.json b/assets/fonts/source.json new file mode 100644 index 0000000..ca532d9 --- /dev/null +++ b/assets/fonts/source.json @@ -0,0 +1,10 @@ +{ + "name": "Noto Sans", + "repository": "https://github.com/google/fonts", + "commit": "a54f7446f84a1125ef6bf08baa46f3639e8905e0", + "path": "ofl/notosans/NotoSans[wdth,wght].ttf", + "sha256": "bfb7bb691513f12e734dc346c03a03f784912432d7e3fa8e56efcf906fe86b3d", + "license": "SIL Open Font License 1.1", + "license_file": "OFL.txt", + "license_sha256": "cee9892f9f0cc8fe882c9e9537ee6a89621d86ee7ceaf70b02e2b2b1c25c061a" +} diff --git a/assets/ui/dark.json b/assets/ui/dark.json new file mode 100644 index 0000000..0828d82 --- /dev/null +++ b/assets/ui/dark.json @@ -0,0 +1,16 @@ +{ + "background": [0.073, 0.078, 0.090, 1], + "surface": [0.102, 0.108, 0.122, 1], + "raised": [0.145, 0.151, 0.169, 1], + "hover": [0.19, 0.197, 0.219, 1], + "border": [0.24, 0.25, 0.278, 1], + "text": [0.88, 0.889, 0.91, 1], + "muted": [0.59, 0.61, 0.65, 1], + "accent": [0.65, 0.60, 0.88, 1], + "selection": [0.26, 0.245, 0.35, 1], + "danger": [0.92, 0.39, 0.38, 1], + "font_size": 14, + "row_height": 28, + "padding": 8, + "gap": 4 +} diff --git a/assets/ui/editor-layout.json b/assets/ui/editor-layout.json new file mode 100644 index 0000000..09c8d08 --- /dev/null +++ b/assets/ui/editor-layout.json @@ -0,0 +1,19 @@ +{ + "root": { + "id": "root", "kind": "column", "layout": {"gap": 1}, + "children": [ + {"id": "menubar", "kind": "panel", "layout": {"height": 34, "padding": 3}}, + {"id": "toolbar", "kind": "panel", "layout": {"height": 40, "padding": 5}}, + {"id": "workspace", "kind": "row", "layout": {"flex": 1, "gap": 1}, "children": [ + {"id": "scene_panel", "kind": "panel", "layout": {"width": 224, "min_width": 150, "gap": 0}}, + {"id": "left_divider", "kind": "divider", "layout": {"width": 5}}, + {"id": "viewport", "kind": "viewport", "layout": {"flex": 1, "min_width": 180}}, + {"id": "right_divider", "kind": "divider", "layout": {"width": 5}}, + {"id": "inspector_panel", "kind": "panel", "layout": {"width": 300, "min_width": 210, "gap": 0}} + ]}, + {"id": "bottom_divider", "kind": "divider", "layout": {"height": 5}}, + {"id": "bottom_panel", "kind": "panel", "layout": {"height": 184, "min_height": 90, "gap": 0}}, + {"id": "statusbar", "kind": "panel", "layout": {"height": 26, "padding": 0}} + ] + } +} diff --git a/cmake/Assets.cmake b/cmake/Assets.cmake index f4f0764..29ea1d0 100644 --- a/cmake/Assets.cmake +++ b/cmake/Assets.cmake @@ -1,9 +1,13 @@ +add_library(faset_asset_data STATIC ${PROJECT_SOURCE_DIR}/src/assets/asset_data.cpp) +target_compile_features(faset_asset_data PUBLIC cxx_std_20) +target_include_directories(faset_asset_data PUBLIC ${PROJECT_SOURCE_DIR}/include) +target_link_libraries(faset_asset_data PUBLIC faset_core nlohmann_json::nlohmann_json) add_library(faset_assets ${PROJECT_SOURCE_DIR}/src/assets/asset_pipeline.cpp ${PROJECT_SOURCE_DIR}/src/assets/cgltf.cpp) target_compile_features(faset_assets PUBLIC cxx_std_20) target_include_directories(faset_assets PUBLIC ${PROJECT_SOURCE_DIR}/include) -target_link_libraries(faset_assets PUBLIC faset_core nlohmann_json::nlohmann_json PRIVATE faset_cgltf) +target_link_libraries(faset_assets PUBLIC faset_asset_data PRIVATE faset_cgltf faset_stb) if(BUILD_TESTING) add_executable(faset_assets_tests ${PROJECT_SOURCE_DIR}/tests/assets_pipeline.cpp) target_link_libraries(faset_assets_tests PRIVATE faset_assets) diff --git a/cmake/Authoring.cmake b/cmake/Authoring.cmake index 22c4cc1..2704c9c 100644 --- a/cmake/Authoring.cmake +++ b/cmake/Authoring.cmake @@ -1,4 +1,4 @@ -add_library(faset_authoring STATIC src/authoring/schema.cpp src/authoring/service.cpp src/authoring/templates.cpp) +add_library(faset_authoring STATIC src/authoring/schema.cpp src/authoring/service.cpp src/authoring/templates.cpp src/authoring/transforms.cpp) target_include_directories(faset_authoring PUBLIC "${PROJECT_SOURCE_DIR}/include") target_link_libraries(faset_authoring PUBLIC faset_core) if(BUILD_TESTING) diff --git a/cmake/BuildService.cmake b/cmake/BuildService.cmake new file mode 100644 index 0000000..808c666 --- /dev/null +++ b/cmake/BuildService.cmake @@ -0,0 +1,10 @@ +add_library(faset_build_service STATIC ${PROJECT_SOURCE_DIR}/src/editor/build_service.cpp) +target_include_directories(faset_build_service PUBLIC ${PROJECT_SOURCE_DIR}/include) +target_compile_features(faset_build_service PUBLIC cxx_std_20) +target_link_libraries(faset_build_service PUBLIC faset_core PRIVATE faset_asset_data Threads::Threads) +if(BUILD_TESTING) + add_executable(faset_build_service_tests ${PROJECT_SOURCE_DIR}/tests/build_service_tests.cpp) + target_link_libraries(faset_build_service_tests PRIVATE faset_build_service faset_assets) + target_compile_definitions(faset_build_service_tests PRIVATE FASET_ENGINE_SOURCE="${PROJECT_SOURCE_DIR}") + add_test(NAME process_and_cook COMMAND faset_build_service_tests) +endif() diff --git a/cmake/EditorCommands.cmake b/cmake/EditorCommands.cmake new file mode 100644 index 0000000..3c03cb1 --- /dev/null +++ b/cmake/EditorCommands.cmake @@ -0,0 +1,8 @@ +add_library(faset_editor_commands STATIC src/editor/commands.cpp src/editor/mcp.cpp) +target_link_libraries(faset_editor_commands PUBLIC faset_authoring) +target_include_directories(faset_editor_commands PUBLIC include) +if(BUILD_TESTING) + add_executable(faset_mcp_tests tests/mcp_tests.cpp) + target_link_libraries(faset_mcp_tests PRIVATE faset_editor_commands) + add_test(NAME editor_mcp COMMAND faset_mcp_tests) +endif() diff --git a/cmake/EditorUI.cmake b/cmake/EditorUI.cmake new file mode 100644 index 0000000..3f7fddd --- /dev/null +++ b/cmake/EditorUI.cmake @@ -0,0 +1,15 @@ +if(TARGET faset_ui AND TARGET faset_editor_session AND TARGET faset_scene_view) + add_library(faset_editor_ui STATIC ${PROJECT_SOURCE_DIR}/src/editor/editor_ui.cpp) + target_link_libraries(faset_editor_ui PUBLIC faset_ui faset_editor_session faset_scene_view) + if(BUILD_TESTING) + add_executable(faset_editor_ui_tests ${PROJECT_SOURCE_DIR}/tests/editor_ui_tests.cpp) + target_link_libraries(faset_editor_ui_tests PRIVATE faset_editor_ui) + target_compile_definitions(faset_editor_ui_tests PRIVATE FASET_TEST_ENGINE="${PROJECT_SOURCE_DIR}") + if(TARGET faset_example_plugin) + add_dependencies(faset_editor_ui_tests faset_example_plugin) + target_compile_definitions(faset_editor_ui_tests PRIVATE FASET_TEST_PLUGIN_DIRECTORY="${PROJECT_BINARY_DIR}/example-plugin") + endif() + add_test(NAME editor_ui_authoring COMMAND faset_editor_ui_tests) + set_tests_properties(editor_ui_authoring PROPERTIES LABELS "gpu") + endif() +endif() diff --git a/cmake/Player.cmake b/cmake/Player.cmake new file mode 100644 index 0000000..3d7978d --- /dev/null +++ b/cmake/Player.cmake @@ -0,0 +1,24 @@ +if(TARGET faset_gameplay) + add_executable(faset_schema_exporter ${PROJECT_SOURCE_DIR}/apps/schema_exporter_main.cpp) + target_link_libraries(faset_schema_exporter PRIVATE faset_core faset_gameplay) +endif() + +if(TARGET faset_runtime AND TARGET faset_render AND TARGET faset_assets) + add_library(faset_scene_view STATIC + ${PROJECT_SOURCE_DIR}/src/player/SceneView.cpp + ${PROJECT_SOURCE_DIR}/src/player/scene_io.cpp) + target_include_directories(faset_scene_view PUBLIC ${PROJECT_SOURCE_DIR}/include) + target_link_libraries(faset_scene_view PUBLIC faset_render faset_core PRIVATE faset_asset_data) + if(TARGET faset_stb) + target_link_libraries(faset_scene_view PRIVATE faset_stb) + target_compile_definitions(faset_scene_view PRIVATE FASET_HAS_STB=1) + endif() + add_executable(faset_player ${PROJECT_SOURCE_DIR}/apps/player_main.cpp) + target_link_libraries(faset_player PRIVATE faset_scene_view faset_runtime faset_gameplay) + install(TARGETS faset_player RUNTIME DESTINATION .) + if(BUILD_TESTING) + add_executable(faset_player_tests ${PROJECT_SOURCE_DIR}/tests/runtime_player_tests.cpp) + target_link_libraries(faset_player_tests PRIVATE faset_scene_view faset_runtime faset_assets) + add_test(NAME player_scene_contracts COMMAND faset_player_tests) + endif() +endif() diff --git a/cmake/Plugins.cmake b/cmake/Plugins.cmake new file mode 100644 index 0000000..cef9222 --- /dev/null +++ b/cmake/Plugins.cmake @@ -0,0 +1,33 @@ +# Native plugins deliberately require the exact SDK, compiler, CRT and build. +file(GLOB_RECURSE FASET_SDK_INPUTS CONFIGURE_DEPENDS + "${PROJECT_SOURCE_DIR}/include/faset/*.hpp" + "${PROJECT_SOURCE_DIR}/include/faset/*.h" + "${PROJECT_SOURCE_DIR}/src/editor/*.cpp" + "${PROJECT_SOURCE_DIR}/src/authoring/*.cpp") +set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS ${FASET_SDK_INPUTS} "${PROJECT_SOURCE_DIR}/dependencies.lock.json") +set(FASET_SDK_SIGNATURE "${PROJECT_VERSION};${CMAKE_SYSTEM_NAME};${CMAKE_SYSTEM_PROCESSOR};${CMAKE_SIZEOF_VOID_P};${CMAKE_CXX_COMPILER_ID};${CMAKE_CXX_COMPILER_VERSION};${CMAKE_CXX_COMPILER_FRONTEND_VARIANT};${CMAKE_MSVC_RUNTIME_LIBRARY};${CMAKE_BUILD_TYPE};${CMAKE_CXX_FLAGS};${FASET_SANITIZERS}") +foreach(source IN LISTS FASET_SDK_INPUTS) + file(SHA256 "${source}" source_hash) + string(APPEND FASET_SDK_SIGNATURE ";${source_hash}") +endforeach() +file(SHA256 "${PROJECT_SOURCE_DIR}/dependencies.lock.json" dependency_hash) +string(SHA256 FASET_EDITOR_SDK_FINGERPRINT "${FASET_SDK_SIGNATURE};${dependency_hash}") +file(MAKE_DIRECTORY "${PROJECT_BINARY_DIR}/generated/faset/editor") +file(WRITE "${PROJECT_BINARY_DIR}/generated/faset/editor/sdk_build.h" + "#pragma once\n#define FASET_EDITOR_SDK_FINGERPRINT \"${FASET_EDITOR_SDK_FINGERPRINT}\"\n") +add_library(faset_editor_sdk INTERFACE) +target_include_directories(faset_editor_sdk INTERFACE "${PROJECT_SOURCE_DIR}/include" "${PROJECT_BINARY_DIR}/generated") +add_library(faset_editor_plugins STATIC src/editor/plugins.cpp) +target_link_libraries(faset_editor_plugins PUBLIC faset_editor_commands faset_editor_sdk PRIVATE ${CMAKE_DL_LIBS}) +add_library(faset_example_plugin MODULE examples/extensions/beacon/Editor.cpp) +target_link_libraries(faset_example_plugin PRIVATE faset_editor_sdk nlohmann_json::nlohmann_json) +set_target_properties(faset_example_plugin PROPERTIES PREFIX "" LIBRARY_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/example-plugin" RUNTIME_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/example-plugin") +file(GENERATE OUTPUT "${PROJECT_BINARY_DIR}/example-plugin/beacon.faset-plugin.json" CONTENT + "{\n \"format\":\"faset.editor_plugin\",\n \"version\":1,\n \"id\":\"example.beacon\",\n \"module_version\":\"1.0.0\",\n \"kind\":\"editor\",\n \"api_version\":1,\n \"build_fingerprint\":\"${FASET_EDITOR_SDK_FINGERPRINT}\",\n \"library\":\"$\",\n \"dependencies\":[]\n}\n") +if(BUILD_TESTING) + add_executable(faset_plugin_tests tests/plugin_tests.cpp) + target_link_libraries(faset_plugin_tests PRIVATE faset_editor_plugins faset_runtime) + target_compile_definitions(faset_plugin_tests PRIVATE FASET_TEST_PLUGIN_DIRECTORY="${PROJECT_BINARY_DIR}/example-plugin") + add_dependencies(faset_plugin_tests faset_example_plugin) + add_test(NAME editor_plugins COMMAND faset_plugin_tests) +endif() diff --git a/cmake/Runtime.cmake b/cmake/Runtime.cmake index 1f27025..51cbdb5 100644 --- a/cmake/Runtime.cmake +++ b/cmake/Runtime.cmake @@ -6,13 +6,24 @@ target_compile_features(faset_runtime PUBLIC cxx_std_20) target_include_directories(faset_runtime PUBLIC ${CMAKE_CURRENT_LIST_DIR}/../include) target_link_libraries(faset_runtime PUBLIC nlohmann_json::nlohmann_json PRIVATE EnTT::EnTT box2d box3d) -add_library(faset_gameplay STATIC ${CMAKE_CURRENT_LIST_DIR}/../examples/gameplay/Gameplay.cpp) +set(FASET_GAMEPLAY_SOURCE_DIR "${PROJECT_SOURCE_DIR}/examples/gameplay" CACHE PATH "Directory containing the game's Gameplay.cpp and Gameplay.hpp") +if(NOT EXISTS "${FASET_GAMEPLAY_SOURCE_DIR}/Gameplay.cpp" OR NOT EXISTS "${FASET_GAMEPLAY_SOURCE_DIR}/Gameplay.hpp") + message(FATAL_ERROR "FASET_GAMEPLAY_SOURCE_DIR must contain Gameplay.cpp and Gameplay.hpp") +endif() +add_library(faset_gameplay STATIC "${FASET_GAMEPLAY_SOURCE_DIR}/Gameplay.cpp") add_library(Faset::Gameplay ALIAS faset_gameplay) -target_include_directories(faset_gameplay PUBLIC ${CMAKE_CURRENT_LIST_DIR}/../examples/gameplay) +target_include_directories(faset_gameplay PUBLIC "${FASET_GAMEPLAY_SOURCE_DIR}") target_link_libraries(faset_gameplay PUBLIC faset_runtime) if(BUILD_TESTING) add_executable(faset_runtime_tests ${CMAKE_CURRENT_LIST_DIR}/../tests/runtime_tests.cpp) - target_link_libraries(faset_runtime_tests PRIVATE faset_runtime faset_gameplay) + if(FASET_GAMEPLAY_SOURCE_DIR STREQUAL "${PROJECT_SOURCE_DIR}/examples/gameplay") + target_link_libraries(faset_runtime_tests PRIVATE faset_runtime faset_gameplay) + else() + add_library(faset_gameplay_test_fixture STATIC ${CMAKE_CURRENT_LIST_DIR}/../examples/gameplay/Gameplay.cpp) + target_include_directories(faset_gameplay_test_fixture PUBLIC ${CMAKE_CURRENT_LIST_DIR}/../examples/gameplay) + target_link_libraries(faset_gameplay_test_fixture PUBLIC faset_runtime) + target_link_libraries(faset_runtime_tests PRIVATE faset_runtime faset_gameplay_test_fixture) + endif() add_test(NAME runtime_contracts COMMAND faset_runtime_tests) endif() diff --git a/cmake/Tutorials.cmake b/cmake/Tutorials.cmake new file mode 100644 index 0000000..64e4733 --- /dev/null +++ b/cmake/Tutorials.cmake @@ -0,0 +1,14 @@ +if(BUILD_TESTING AND TARGET faset_runtime) + foreach(tutorial moving following spawning physics) + set(tutorial_dir "${PROJECT_SOURCE_DIR}/examples/tutorials/${tutorial}") + add_library(faset_tutorial_${tutorial} STATIC "${tutorial_dir}/Gameplay.cpp") + target_include_directories(faset_tutorial_${tutorial} PUBLIC "${tutorial_dir}") + target_link_libraries(faset_tutorial_${tutorial} PUBLIC faset_runtime) + add_executable(faset_tutorial_${tutorial}_tests "${PROJECT_SOURCE_DIR}/tests/runtime_tutorials.cpp") + target_link_libraries(faset_tutorial_${tutorial}_tests PRIVATE faset_tutorial_${tutorial}) + target_compile_definitions(faset_tutorial_${tutorial}_tests PRIVATE + FASET_TUTORIAL_NAME="${tutorial}" + FASET_TUTORIAL_SCENE="${tutorial_dir}/scene.json") + add_test(NAME tutorial_${tutorial} COMMAND faset_tutorial_${tutorial}_tests) + endforeach() +endif() diff --git a/cmake/UI.cmake b/cmake/UI.cmake new file mode 100644 index 0000000..c634534 --- /dev/null +++ b/cmake/UI.cmake @@ -0,0 +1,59 @@ +# FreeType rasterization + HarfBuzz shaping. The default uses verified pinned archives. +option(FASET_USE_SYSTEM_TEXT_LIBRARIES "Use system FreeType/HarfBuzz instead of pinned SDK versions" OFF) +if(FASET_USE_SYSTEM_TEXT_LIBRARIES) + find_package(Freetype QUIET) +endif() +if(NOT TARGET Freetype::Freetype) + include(FetchContent) + set(FT_DISABLE_ZLIB ON CACHE BOOL "" FORCE) + set(FT_DISABLE_BZIP2 ON CACHE BOOL "" FORCE) + set(FT_DISABLE_PNG ON CACHE BOOL "" FORCE) + set(FT_DISABLE_BROTLI ON CACHE BOOL "" FORCE) + set(FT_DISABLE_HARFBUZZ ON CACHE BOOL "" FORCE) + faset_dependency(freetype) + if(NOT TARGET Freetype::Freetype) + add_library(Freetype::Freetype ALIAS freetype) + endif() +endif() +if(FASET_USE_SYSTEM_TEXT_LIBRARIES) + find_package(harfbuzz CONFIG QUIET) +endif() +if(TARGET harfbuzz::harfbuzz) + set(FASET_HARFBUZZ_TARGET harfbuzz::harfbuzz) +else() + find_package(PkgConfig QUIET) + if(PkgConfig_FOUND AND FASET_USE_SYSTEM_TEXT_LIBRARIES) + pkg_check_modules(FASET_HARFBUZZ QUIET IMPORTED_TARGET harfbuzz) + endif() + if(TARGET PkgConfig::FASET_HARFBUZZ) + set(FASET_HARFBUZZ_TARGET PkgConfig::FASET_HARFBUZZ) + else() + include(FetchContent) + set(HB_HAVE_FREETYPE ON CACHE BOOL "" FORCE) + set(HB_BUILD_UTILS OFF CACHE BOOL "" FORCE) + set(HB_BUILD_SUBSET OFF CACHE BOOL "" FORCE) + faset_dependency(harfbuzz) + set(FASET_HARFBUZZ_TARGET harfbuzz) + endif() +endif() +add_library(faset_ui + ${PROJECT_SOURCE_DIR}/src/ui/ui.cpp + ${PROJECT_SOURCE_DIR}/src/ui/text.cpp + ${PROJECT_SOURCE_DIR}/src/ui/font.cpp) +target_compile_features(faset_ui PUBLIC cxx_std_20) +target_include_directories(faset_ui PUBLIC ${PROJECT_SOURCE_DIR}/include) +target_link_libraries(faset_ui PUBLIC faset_core PRIVATE Freetype::Freetype ${FASET_HARFBUZZ_TARGET}) +if(BUILD_TESTING) + add_executable(faset_ui_tests ${PROJECT_SOURCE_DIR}/tests/ui_tests.cpp) + target_link_libraries(faset_ui_tests PRIVATE faset_ui) + target_compile_definitions(faset_ui_tests PRIVATE FASET_TEST_FONT="${PROJECT_SOURCE_DIR}/assets/fonts/NotoSans.ttf") + add_test(NAME ui_widgets COMMAND faset_ui_tests) + if(TARGET faset_render) + add_executable(faset_ui_render_test ${PROJECT_SOURCE_DIR}/tests/ui_render_test.cpp) + target_link_libraries(faset_ui_render_test PRIVATE faset_ui faset_render) + target_compile_definitions(faset_ui_render_test PRIVATE FASET_TEST_FONT="${PROJECT_SOURCE_DIR}/assets/fonts/NotoSans.ttf" FASET_UI_THEME="${PROJECT_SOURCE_DIR}/assets/ui/dark.json") + add_test(NAME ui_render COMMAND faset_ui_render_test ${CMAKE_BINARY_DIR}/ui-test.ppm) + set_tests_properties(ui_render PROPERTIES LABELS "gpu") + endif() +endif() +install(DIRECTORY ${PROJECT_SOURCE_DIR}/assets/fonts ${PROJECT_SOURCE_DIR}/assets/ui DESTINATION assets) diff --git a/dependencies.lock.json b/dependencies.lock.json index 7e9b1a7..39aaf6f 100644 --- a/dependencies.lock.json +++ b/dependencies.lock.json @@ -64,6 +64,22 @@ "url": "https://codeload.github.com/nothings/stb/tar.gz/2c980bb59875b0d32144a71867fbdebb2f77cd20", "sha256": "9a955b1b49a4410088a2e0ee2a9c057c3c907d0c1d75454144cb980aca0ba515", "license": "MIT OR Unlicense" + }, + "freetype": { + "repository": "https://github.com/freetype/freetype", + "version": "2.13.3", + "commit": "42608f77f20749dd6ddc9e0536788eaad70ea4b5", + "url": "https://codeload.github.com/freetype/freetype/tar.gz/42608f77f20749dd6ddc9e0536788eaad70ea4b5", + "sha256": "68ce87bb59ea209eb7350f41a94a27519ce16b37011b475a1e62d4abee154b66", + "license": "FTL" + }, + "harfbuzz": { + "repository": "https://github.com/harfbuzz/harfbuzz", + "version": "10.4.0", + "commit": "3ef8709829a5884517ad91a97b32b9435b2f20d1", + "url": "https://codeload.github.com/harfbuzz/harfbuzz/tar.gz/3ef8709829a5884517ad91a97b32b9435b2f20d1", + "sha256": "61757682efefaa93a6eab7d988d139827e8f35071327cd93e23dc7fd77e0162b", + "license": "MIT" } } } diff --git a/docs/IMPLEMENTATION.md b/docs/IMPLEMENTATION.md index 8cb77d8..444e3dc 100644 --- a/docs/IMPLEMENTATION.md +++ b/docs/IMPLEMENTATION.md @@ -28,9 +28,60 @@ Observed validation on Linux: - MkDocs strict build passed with MkDocs 1.6.1 and Material 9.7.7. The full editor, user-project build pipeline, MCP integration, standalone exports, -and Windows acceptance are still being implemented. This checkpoint is not the MVP release. +and Windows acceptance were still being implemented at that checkpoint. Later progress is recorded below. Known intermediate constraints include box-only physics colliders, root-level physics -objects, static glTF triangles/UV0, a conservative serial renderer, and unfinished -world-preserving authoring reparent operations. These remain implementation work or +objects, static glTF triangles/UV0, a conservative serial renderer, and then-unfinished +world-preserving authoring reparent operations (completed in checkpoint 2). These remain implementation work or explicit profile limits to review during final acceptance. + +## Checkpoint 2 — integrated Editor, gameplay iteration and export + +Implemented and integrated: + +- Separate Player and SchemaExporter executables; statically linked project gameplay, + configurable simulation settings, real contact-based grounded queries, and four + compiled scripting tutorials embedded directly into the English MkDocs manual. +- Shared authoring commands and a real stdio MCP server, optimistic revisions, + transactional retries, jobs/cancellation, recovery of unsaved documents, and + viewport capture in graphical sessions only. +- Cancellable native subprocess execution, incremental project builds, schema export, + binary scene/resource packaging, distinct Debug development and Release export + directories, immutable published generations and retained last-good builds. +- A native retained UI with pinned FreeType/HarfBuzz and bundled Noto Sans: + scene tree, schema Inspector, viewport camera/picking/gizmos, assets, diagnostics, + build/play controls, commands, recovery and startup-loaded extension action panels. +- Exact-build native Editor SDK, dependency validation, owner-bound registrations, + example Beacon runtime component/editor command/panel, and unknown-data preservation. +- Full world-preserving TRS reparent with explicit rejection of unsupported shear. +- Read-only cooked asset target for Player. Import/build/editor/MCP services remain + outside the shipping runtime dependency graph. + +Observed validation: + +- Integrated Linux Clang 21 build: 19 CTests pass, including GPU rendering, retained + widgets, Editor authoring interaction, actual plugin loading, real MCP stdio, + process/cook contracts, and all four compiled gameplay tutorials. +- Real 2D and imported-glTF 3D standalone exports render with zero Vulkan validation + errors on NVIDIA RTX 2080 Ti. Changing gameplay rebuilds metadata; failed C++ + compilation preserves the last successful published build. +- Runtime/tutorial checks also pass with Clang 18; runtime ASan/UBSan checks pass. +- Unmodified Blender 4.5.3 exports through the optional add-on. Real Editor imports + preserve output IDs after rename/geometry edits, report deleted-output conflicts, + retain the last generation on failure, and preserve separate scene placement/color. + Reproduce with `tools/verify_blender_roundtrip.py --blender PATH --editor PATH`. +- Strict MkDocs build passes. Tutorial source snippets are compiled by CTest. +- Previous checkpoint headless Linux and Windows GitHub CI passed after portability + fixes. New checkpoint and full Windows graphical/export checks are separate work; + Linux validation does not imply Windows validation. + +This is an implementation checkpoint, not an MVP release. Finished playable sample +projects, complete Windows graphical/export acceptance, fresh-install checks, +performance measurements, and final UX review remain. Standalone image import is +integrated but its dedicated PNG/JPEG edge-case checks are the next asset task. + +The baseline profile currently uses box colliders, root-level rigid bodies, static +triangle glTF meshes/UV0, basic PBR/directional shadows and a conservative serial +Vulkan renderer. Advanced rendering and broader content profiles remain later work. +The generated UI reference determines visual direction only; architecture, behavior +and acceptance criteria remain authoritative. diff --git a/docs/manual/editor/extensions.md b/docs/manual/editor/extensions.md new file mode 100644 index 0000000..231a168 --- /dev/null +++ b/docs/manual/editor/extensions.md @@ -0,0 +1,58 @@ +# Native Editor extensions + +Editor extensions are startup-loaded `.so`/`.dll` modules. They are trusted native +code inside the Editor process. Gameplay remains statically linked into the separate +Player; an Editor extension is never required by the exported game. + +The initial SDK registers commands and small action panels. Inspector fields for +runtime components come from the separate gameplay SchemaExporter. Rich custom +widgets and a general marketplace/package manager are later work. + +## Example: Beacon + +`examples/extensions/beacon` contains: + +- `Beacon.hpp`: a runtime component schema and rotating-object behavior. +- `Editor.cpp`: an Editor command and a panel that creates a Beacon in one transaction. + +Include `Beacon.hpp` from your project's `Scripts/Gameplay.cpp`. Call +`beacon::register_behavior(runtime)` from `registerGameplay`, and append +`beacon::schema()` to the array returned by `schema()`. Build gameplay so the Editor +can load the new metadata. Read [the first behavior tutorial](../scripting/first-behavior.md) +for the complete gameplay registration convention. + +The normal engine build produces `example-plugin/` inside its build directory. +Copy its `beacon.faset-plugin.json` and native library into your project's +`Plugins/` directory, then restart the Editor. The **Beacon tools** panel offers +**Add Beacon**. Its command is also discoverable through MCP as +`plugin_example_beacon_create` and requires a document ID. + +Disabling the Editor extension removes its panel and command after restart. It does +not erase its saved component data. Removing the runtime registration leaves an +unknown component preserved by authoring; exporting that scene fails until the +runtime dependency is restored or the component is deliberately removed. + +## Compatibility and ownership + +A manifest includes module ID/version, `kind: editor`, API version, native library, +build fingerprint and dependencies with exact versions. The loader validates the +complete graph for missing dependencies and cycles before calling entry points. +A failed dependency prevents loading its dependents. + +The fingerprint includes the SDK sources, dependency lock, platform, architecture, +compiler version, configuration and CRT settings. Rebuild a plugin for the exact +Editor SDK. Compatibility across arbitrary C++ builds is not promised. Reloading an +updated native module requires restarting the Editor. + +`include/faset/editor/plugin_api.h` defines a small C interface. Borrowed UTF-8 JSON +strings are valid during a call; responses are copied through a receiving callback. +Each side frees its own allocations. Register only during startup and invoke the SDK +on the Editor thread. Commands must use their owning module's name prefix. Panels +can invoke owned commands; a `$document` argument resolves to the active authoring +document. No EnTT registry, live runtime world, or arbitrary C++ object pointer is +exposed as a scripting API. + +The native plugin test loads the actual example module, creates a component, +checks Undo, runs its separate runtime behavior, unloads command registrations, +opens the saved scene without the package, and rejects incompatible/cyclic/missing +plugin dependencies. diff --git a/docs/manual/editor/mcp.md b/docs/manual/editor/mcp.md new file mode 100644 index 0000000..fc02753 --- /dev/null +++ b/docs/manual/editor/mcp.md @@ -0,0 +1,85 @@ +# Use the Editor through MCP + +Faset exposes the same authoring commands to its native interface and to MCP. MCP +runs in the **Editor**. It never provides access to a running game's entities, and +is not linked into the Player or SchemaExporter. + +Start a headless server after building Faset: + +```sh +build/linux-debug/faset_editor --project /absolute/path/to/game --mcp +``` + +Configure your MCP client to launch that executable with those arguments using a +stdio transport. On Windows select `build/windows-debug/faset_editor.exe`. Use +absolute paths, including the project path. Add `--gui` when the same process +should display the native Editor; a graphical session and supported GPU are then +required. A separately launched Editor process owns a separate in-memory session. + +The transport uses newline-delimited JSON-RPC and the MCP `2025-06-18` lifecycle. +Initialize, send `notifications/initialized`, then discover commands with +`tools/list`. Standard output is reserved for protocol messages. See the official +[MCP transport](https://modelcontextprotocol.io/specification/2025-06-18/basic/transports) +and [tool contracts](https://modelcontextprotocol.io/specification/2025-06-18/server/tools). + +## Authoring workflow + +1. Use `faset_documents` or create/open a document. +2. Query `faset_schema` for stable type and field IDs and their constraints. +3. Query the document for its persistent ID and current revision. +4. Submit one `faset_scene_edit` batch with that revision. +5. Save with `faset_document_save`. Use Undo/Redo for authoring changes. + +For example, the arguments to `faset_scene_edit` can be: + +```json +{ + "document": "REPLACE_WITH_DOCUMENT_ID", + "revision": 0, + "idempotency_key": "create-first-object", + "operations": [{"op": "entity.create", "name": "Player"}] +} +``` + +The command returns the new revision and scene with generated IDs. Repeating the +same batch and retry key in the same session returns its previous result. Reusing +the key for a different payload is an error. An outdated revision produces +`revision.conflict`; query the new state and decide how to apply the intended change. +Do not blindly retry a write using a fresh revision. + +Each successful batch is one Undo step. A failed operation rejects the whole batch. +Manual Inspector edits use this same service, including revision checks. + +## Jobs and capabilities + +`faset_import`, `faset_build`, `faset_export`, and `faset_play` return job IDs. +Use `faset_job` or `faset_jobs` for progress, diagnostics and results. +`faset_job_cancel` requests cancellation; cancelling a build is separate from +undoing a document change. Failed compilation/import preserves the last successful +published generation. + +`faset_capabilities` reports available services. `faset_editor_capture` is present +only in a graphical Editor. It returns an MCP image and can save a project-relative +PNG. A headless server has no screenshot tool. `faset_play_control` provides pause, +resume and single-step process controls; it cannot read or modify game entities. + +`faset_recovery_list` and `faset_recovery_restore` expose crash recovery, including +scenes that have never been saved. Restoring an already open document requires its +current revision. Recovery refuses to overwrite an externally changed scene file. + +## Single-command CLI + +The CLI is useful for scripts that do not need an MCP session: + +```sh +build/linux-debug/faset_editor --project /absolute/path/to/game \ + --command '{"name":"faset_import","arguments":{"path":"Assets/door/manifest.json"}}' --wait +``` + +`--wait` follows a returned job until completion. Failed, cancelled and conflicting +jobs produce a nonzero exit code. This shell quoting example targets Bash; use the +appropriate argument quoting for your Windows shell. + +Validation: unit tests cover protocol errors and shared authoring semantics. +`editor_mcp_stdio` launches the real Editor and verifies initialization, clean JSON +stdout, conflicts, retry behavior, Undo/Redo, saving, reopening, and orderly EOF. diff --git a/docs/manual/getting-started/build.md b/docs/manual/getting-started/build.md index e7aee02..6144c98 100644 --- a/docs/manual/getting-started/build.md +++ b/docs/manual/getting-started/build.md @@ -1,14 +1,14 @@ # Build from source -!!! warning "Foundation checkpoint" - These instructions initially cover the build foundation. The integrated editor, - sample projects, and packaging steps are being added and verified during MVP implementation. +!!! note "Implementation checkpoint" + Linux Editor, Player and export integration are tested. Final Windows graphics/export + acceptance is tracked separately in the implementation report. ## Linux prerequisites The selected toolchain is C++20, CMake 3.25 or later, Ninja, and Clang. Graphical builds need Vulkan 1.3 headers/loader and a compatible driver. -SDL3 is built from a pinned source archive. +SDL3, FreeType and HarfBuzz are built from pinned source archives. On Ubuntu, install the native build tools before configuring: @@ -16,7 +16,7 @@ On Ubuntu, install the native build tools before configuring: sudo apt install clang ninja-build cmake python3 python3-venv pkg-config \ libvulkan-dev vulkan-validationlayers libx11-dev libxext-dev libxrandr-dev \ libxcursor-dev libxi-dev libxfixes-dev libxkbcommon-dev libwayland-dev \ - libfreetype-dev libharfbuzz-dev xvfb + xvfb ``` `xvfb` is used for automated window tests. A normal desktop session does not need it. @@ -30,6 +30,16 @@ cmake --build --preset linux-debug --parallel ctest --preset linux-debug ``` +Create a project and open the native Editor: + +```sh +build/linux-debug/faset_editor --project "$PWD/MyGame" --new MyGame --dimension 3 +``` + +Use **Build C++** after changing `MyGame/Scripts/Gameplay.cpp`, then **Play**. +The Player runs separately. Stop it before changing and rebuilding C++ gameplay. +See [MCP and CLI](../editor/mcp.md) for headless authoring and automation. + For an optimized build use `linux-release`. The `linux-sanitize` preset enables AddressSanitizer and UndefinedBehaviorSanitizer for tests without the graphics backend. diff --git a/docs/manual/index.md b/docs/manual/index.md index db14450..bc5ac4e 100644 --- a/docs/manual/index.md +++ b/docs/manual/index.md @@ -7,7 +7,7 @@ and how those functions interact with scenes, physics, and the editor. !!! warning "Development status" MVP implementation is in progress. A planned feature is not a working feature. Individual guides state their prerequisites and validation status. The current - foundation can be built and tested; a complete editor and game export are not yet available. + Editor, gameplay tutorials and Linux export can be built and tested. Final Windows graphics/export acceptance and complete sample games are still in progress. Start with [how C++ gameplay works](scripting/index.md), then read [frame and physics updates](scripting/lifecycle.md). See diff --git a/docs/manual/scripting/api.md b/docs/manual/scripting/api.md new file mode 100644 index 0000000..e4603b7 --- /dev/null +++ b/docs/manual/scripting/api.md @@ -0,0 +1,70 @@ +# Runtime API reference + +Include `` and use namespace `faset::runtime`. This is the implemented C++ surface used by the compiled tutorials. The runtime is sequential; call it from its owning thread. + +## Register behavior + +`void Runtime::registerBehavior(std::string componentType, Behavior behavior)` registers callbacks before scene loading. An empty or duplicate type, registration during a callback, and registration after entities have loaded are rejected. + +`Behavior::Callback` is `std::function`. Assign it to any of `onStart`, `fixedUpdate`, `update`, `lateUpdate`, and `onDestroy`. Unassigned members do nothing. `Behavior::onCollision` instead accepts `(Runtime&, EntityHandle, const CollisionEvent&)`. + +See [callback order](lifecycle.md) and the complete [registration example](first-behavior.md). + +## Resolve identity + +- `EntityHandle find(const std::string& persistentId) const` returns a handle, or an empty handle when absent. +- `bool valid(EntityHandle) const noexcept` checks session, entity validity, and generation. +- `std::uint64_t session() const noexcept` identifies this runtime session, not the saved scene. + +A handle contains `session`, `slot`, and `generation`. Its Boolean conversion says it is nonempty; it **does not** prove that the object is still alive. Call `valid` before using a retained handle. A handle from another runtime or an earlier `load` is rejected. + +## Read configuration and poses + +- `nlohmann::json fields(EntityHandle, const std::string& componentType) const` returns a configuration copy. It throws if the type is absent. +- `Transform transform(EntityHandle) const` returns a simulation-pose copy. +- `Transform presentation(EntityHandle) const` returns the pose prepared for display. +- `void setTransform(EntityHandle, const Transform&)` updates a non-physical object. +- `void setPresentation(EntityHandle, const Transform&)` updates presentation only, during `lateUpdate`. + +`Transform` has `position`, `rotation`, and `scale`, each a `std::array`. Position is in metres; rotation is XYZ Euler radians with matrix composition `Rz * Ry * Rx`; scale is a multiplier. The pose is local to its scene parent. The renderer composes the hierarchy. The initial physics adapters require root objects. + +These are values, not borrowed component pointers. Changing a returned copy has no effect until an appropriate setter is called. Presentation writes do not alter physics or the saved scene. + +## Control a rigid body + +- `Vec3 velocity(EntityHandle) const` reads metres per second. A 2D body returns Z = 0. +- `void setVelocity(EntityHandle, Vec3)` sets linear velocity; it does not take a displacement. +- `void applyImpulse(EntityHandle, Vec3)` applies an impulse at the centre and wakes the body. +- `void teleport(EntityHandle, const Transform&)` changes the pose discontinuously, wakes the body, and resets interpolation/contact-query history. It does not zero velocity. +- `bool grounded(EntityHandle) const` tests support using recent native contact normals. + +These methods require a valid handle and a physics body. Ordinary `setTransform` is rejected for physical objects, including static and kinematic bodies. See [physics](physics.md) for dimensions, tolerances, and collider limits. + +## Input and collision events + +`InputState input() const noexcept` returns `horizontal`, `vertical`, `jumpPressed`, and `interactPressed`. The Player maps A/D and left/right arrows to horizontal input, W/S and up/down arrows to vertical input, Space to jump, and E to interact. The gameplay module decides what these actions do. + +`CollisionEvent` contains `first`, `second`, and `began`. `onCollision` receives an event during post-physics delivery. Its reference lasts for that callback; copy the event if you need to retain it, then recheck retained handles before later use. + +`const std::vector& collisions() const noexcept` exposes the most recently completed tick's events. The vector is replaced on a later tick or scene replacement. Polling only once per rendered frame can miss an earlier tick in a multi-tick frame; use callbacks when every delivered event matters. This is contact begin/end notification, not a general event bus or a contact-normal query. + +## Queue structural changes + +- `void spawn(nlohmann::json entity)` queues an entity record with `id`, `name`, `parent`, and `components`. +- `void destroy(EntityHandle)` queues removal of the object and its descendants. +- `void addComponent(EntityHandle, nlohmann::json component)` queues a full component record. +- `void removeComponent(EntityHandle, const std::string& componentType)` queues removal by type. + +Changes are applied in FIFO order at the next fixed-tick barrier. `spawn` does not return an immediately usable handle; use `find(id)` after application. A spawned child's parent must already exist when its command is applied. These commands are individual runtime operations, not an atomic authoring batch with Undo. + +Immediate validation errors throw. Deferred failures are recorded in diagnostics; a stale command does not revive an object. IDs and component types must not collide. The [spawning example](examples.md#spawn-and-destroy-on-safe-boundaries) demonstrates the timing. + +## Drive a world or a test + +`Runtime(RuntimeConfig = {})` constructs the controller. `load(const nlohmann::json&)` validates and prepares a scene, creates its entities, then calls initial callbacks. Invalid scene data leaves the preceding world intact. `clear()` destroys the current entities and invalidates their session handles. + +`FrameStats advance(double elapsedSeconds, InputState = {})` advances fixed ticks, frame callbacks, interpolation, and late callbacks. `singleStep(InputState = {})` advances one fixed tick. `setPaused(bool)` clears accumulated time and resets presentation history; `paused()` reports this local state. Do not call load/clear/advance recursively from a callback. + +`RuntimeConfig` defaults to `fixedDelta = 1.0 / 60.0`, `maxCatchUpTicks = 4`, `physicsSubsteps = 4`, and `gravity = {0, -9.81f, 0}`. `FrameStats` reports fixed ticks performed, dropped time, interpolation fraction, and total tick count. + +`snapshot()` returns a value snapshot for rendering; `snapshotJson()` provides its JSON representation. `diagnostics()` returns a read-only vector of runtime messages. These are native C++ APIs for the Player and tests, **not MCP endpoints**. diff --git a/docs/manual/scripting/examples.md b/docs/manual/scripting/examples.md new file mode 100644 index 0000000..69e275f --- /dev/null +++ b/docs/manual/scripting/examples.md @@ -0,0 +1,50 @@ +# More complete examples + +Each folder below is a separate, buildable gameplay module with `Gameplay.hpp`, `Gameplay.cpp`, and `scene.json`. Select one using `FASET_GAMEPLAY_SOURCE_DIR`, as shown in [the first tutorial](first-behavior.md). The Player links that module statically. + +## Follow an interpolated object + +`examples/tutorials/following` moves an object during fixed updates. A camera follows its presentation pose during `lateUpdate`: + +```cpp +--8<-- "examples/tutorials/following/Gameplay.cpp" +``` + +The camera resolves the saved target ID on each frame, handles its disappearance, reads `presentation(target)`, and writes only its own presentation pose. In this small scene both objects are roots, so their coordinate frames match. For objects under different parents, transform between coordinate frames explicitly; adding local positions from unrelated parents is incorrect. + +The `tutorial_following` test advances one and a half fixed intervals. It checks that the camera follows the halfway presentation position, while its simulation pose is unchanged. It also removes the target to exercise missing-handle behavior. + +## Spawn and destroy on safe boundaries + +`examples/tutorials/spawning` creates a temporary sprite and removes it after its lifetime: + +```cpp +--8<-- "examples/tutorials/spawning/Gameplay.cpp" +``` + +The spawner's `onStart` queues creation. The new object's `onStart` runs only when that command is applied. Its elapsed time is ordinary C++ state owned by the callbacks. A key contains all three handle fields, so a recycled slot or restarted session cannot accidentally reuse an older object's timer. + +When the timer expires, `destroy` queues removal; the handle remains valid until the next barrier. `onDestroy` removes the stored timer entry. The example's `spawned_id` must be unique in the runtime scene: using the same value on several spawners produces a duplicate-ID diagnostic. A production spawner should choose an appropriate runtime ID policy. + +This does not save the spawned object into the authoring document. The test checks deferred creation, eventual invalidation, and a fresh spawn after reloading the scene. + +## Use a contact-based jump + +`examples/tutorials/physics` contains the [complete physics controller](physics.md). Its test checks movement, a supported jump, rejection of a jump at the apex, and landing. The default example gameplay module also uses the same grounded query. + +The query's slope/separation thresholds are intentionally small and explicit. Extend the gameplay controller when your game needs coyote time, jump buffering, climbing steps, or moving platforms; these are not automatically provided by naming a component “character”. + +## Run the tutorial checks + +After configuring a normal build with `BUILD_TESTING=ON`: + +```bash +cmake --build build/linux-debug --target \ + faset_tutorial_moving_tests faset_tutorial_following_tests \ + faset_tutorial_spawning_tests faset_tutorial_physics_tests +ctest --test-dir build/linux-debug -R '^tutorial_' --output-on-failure +``` + +On Windows use the chosen Windows build directory. The four tests compile separate gameplay libraries and execute their actual callbacks. They require neither a graphics window nor the Editor. Running a tutorial through `faset_player` additionally checks rendering and platform integration and requires the documented Vulkan setup. + +Schema declarations are tested for stable map-key/FieldId matching and defaults. They remain ordinary C++ source; the engine does not scan arbitrary C++ classes to create this API automatically. diff --git a/docs/manual/scripting/first-behavior.md b/docs/manual/scripting/first-behavior.md new file mode 100644 index 0000000..cd34471 --- /dev/null +++ b/docs/manual/scripting/first-behavior.md @@ -0,0 +1,67 @@ +# Your first behavior + +This example moves a sprite along the X axis at two metres per second. It has no rigid body: the behavior owns its simulation pose. + +## Build and run the complete example + +First complete [the build setup](../getting-started/build.md), including the renderer dependencies. From the repository root on Linux: + +```bash +cmake -S . -B build/tutorial-moving -G Ninja \ + -DCMAKE_BUILD_TYPE=Debug \ + -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ \ + -DFASET_GAMEPLAY_SOURCE_DIR="$PWD/examples/tutorials/moving" +cmake --build build/tutorial-moving --target faset_player faset_schema_exporter +build/tutorial-moving/faset_schema_exporter --output build/tutorial-moving/schema.json +build/tutorial-moving/faset_player --scene examples/tutorials/moving/scene.json +``` + +On Windows, use a Developer shell with `clang-cl`, the Windows SDK and the documented dependencies. Use `clang-cl` for both compiler options and an absolute path for `FASET_GAMEPLAY_SOURCE_DIR`; run `faset_player.exe` from the selected build directory. + +The same directory contract is used by a project's `Scripts` folder. These commands select a complete gameplay module; they do not add its behavior to an unrelated module automatically. + +## The module interface + +```cpp +--8<-- "examples/tutorials/moving/Gameplay.hpp" +``` + +The header declares the two entry functions. `Runtime` is the game world API; its implementation and EnTT storage remain inside the engine. + +## The implementation + +```cpp +--8<-- "examples/tutorials/moving/Gameplay.cpp" +``` + +Read the callback from top to bottom: + +1. `game` is the current runtime, and `self` is the object carrying `tutorial.move_x`. +2. `delta` is this frame's elapsed time in **seconds**. +3. `settings.value("speed", 2.0f)` reads configuration and supplies a fallback if the field is absent. +4. `transform` gives a pose copy. Multiplying metres per second by seconds gives a displacement in metres. +5. `setTransform` publishes the changed non-physical pose. + +The `[](...) { ... }` expression is a C++ lambda: a function stored in `Behavior::update`. Empty brackets mean it captures no local variables. `registerBehavior` takes ownership of the callback object. Register before calling `load`; registration after a world has loaded is rejected. + +The `schema()` function describes editable configuration. It does not create a runtime object. `tutorial.move_x` is the stable `TypeId`; `speed` is a stable `FieldId` within that type. Keep these IDs when changing a display label. Changing a field's meaning or units needs an explicit data migration, not just a new label. + +## Attach the behavior + +The example scene is a complete, loadable document: + +```json +--8<-- "examples/tutorials/moving/scene.json" +``` + +The sprite is visible because it has `faset.sprite`. It moves because it also has `tutorial.move_x`. The configuration field is `speed`; the type string must match the registration exactly. `rotation` uses radians, and the default coordinate system is Y-up. + +After your project's schema is exported and loaded by the Editor, the type can be described through the same authoring schema used by the Inspector. The direct Player command above is useful before building an Editor workflow around your component. + +## Make a change and verify it + +Change the scene's `speed` to `-2`: the object moves left. Change the C++ callback or schema: stop the Player, rebuild, regenerate the schema, then launch a new session. There is no automatic C++ hot reload. + +The `tutorial_moving` CTest checks that both 30 Hz and 60 Hz frame sequences move the object two metres in one second. It checks the resulting pose, rather than only checking that the program starts. + +Common mistakes are forgetting `setTransform` after editing the copy, writing the wrong component type string, and attaching a rigid body while still using `setTransform`. The last case produces a runtime diagnostic: physics owns that body's pose. Continue with [physics movement](physics.md) for the correct API. diff --git a/docs/manual/scripting/index.md b/docs/manual/scripting/index.md index 75d1a98..ac0ef4f 100644 --- a/docs/manual/scripting/index.md +++ b/docs/manual/scripting/index.md @@ -1,41 +1,40 @@ # C++ gameplay -In the first version of Faset, a "script" is C++ gameplay code compiled into your game. -It is not an interpreted text file. The gameplay library is statically linked into -a separate Player executable. +In Faset, a gameplay script is **C++ compiled into the Player**. You write ordinary functions and register the callbacks an object needs. There is no C++ interpreter or live replacement of compiled classes. Stop Play, rebuild, export the schema, and start a new Player session. -The intended iteration cycle is: +Lua is planned for a later stage. The APIs and tutorials in this section describe the C++ implementation available now. -1. Stop Play. -2. Edit your C++ behavior or system. -3. Build the changed code and export its property schema. -4. Start a new Player session. +## Start here -The Editor reads a schema generated by a separate SchemaExporter. It does not load -your gameplay library into its own process. A gameplay crash therefore does not -automatically crash the Editor. Editor native extensions have a different lifecycle -and run inside the Editor process. +1. Read [Your first behavior](first-behavior.md) and run the moving-object example. +2. Learn [when callbacks run](lifecycle.md) before mixing frame updates and physics. +3. Build a [physics character](physics.md) that can move and jump from the floor. +4. Try [following, spawning, and timed destruction](examples.md). +5. Keep the [runtime API reference](api.md) nearby while writing code. -!!! note "API examples are added with implementation" - This page describes the accepted execution model. Exact function signatures and - complete examples will be documented alongside compiling runtime examples, rather - than presenting proposed APIs as available functions. +The complete tutorial modules are compiled and executed by CTest. The code blocks include those source files directly, so the manual does not maintain separate, untested copies. -## Behaviors and systems +## What belongs to your module -A behavior gives an individual object lifecycle callbacks. A system operates on a -set of objects with matching components. Both use the same runtime state; the visual -scene and Inspector are the authoring view of that state. +A gameplay directory contains `Gameplay.hpp` and `Gameplay.cpp`. It provides two functions in `faset::gameplay`: -Persistent scene IDs and runtime handles are different. A scene ID survives saving -and reopening. A runtime handle belongs to a particular world/session and can become -invalid after an object is removed. Do not store raw component pointers across -structural changes or treat a runtime handle as a save-file ID. +- `registerGameplay(runtime::Runtime&)` registers executable behavior callbacks. +- `schema()` returns a JSON array of component descriptions: stable type and field IDs, versions, defaults, constraints, and Inspector hints. -## Physics ownership +The Player calls registration before loading a scene. The separate SchemaExporter calls `schema()` without creating a game world or running gameplay callbacks. The Editor reads the resulting declaration; it does not load the gameplay binary into the Editor process. -Physics owns the position of a dynamic rigid body. Move it with the supported physics -commands instead of writing its presentation transform. A camera or other visual-only -object can follow the interpolated result without modifying the simulation. +A scene object receives a behavior by containing a component whose `type` matches the string passed to `registerBehavior`. Registering a behavior does not attach it to every object. A component can contain data without having any callbacks. -Continue with [Frame and physics updates](lifecycle.md). +## Data, poses, and state + +`fields(self, type)` returns a **copy of component configuration**. Editing that copy changes neither the saved scene nor the runtime configuration. `transform(self)` returns a copy of the current simulation pose; pass the changed copy to `setTransform` for a non-physical object. A rigid body uses `setVelocity`, `applyImpulse`, or an explicit `teleport` instead. + +Ordinary C++ state can be captured by callbacks. The spawning tutorial shows state indexed by the full runtime handle and cleaned up in `onDestroy`. Do not capture a reference to a local variable that will disappear after `registerGameplay` returns. Use owned state, or ensure the referenced object outlives the runtime. + +Scene IDs are saved strings. `EntityHandle` is a temporary reference containing a session, slot, and generation. It must not be written into a save file. Resolve a scene ID with `find`, check `valid`, and expect old handles to stop working after removal or a new Play session. + +## Current boundaries + +These examples use per-object callbacks and the implemented typed pose/physics API. They do not provide a universal binding for arbitrary C++ classes, a public EnTT registry, or a general parallel-system scheduler. The runtime is sequential and has one owning thread. + +MCP belongs to the Editor's authoring, import, build, and process-control services. It does not invoke runtime methods or inspect the live game world. A C++ gameplay change requires the same rebuild whether a person or an agent edited the source. diff --git a/docs/manual/scripting/lifecycle.md b/docs/manual/scripting/lifecycle.md index 5aabe01..4e7fbff 100644 --- a/docs/manual/scripting/lifecycle.md +++ b/docs/manual/scripting/lifecycle.md @@ -1,47 +1,61 @@ # Frame and physics updates -!!! note "Execution contract" - This page describes the accepted runtime contract. The runnable callback examples - and test results are added as the runtime implementation becomes available. +The C++ member names are `onStart`, `fixedUpdate`, `update`, `lateUpdate`, and `onDestroy`. Design discussions may call the corresponding phases OnStart, FixedUpdate, Update, LateUpdate, and OnDestroy. Use the **camelCase member names** in code. -## Choose the right callback +Each ordinary callback receives `(Runtime& game, EntityHandle self, double delta)`. Register only the callbacks you need. `onStart` and `onDestroy` receive a zero `delta`; update callbacks receive seconds. `onCollision` has a separate event signature described in the [API reference](api.md). -- `OnStart`: initialize a behavior once its object and components exist. -- `FixedUpdate`: update simulation logic before a physics step. -- `Update`: run frame-based gameplay once per rendered frame. -- `LateUpdate`: update cameras and dependent visual objects after presentation interpolation. -- `OnDestroy`: release subscriptions and other behavior-owned state before its handle is invalidated. +## Object lifetime -The default simulation interval is 1/60 second. A rendered frame may contain zero, -one, or several fixed ticks. Frame rate and physics rate are not the same quantity. +`onStart` runs once after an object and its components exist. All objects in the initial scene are created before their initial callbacks run. A spawn queued by `onStart` becomes visible at the next fixed-tick barrier, not during the callback that requested it. -## Fixed tick order +`onDestroy` runs while that object's handle and allowed component data are still valid. Clean up subscriptions or external C++ state there. After removal, `valid(oldHandle)` returns false. Removing a behavior component also runs that component's `onDestroy`. Clearing or replacing a scene runs destruction callbacks; a new scene uses a new session identity. -1. Apply structural commands queued by earlier work. -2. Deliver tick input and call `FixedUpdate`. -3. Apply physics commands and step the 2D and 3D worlds. -4. Read back transforms and queue collision events. -5. Run reactions after physics. +Registering a callback does not make captured pointers safe. A lambda that stores a reference to a stack variable in `registerGameplay` will outlive that variable. The [timed-despawn example](examples.md#spawn-and-destroy-on-safe-boundaries) uses shared ownership for captured state and removes each object's entry on destruction. -Object creation/removal and component addition/removal are deferred to the beginning -of the next fixed tick. This prevents a callback from invalidating the collection -currently being processed. New objects follow the same initialization rules as objects -loaded from a scene. +## One fixed tick -After the fixed ticks, the frame runs `Update`, prepares interpolated presentation -transforms, calls `LateUpdate`, and produces the render snapshot. +The default interval is 1/60 second. A rendered frame may contain zero, one, or several fixed ticks. For each tick the runtime: -## Avoid frame-rate-dependent movement +1. Applies structural commands queued by earlier work, in FIFO order. +2. Makes tick input available and calls `fixedUpdate`. +3. Steps the scene's Box2D or Box3D world with its configured substeps. +4. Reads physical poses back and delivers collision events to `onCollision` callbacks. -A speed is a distance per second. Multiply it by the callback's elapsed seconds when -calculating a displacement. Do not multiply a velocity by elapsed time before assigning -it to a physics velocity API; the physics step performs that integration. +`spawn`, `destroy`, `addComponent`, and `removeComponent` queue structural changes. A command queued while this barrier or a callback runs waits until the **next** tick. This avoids invalidating the entity collection currently being visited. Runtime structural commands do not create an Editor Undo action or modify a saved scene. -## Overload and pause +A velocity is metres per second: assign it directly. A manually calculated displacement is speed multiplied by `delta`. The [physics controller](physics.md) demonstrates this distinction. -The initial catch-up limit is four fixed ticks per frame. Excess whole intervals are -dropped with a diagnostic rather than making the physics step arbitrarily large. -This is a local-game policy, not a guarantee of deterministic network simulation. +## One rendered frame -Pausing clears accumulated time. Single-step advances exactly one simulation tick. -Interpolation history is reset for a new session, spawn, or teleport. +After its fixed ticks, the runtime calls `update` once. It then prepares presentation transforms, calls `lateUpdate`, and makes the final snapshot available to rendering. + +For interpolation, the runtime blends the previous and current completed simulation poses using the accumulator fraction. Position and scale are interpolated linearly; rotation follows the shortest quaternion path. This normally displays a pose up to one fixed tick behind the latest simulated state. It is not prediction of a future physics pose. + +Use `presentation(target)` in `lateUpdate` when a camera follows a physical object. Following `transform(target)` instead would follow the discrete simulation pose and can cause visible judder. Use `setPresentation` for the camera's visual pose; this method is permitted only during `lateUpdate` and does not write back into physics. + +A non-physical pose changed in `update` is presented directly for that frame. Physical bodies reject ordinary `setTransform`; use an explicit teleport when discontinuous motion is intended. Spawn, teleport, scene replacement, and pause transitions reset the relevant interpolation history. + +## Input, pause, and overload + +`input()` supplies held horizontal/vertical axes and one-shot jump/interact edges. In `fixedUpdate`, an edge survives a rendered frame with no fixed tick and is consumed once, even when the next frame catches up several ticks. In `update`, input is the current frame's input. Consume a gameplay action in one chosen phase so your own code does not apply it twice. + +The default catch-up limit is four ticks per frame. Excess whole intervals are dropped and reported as `dropped_time`; the fractional remainder is retained. Physics `delta` is not enlarged to compensate. This is a local-game policy, not a lockstep or rollback guarantee. + +Player keys `P` and `N` pause and single-step. Pause clears accumulated wall time. One step advances one fixed tick and produces a current presentation pose. Resuming does not simulate the time spent paused. + +## Configure simulation + +The Player reads this optional object from the scene document. The settings are used by ordinary Play and `--validate`: + +```json +{ + "simulation": { + "fixed_delta": 0.016666666666666666, + "max_catch_up_ticks": 4, + "physics_substeps": 4, + "gravity": [0, -9.81, 0] + } +} +``` + +This is an excerpt, not a complete scene. The tutorial scenes contain complete examples. `fixed_delta` is seconds, gravity is metres per second squared, and substeps are solver subdivisions inside one fixed tick. These do not create additional gameplay callbacks. Invalid configuration is rejected before the Player starts. Editing these JSON settings is implemented; an Editor settings panel should only be relied on where the current UI exposes it. diff --git a/docs/manual/scripting/physics.md b/docs/manual/scripting/physics.md new file mode 100644 index 0000000..8fe5c6b --- /dev/null +++ b/docs/manual/scripting/physics.md @@ -0,0 +1,49 @@ +# Move and jump with physics + +A physical object's final pose belongs to Box2D or Box3D. Your behavior supplies intent through velocity, impulse, or an explicit teleport. It must not write a presentation position back into a rigid body each frame. + +## Run the controller + +Select `examples/tutorials/physics` as `FASET_GAMEPLAY_SOURCE_DIR`, build `faset_player`, and launch it with `--scene examples/tutorials/physics/scene.json`. Use the commands from [the first tutorial](first-behavior.md), changing the folder and build directory. + +Press **A/D** or the left/right arrows to move, and **Space** to jump. The built-in Player supplies W/S as a vertical input axis too; this particular 2D controller deliberately uses only the horizontal axis. `P` pauses, `N` advances one tick while paused, and Escape closes the Player. + +## Complete controller code + +```cpp +--8<-- "examples/tutorials/physics/Gameplay.cpp" +``` + +The callback starts with the current velocity so it preserves the solver's vertical motion. It replaces only the horizontal component. An accepted jump replaces vertical velocity with `jump_speed`. + +Do **not** multiply the assigned velocity by `delta`. The solver integrates metres per second over the fixed interval. `applyImpulse` is different: it applies a momentum impulse and its effect depends on mass. The adapter uses the body's centre and wakes it. + +The collision callback is delivered after the physics step on the runtime's owning thread. It receives copied handles and a begin/end flag, not pointers into the native solver. This example prints a message when contact begins. Both objects can receive their own callback if both have registered behaviors. + +## What grounded means + +`grounded(self)` examines contact manifolds from the last completed physics step. A contact counts as support when its normal points sufficiently against gravity (dot product greater than 0.6) and at least one contact point is within 0.02 metres. With zero gravity, the query uses Y-up. The query supports both physics adapters. + +This distinguishes a floor from a wall and from the top of a jump. **Zero vertical speed is not a ground test**: vertical speed is also near zero at the apex. The tests explicitly try to jump there and check that another upward impulse is not created. + +New bodies have no support result before a physics step. Teleporting invalidates the old contact result until the next step. The query is a small support test; it is not a full character motor with step climbing, coyote time, jump buffering, moving-platform attachment, or a capsule controller. + +## Scene components and units + +The controller's scene includes a static floor and a dynamic box: + +```json +--8<-- "examples/tutorials/physics/scene.json" +``` + +Use `faset.rigid_body_2d` in a 2D scene and `faset.rigid_body_3d` in a 3D scene. Each currently creates a box collider. `body_type` accepts `static`, `dynamic`, or `kinematic`. `half_extents` contains half the box dimensions in metres: two values for 2D, three for 3D. The object's absolute scale multiplies those extents at creation. + +Density must be positive; friction is nonnegative; restitution is between zero and one. `linear_velocity` uses metres per second, `gravity_scale` scales world gravity for that body, and `category_bits`/`mask_bits` filter collisions. Rotation uses radians; a 2D rigid body rotates only around Z. + +Initial adapters require physical bodies to be **root scene objects**. A parent transform is not silently baked into a rigid body's simulation frame. Collider scale cannot be changed through teleport; remove/re-add the body through the deferred component API when rebuilding its shape. More collider types and articulated character motors are separate work. + +## Teleport and failure handling + +For an intentional discontinuity, get a pose copy, change its position, and call `teleport(self, pose)`. It resets interpolation and wakes the body. It preserves the body's velocity; call `setVelocity(self, {0, 0, 0})` as well when resetting motion is intended. + +A missing body or stale handle makes the physics accessor throw. Exceptions raised inside gameplay callbacks are recorded in `Runtime::diagnostics()` and printed by the Player; later phases continue. Fix the error instead of using exceptions as a normal ground test. A behavior that controls physics should be attached only to an object with the matching rigid-body component. diff --git a/examples/extensions/beacon/Beacon.hpp b/examples/extensions/beacon/Beacon.hpp new file mode 100644 index 0000000..4126395 --- /dev/null +++ b/examples/extensions/beacon/Beacon.hpp @@ -0,0 +1,28 @@ +#pragma once +#include + +namespace beacon { +inline nlohmann::json schema() { + return {{"id", "example.beacon"}, + {"name", "Beacon"}, + {"version", 1}, + {"fields", + {{"speed", + {{"id", "speed"}, + {"name", "Rotation speed"}, + {"type", "number"}, + {"default", 1.0}, + {"units", "rad/s"}}}}}}; +} +inline void register_behavior(faset::runtime::Runtime& runtime) { + faset::runtime::Behavior behavior; + behavior.fixedUpdate = [](faset::runtime::Runtime& world, faset::runtime::EntityHandle self, + double dt) { + auto pose = world.transform(self); + pose.rotation[1] += + world.fields(self, "example.beacon").value("speed", 1.0f) * static_cast(dt); + world.setTransform(self, pose); + }; + runtime.registerBehavior("example.beacon", std::move(behavior)); +} +} // namespace beacon diff --git a/examples/extensions/beacon/Editor.cpp b/examples/extensions/beacon/Editor.cpp new file mode 100644 index 0000000..2262281 --- /dev/null +++ b/examples/extensions/beacon/Editor.cpp @@ -0,0 +1,119 @@ +#include +#include +#include +#include +#include +#include +#include + +namespace { +using Json = nlohmann::json; +struct State { + const FasetEditorHost* host; +}; +void collect(void* target, const char* data, uint64_t size) { + static_cast(target)->append(data, size); +} +Json invoke(State& state, const char* command, const Json& arguments) { + std::string output; + const auto input = arguments.dump(); + const auto status = + state.host->invoke_command(state.host->context, command, input.c_str(), collect, &output); + auto result = Json::parse(output); + if (status != 0) + throw std::runtime_error(result.value("message", std::string("Editor command failed"))); + return result; +} +std::string id() { + std::random_device random; + std::ostringstream stream; + stream << std::hex << std::setfill('0'); + for (int i = 0; i < 4; ++i) + stream << std::setw(8) << random(); + return stream.str(); +} +int create(void* user, const char* input, FasetWrite write, void* receiver) { + try { + auto& state = *static_cast(user); + const auto arguments = Json::parse(input); + const auto document = + invoke(state, "faset_document_query", {{"document", arguments.at("document")}}); + const auto schema = invoke(state, "faset_schema", Json::object()); + bool known = false; + for (const auto& type : schema.at("types")) + if (type.at("id") == "example.beacon") + known = true; + if (!known) + throw std::runtime_error("Include Beacon.hpp in gameplay, register its schema and " + "behavior, then Build before adding a Beacon"); + const auto entity = id(); + Json record = { + {"id", entity}, + {"name", "Beacon"}, + {"parent", nullptr}, + {"components", + Json::array( + {{{"id", id()}, + {"type", "faset.transform"}, + {"version", 1}, + {"fields", + {{"position", {0, 1, 0}}, {"rotation", {0, 0, 0}}, {"scale", {1, 1, 1}}}}}, + {{"id", id()}, + {"type", "faset.mesh"}, + {"version", 1}, + {"fields", + {{"asset", ""}, {"primitive", "cube"}, {"color", {0.68, 0.55, 0.95, 1}}}}}, + {{"id", id()}, + {"type", "example.beacon"}, + {"version", 1}, + {"fields", {{"speed", 1.0}}}}})}}; + const auto result = + invoke(state, "faset_scene_edit", + {{"document", document.at("id")}, + {"revision", document.at("revision")}, + {"operations", Json::array({{{"op", "entity.create"}, {"entity", record}}})}}) + .dump(); + write(receiver, result.data(), result.size()); + return 0; + } catch (const std::exception& error) { + const auto output = Json{{"code", "beacon.create"}, {"message", error.what()}}.dump(); + write(receiver, output.data(), output.size()); + return 1; + } +} +void shutdown(void* user) { + delete static_cast(user); +} +} // namespace +extern "C" FASET_PLUGIN_EXPORT int faset_editor_plugin(const FasetEditorHost* host, + FasetEditorPlugin* plugin) { + if (!host || !plugin || host->api_version != FASET_EDITOR_API_VERSION || + host->struct_size != sizeof(FasetEditorHost) || + std::string(host->build_fingerprint) != FASET_EDITOR_SDK_FINGERPRINT) + return 1; + try { + auto* state = new State{host}; + *plugin = {FASET_EDITOR_API_VERSION, sizeof(FasetEditorPlugin), + FASET_EDITOR_SDK_FINGERPRINT, state, shutdown}; + const auto descriptor = Json{ + {"name", "plugin_example_beacon_create"}, + {"description", "Create a rotating Beacon using one authoring transaction."}, + {"inputSchema", + {{"type", "object"}, + {"properties", {{"document", {{"type", "string"}}}}}, + {"required", {"document"}}, + {"additionalProperties", + false}}}}.dump(); + if (host->register_command(host->context, descriptor.c_str(), create, state) != 0) + return 1; + const auto panel = Json{{"id", "example.beacon.tools"}, + {"title", "Beacon tools"}, + {"action", "Add Beacon"}, + {"command", "plugin_example_beacon_create"}, + {"arguments", {{"document", "$document"}}}} + .dump(); + return host->register_panel(host->context, panel.c_str()); + } catch (...) { + return 1; + } +} diff --git a/examples/gameplay/Gameplay.cpp b/examples/gameplay/Gameplay.cpp index f9c63be..5e90024 100644 --- a/examples/gameplay/Gameplay.cpp +++ b/examples/gameplay/Gameplay.cpp @@ -6,46 +6,65 @@ namespace faset::gameplay { void registerGameplay(runtime::Runtime& engine) { runtime::Behavior character; - character.fixedUpdate=[](runtime::Runtime& world,runtime::EntityHandle self,double) { - const auto fields=world.fields(self,"gameplay.character"); - auto velocity=world.velocity(self);const auto input=world.input(); - velocity[0]=input.horizontal*fields.value("speed",4.0f); - // A minimal demo controller: jump only near zero vertical velocity. - // A production grounded controller needs contact normals / a ground query. - if(input.jumpPressed&&std::abs(velocity[1])<0.1f)velocity[1]=fields.value("jump_speed",5.0f); - world.setVelocity(self,velocity); + character.fixedUpdate = [](runtime::Runtime& world, runtime::EntityHandle self, double) { + const auto fields = world.fields(self, "gameplay.character"); + auto velocity = world.velocity(self); + const auto input = world.input(); + velocity[0] = input.horizontal * fields.value("speed", 4.0f); + if (input.jumpPressed && world.grounded(self)) + velocity[1] = fields.value("jump_speed", 5.0f); + world.setVelocity(self, velocity); }; - engine.registerBehavior("gameplay.character",std::move(character)); + engine.registerBehavior("gameplay.character", std::move(character)); runtime::Behavior door; - auto open=std::make_shared,bool>>(); - door.onStart=[open](runtime::Runtime&,runtime::EntityHandle self,double){(*open)[{self.session,self.slot}]=false;}; - door.onDestroy=[open](runtime::Runtime&,runtime::EntityHandle self,double){open->erase({self.session,self.slot});}; - door.fixedUpdate=[open](runtime::Runtime& world,runtime::EntityHandle self,double dt) { - const auto fields=world.fields(self,"gameplay.door"); - auto pose=world.transform(self); - auto& opened=(*open)[{self.session,self.slot}]; - if(world.input().interactPressed)opened=!opened; - const float target=opened?fields.value("open_angle",1.5707963f):fields.value("closed_angle",0.0f); - const float distance=target-pose.rotation[1]; - const float amount=std::max(0.0f,fields.value("speed",1.5f))*static_cast(dt); - pose.rotation[1]+=std::clamp(distance,-amount,amount); - world.setTransform(self,pose); + auto open = std::make_shared, bool>>(); + door.onStart = [open](runtime::Runtime&, runtime::EntityHandle self, double) { + (*open)[{self.session, self.slot}] = false; }; - engine.registerBehavior("gameplay.door",std::move(door)); + door.onDestroy = [open](runtime::Runtime&, runtime::EntityHandle self, double) { + open->erase({self.session, self.slot}); + }; + door.fixedUpdate = [open](runtime::Runtime& world, runtime::EntityHandle self, double dt) { + const auto fields = world.fields(self, "gameplay.door"); + auto pose = world.transform(self); + auto& opened = (*open)[{self.session, self.slot}]; + if (world.input().interactPressed) + opened = !opened; + const float target = + opened ? fields.value("open_angle", 1.5707963f) : fields.value("closed_angle", 0.0f); + const float distance = target - pose.rotation[1]; + const float amount = std::max(0.0f, fields.value("speed", 1.5f)) * static_cast(dt); + pose.rotation[1] += std::clamp(distance, -amount, amount); + world.setTransform(self, pose); + }; + engine.registerBehavior("gameplay.door", std::move(door)); } nlohmann::json schema() { // Explicit declarations shared by Player and SchemaExporter. This function // constructs descriptions only: no Runtime, physics world or lifecycle. - return nlohmann::json::array({ - {{"id","gameplay.character"},{"version",1},{"name","Character"},{"fields",{ - {"speed",{{"id","speed"},{"type","number"},{"default",4.0},{"min",0.0}}}, - {"jump_speed",{{"id","jump_speed"},{"type","number"},{"default",5.0},{"min",0.0}}}}}}, - {{"id","gameplay.door"},{"version",1},{"name","Door"},{"fields",{ - {"open_angle",{{"id","open_angle"},{"type","number"},{"default",1.5707963},{"units","rad"}}}, - {"closed_angle",{{"id","closed_angle"},{"type","number"},{"default",0.0},{"units","rad"}}}, - {"speed",{{"id","speed"},{"type","number"},{"default",1.5},{"min",0.0},{"units","rad/s"}}}}}} - }); -} + return nlohmann::json::array( + {{{"id", "gameplay.character"}, + {"version", 1}, + {"name", "Character"}, + {"fields", + {{"speed", {{"id", "speed"}, {"type", "number"}, {"default", 4.0}, {"min", 0.0}}}, + {"jump_speed", + {{"id", "jump_speed"}, {"type", "number"}, {"default", 5.0}, {"min", 0.0}}}}}}, + {{"id", "gameplay.door"}, + {"version", 1}, + {"name", "Door"}, + {"fields", + {{"open_angle", + {{"id", "open_angle"}, {"type", "number"}, {"default", 1.5707963}, {"units", "rad"}}}, + {"closed_angle", + {{"id", "closed_angle"}, {"type", "number"}, {"default", 0.0}, {"units", "rad"}}}, + {"speed", + {{"id", "speed"}, + {"type", "number"}, + {"default", 1.5}, + {"min", 0.0}, + {"units", "rad/s"}}}}}}}); } +} // namespace faset::gameplay diff --git a/examples/gameplay/Gameplay.hpp b/examples/gameplay/Gameplay.hpp index 18adf46..536ab72 100644 --- a/examples/gameplay/Gameplay.hpp +++ b/examples/gameplay/Gameplay.hpp @@ -4,4 +4,4 @@ namespace faset::gameplay { void registerGameplay(runtime::Runtime& runtime); nlohmann::json schema(); -} +} // namespace faset::gameplay diff --git a/examples/tutorials/following/Gameplay.cpp b/examples/tutorials/following/Gameplay.cpp new file mode 100644 index 0000000..3c666ab --- /dev/null +++ b/examples/tutorials/following/Gameplay.cpp @@ -0,0 +1,43 @@ +#include "Gameplay.hpp" + +namespace faset::gameplay { +void registerGameplay(runtime::Runtime& world) { + runtime::Behavior motion; + motion.fixedUpdate = [](runtime::Runtime& game, runtime::EntityHandle self, double delta) { + auto pose = game.transform(self); + pose.position[0] += game.fields(self, "tutorial.fixed_move").value("speed", 2.0f) * + static_cast(delta); + game.setTransform(self, pose); + }; + world.registerBehavior("tutorial.fixed_move", std::move(motion)); + + runtime::Behavior follow; + follow.lateUpdate = [](runtime::Runtime& game, runtime::EntityHandle self, double) { + const auto settings = game.fields(self, "tutorial.follow"); + const auto target = game.find(settings.value("target", std::string{})); + if (!game.valid(target)) + return; // Target may be absent or destroyed. + const auto targetPose = game.presentation(target); // Already interpolated. + const auto offset = settings.at("offset").get(); + auto cameraPose = game.presentation(self); + for (int axis = 0; axis < 3; ++axis) + cameraPose.position[axis] = targetPose.position[axis] + offset[axis]; + game.setPresentation(self, cameraPose); // Does not write the simulation pose. + }; + world.registerBehavior("tutorial.follow", std::move(follow)); +} + +nlohmann::json schema() { + return nlohmann::json::array( + {{{"id", "tutorial.fixed_move"}, + {"version", 1}, + {"name", "Fixed movement"}, + {"fields", {{"speed", {{"id", "speed"}, {"type", "number"}, {"default", 2.0}}}}}}, + {{"id", "tutorial.follow"}, + {"version", 1}, + {"name", "Follow presentation"}, + {"fields", + {{"target", {{"id", "target"}, {"type", "entity_ref"}, {"default", "actor"}}}, + {"offset", {{"id", "offset"}, {"type", "vec3"}, {"default", {0, 0, 10}}}}}}}}); +} +} // namespace faset::gameplay diff --git a/examples/tutorials/following/Gameplay.hpp b/examples/tutorials/following/Gameplay.hpp new file mode 100644 index 0000000..d9caafe --- /dev/null +++ b/examples/tutorials/following/Gameplay.hpp @@ -0,0 +1,7 @@ +#pragma once +#include + +namespace faset::gameplay { +void registerGameplay(runtime::Runtime& world); +nlohmann::json schema(); +} // namespace faset::gameplay diff --git a/examples/tutorials/following/scene.json b/examples/tutorials/following/scene.json new file mode 100644 index 0000000..72187d7 --- /dev/null +++ b/examples/tutorials/following/scene.json @@ -0,0 +1,126 @@ +{ + "format": "faset.scene", + "version": 1, + "id": "tutorial-following", + "name": "Following tutorial", + "dimension": 2, + "simulation": { + "fixed_delta": 0.016666666666666666, + "max_catch_up_ticks": 4, + "physics_substeps": 4, + "gravity": [ + 0, + -9.81, + 0 + ] + }, + "entities": [ + { + "id": "actor", + "name": "actor", + "parent": null, + "components": [ + { + "id": "actor-faset.transform", + "type": "faset.transform", + "version": 1, + "fields": { + "position": [ + 0, + 0, + 0 + ], + "rotation": [ + 0, + 0, + 0 + ], + "scale": [ + 1, + 1, + 1 + ] + } + }, + { + "id": "actor-faset.sprite", + "type": "faset.sprite", + "version": 1, + "fields": { + "color": [ + 0.2, + 0.7, + 0.9, + 1 + ], + "size": [ + 1, + 1 + ] + } + }, + { + "id": "actor-tutorial.fixed_move", + "type": "tutorial.fixed_move", + "version": 1, + "fields": { + "speed": 2 + } + } + ] + }, + { + "id": "camera", + "name": "camera", + "parent": null, + "components": [ + { + "id": "camera-faset.transform", + "type": "faset.transform", + "version": 1, + "fields": { + "position": [ + 0, + 0, + 10 + ], + "rotation": [ + 0, + 0, + 0 + ], + "scale": [ + 1, + 1, + 1 + ] + } + }, + { + "id": "camera-faset.camera", + "type": "faset.camera", + "version": 1, + "fields": { + "fov": 60, + "near": 0.1, + "far": 100 + } + }, + { + "id": "camera-tutorial.follow", + "type": "tutorial.follow", + "version": 1, + "fields": { + "target": "actor", + "offset": [ + 0, + 0, + 10 + ] + } + } + ] + } + ], + "instances": [] +} diff --git a/examples/tutorials/moving/Gameplay.cpp b/examples/tutorials/moving/Gameplay.cpp new file mode 100644 index 0000000..2b14bae --- /dev/null +++ b/examples/tutorials/moving/Gameplay.cpp @@ -0,0 +1,31 @@ +#include "Gameplay.hpp" + +namespace faset::gameplay { +void registerGameplay(runtime::Runtime& world) { + runtime::Behavior mover; + mover.update = [](runtime::Runtime& game, runtime::EntityHandle self, double delta) { + // fields() returns a configuration copy. transform() returns a live pose copy. + const auto settings = game.fields(self, "tutorial.move_x"); + const float speed = settings.value("speed", 2.0f); // metres per second + auto pose = game.transform(self); + pose.position[0] += speed * static_cast(delta); + game.setTransform(self, pose); // This object has no rigid body. + }; + world.registerBehavior("tutorial.move_x", std::move(mover)); +} + +nlohmann::json schema() { + // The FieldId is the map key. Keep it stable if you change a display name. + return nlohmann::json::array({{{"id", "tutorial.move_x"}, + {"version", 1}, + {"name", "Move along X"}, + {"fields", + {{"speed", + {{"id", "speed"}, + {"type", "number"}, + {"default", 2.0}, + {"min", -20.0}, + {"max", 20.0}, + {"units", "m/s"}}}}}}}); +} +} // namespace faset::gameplay diff --git a/examples/tutorials/moving/Gameplay.hpp b/examples/tutorials/moving/Gameplay.hpp new file mode 100644 index 0000000..d9caafe --- /dev/null +++ b/examples/tutorials/moving/Gameplay.hpp @@ -0,0 +1,7 @@ +#pragma once +#include + +namespace faset::gameplay { +void registerGameplay(runtime::Runtime& world); +nlohmann::json schema(); +} // namespace faset::gameplay diff --git a/examples/tutorials/moving/scene.json b/examples/tutorials/moving/scene.json new file mode 100644 index 0000000..0158309 --- /dev/null +++ b/examples/tutorials/moving/scene.json @@ -0,0 +1,74 @@ +{ + "format": "faset.scene", + "version": 1, + "id": "tutorial-moving", + "name": "Moving tutorial", + "dimension": 2, + "simulation": { + "fixed_delta": 0.016666666666666666, + "max_catch_up_ticks": 4, + "physics_substeps": 4, + "gravity": [ + 0, + -9.81, + 0 + ] + }, + "entities": [ + { + "id": "actor", + "name": "actor", + "parent": null, + "components": [ + { + "id": "actor-faset.transform", + "type": "faset.transform", + "version": 1, + "fields": { + "position": [ + 0, + 0, + 0 + ], + "rotation": [ + 0, + 0, + 0 + ], + "scale": [ + 1, + 1, + 1 + ] + } + }, + { + "id": "actor-faset.sprite", + "type": "faset.sprite", + "version": 1, + "fields": { + "color": [ + 0.2, + 0.7, + 0.9, + 1 + ], + "size": [ + 1, + 1 + ] + } + }, + { + "id": "actor-tutorial.move_x", + "type": "tutorial.move_x", + "version": 1, + "fields": { + "speed": 2 + } + } + ] + } + ], + "instances": [] +} diff --git a/examples/tutorials/physics/Gameplay.cpp b/examples/tutorials/physics/Gameplay.cpp new file mode 100644 index 0000000..e734728 --- /dev/null +++ b/examples/tutorials/physics/Gameplay.cpp @@ -0,0 +1,43 @@ +#include "Gameplay.hpp" +#include + +namespace faset::gameplay { +void registerGameplay(runtime::Runtime& world) { + runtime::Behavior character; + character.fixedUpdate = [](runtime::Runtime& game, runtime::EntityHandle self, double) { + const auto settings = game.fields(self, "tutorial.character"); + const auto input = game.input(); + auto velocity = game.velocity(self); // Metres per second; preserve the Y component. + velocity[0] = input.horizontal * settings.value("speed", 4.0f); + if (input.jumpPressed && game.grounded(self)) + velocity[1] = settings.value("jump_speed", 5.0f); + // Do not multiply velocity by delta. The physics solver integrates it. + game.setVelocity(self, velocity); + }; + character.onCollision = [](runtime::Runtime&, runtime::EntityHandle, + const runtime::CollisionEvent& event) { + if (event.began) + std::cout << "Character contact began\n"; + }; + world.registerBehavior("tutorial.character", std::move(character)); +} + +nlohmann::json schema() { + return nlohmann::json::array({{{"id", "tutorial.character"}, + {"version", 1}, + {"name", "Physics character"}, + {"fields", + {{"speed", + {{"id", "speed"}, + {"type", "number"}, + {"default", 4.0}, + {"min", 0.0}, + {"units", "m/s"}}}, + {"jump_speed", + {{"id", "jump_speed"}, + {"type", "number"}, + {"default", 5.0}, + {"min", 0.0}, + {"units", "m/s"}}}}}}}); +} +} // namespace faset::gameplay diff --git a/examples/tutorials/physics/Gameplay.hpp b/examples/tutorials/physics/Gameplay.hpp new file mode 100644 index 0000000..d9caafe --- /dev/null +++ b/examples/tutorials/physics/Gameplay.hpp @@ -0,0 +1,7 @@ +#pragma once +#include + +namespace faset::gameplay { +void registerGameplay(runtime::Runtime& world); +nlohmann::json schema(); +} // namespace faset::gameplay diff --git a/examples/tutorials/physics/scene.json b/examples/tutorials/physics/scene.json new file mode 100644 index 0000000..6e58dab --- /dev/null +++ b/examples/tutorials/physics/scene.json @@ -0,0 +1,148 @@ +{ + "format": "faset.scene", + "version": 1, + "id": "tutorial-physics", + "name": "Physics tutorial", + "dimension": 2, + "simulation": { + "fixed_delta": 0.016666666666666666, + "max_catch_up_ticks": 4, + "physics_substeps": 4, + "gravity": [ + 0, + -9.81, + 0 + ] + }, + "entities": [ + { + "id": "floor", + "name": "floor", + "parent": null, + "components": [ + { + "id": "floor-faset.transform", + "type": "faset.transform", + "version": 1, + "fields": { + "position": [ + 0, + -0.5, + 0 + ], + "rotation": [ + 0, + 0, + 0 + ], + "scale": [ + 1, + 1, + 1 + ] + } + }, + { + "id": "floor-faset.sprite", + "type": "faset.sprite", + "version": 1, + "fields": { + "color": [ + 0.4, + 0.5, + 0.6, + 1 + ], + "size": [ + 12, + 1 + ] + } + }, + { + "id": "floor-faset.rigid_body_2d", + "type": "faset.rigid_body_2d", + "version": 1, + "fields": { + "body_type": "static", + "half_extents": [ + 6, + 0.5 + ] + } + } + ] + }, + { + "id": "actor", + "name": "actor", + "parent": null, + "components": [ + { + "id": "actor-faset.transform", + "type": "faset.transform", + "version": 1, + "fields": { + "position": [ + 0, + 0.5, + 0 + ], + "rotation": [ + 0, + 0, + 0 + ], + "scale": [ + 1, + 1, + 1 + ] + } + }, + { + "id": "actor-faset.sprite", + "type": "faset.sprite", + "version": 1, + "fields": { + "color": [ + 0.2, + 0.7, + 0.9, + 1 + ], + "size": [ + 1, + 1 + ] + } + }, + { + "id": "actor-faset.rigid_body_2d", + "type": "faset.rigid_body_2d", + "version": 1, + "fields": { + "body_type": "dynamic", + "half_extents": [ + 0.5, + 0.5 + ], + "density": 1, + "friction": 0.3, + "gravity_scale": 1 + } + }, + { + "id": "actor-tutorial.character", + "type": "tutorial.character", + "version": 1, + "fields": { + "speed": 4, + "jump_speed": 5 + } + } + ] + } + ], + "instances": [] +} diff --git a/examples/tutorials/spawning/Gameplay.cpp b/examples/tutorials/spawning/Gameplay.cpp new file mode 100644 index 0000000..eb70193 --- /dev/null +++ b/examples/tutorials/spawning/Gameplay.cpp @@ -0,0 +1,70 @@ +#include "Gameplay.hpp" +#include +#include + +namespace faset::gameplay { +void registerGameplay(runtime::Runtime& world) { + runtime::Behavior spawner; + spawner.onStart = [](runtime::Runtime& game, runtime::EntityHandle self, double) { + const auto settings = game.fields(self, "tutorial.spawn_once"); + const auto id = settings.at("spawned_id").get(); + // This queues a runtime object; it does not change the saved scene. + game.spawn( + {{"id", id}, + {"name", "Temporary box"}, + {"parent", nullptr}, + {"components", nlohmann::json::array( + {{{"id", id + "/transform"}, + {"type", "faset.transform"}, + {"version", 1}, + {"fields", {{"position", {0, 0, 0}}}}}, + {{"id", id + "/sprite"}, + {"type", "faset.sprite"}, + {"version", 1}, + {"fields", {{"color", {0.9, 0.6, 0.2, 1}}, {"size", {1, 1}}}}}, + {{"id", id + "/lifetime"}, + {"type", "tutorial.timed_despawn"}, + {"version", 1}, + {"fields", {{"seconds", settings.value("lifetime", 1.0)}}}}})}}); + }; + world.registerBehavior("tutorial.spawn_once", std::move(spawner)); + + // Ordinary C++ state belongs to the gameplay module. Every handle part matters. + using Key = std::tuple; + auto ages = std::make_shared>(); + auto key = [](runtime::EntityHandle h) { return Key{h.session, h.slot, h.generation}; }; + runtime::Behavior lifetime; + lifetime.onStart = [ages, key](runtime::Runtime&, runtime::EntityHandle self, double) { + (*ages)[key(self)] = 0.0; + }; + lifetime.fixedUpdate = [ages, key](runtime::Runtime& game, runtime::EntityHandle self, + double delta) { + auto& age = ages->at(key(self)); + age += delta; + if (age >= game.fields(self, "tutorial.timed_despawn").value("seconds", 1.0)) + game.destroy(self); // Still valid until the next fixed-tick barrier. + }; + lifetime.onDestroy = [ages, key](runtime::Runtime&, runtime::EntityHandle self, double) { + ages->erase(key(self)); + }; + world.registerBehavior("tutorial.timed_despawn", std::move(lifetime)); +} + +nlohmann::json schema() { + return nlohmann::json::array( + {{{"id", "tutorial.spawn_once"}, + {"version", 1}, + {"name", "Spawn once"}, + {"fields", + {{"spawned_id", + {{"id", "spawned_id"}, {"type", "string"}, {"default", "temporary-box"}}}, + {"lifetime", + {{"id", "lifetime"}, {"type", "number"}, {"default", 1.0}, {"min", 0.0}}}}}}, + {{"id", "tutorial.timed_despawn"}, + {"version", 1}, + {"name", "Timed despawn"}, + {"fields", + {{"seconds", + {{"id", "seconds"}, {"type", "number"}, {"default", 1.0}, {"min", 0.0}}}}}}}); +} +} // namespace faset::gameplay diff --git a/examples/tutorials/spawning/Gameplay.hpp b/examples/tutorials/spawning/Gameplay.hpp new file mode 100644 index 0000000..d9caafe --- /dev/null +++ b/examples/tutorials/spawning/Gameplay.hpp @@ -0,0 +1,7 @@ +#pragma once +#include + +namespace faset::gameplay { +void registerGameplay(runtime::Runtime& world); +nlohmann::json schema(); +} // namespace faset::gameplay diff --git a/examples/tutorials/spawning/scene.json b/examples/tutorials/spawning/scene.json new file mode 100644 index 0000000..63d76e9 --- /dev/null +++ b/examples/tutorials/spawning/scene.json @@ -0,0 +1,58 @@ +{ + "format": "faset.scene", + "version": 1, + "id": "tutorial-spawning", + "name": "Spawning tutorial", + "dimension": 2, + "simulation": { + "fixed_delta": 0.016666666666666666, + "max_catch_up_ticks": 4, + "physics_substeps": 4, + "gravity": [ + 0, + -9.81, + 0 + ] + }, + "entities": [ + { + "id": "spawner", + "name": "spawner", + "parent": null, + "components": [ + { + "id": "spawner-faset.transform", + "type": "faset.transform", + "version": 1, + "fields": { + "position": [ + 0, + 0, + 0 + ], + "rotation": [ + 0, + 0, + 0 + ], + "scale": [ + 1, + 1, + 1 + ] + } + }, + { + "id": "spawner-tutorial.spawn_once", + "type": "tutorial.spawn_once", + "version": 1, + "fields": { + "spawned_id": "temporary-box", + "lifetime": 1.0 + } + } + ] + } + ], + "instances": [] +} diff --git a/include/faset/assets/asset_data.hpp b/include/faset/assets/asset_data.hpp new file mode 100644 index 0000000..6d10e34 --- /dev/null +++ b/include/faset/assets/asset_data.hpp @@ -0,0 +1,71 @@ +#pragma once +#include +#include +#include +#include +#include +#include +#include + +namespace faset::assets { +using Json = nlohmann::json; +struct Vertex { + std::array position{}; + std::array normal{0, 0, 1}; + std::array uv{}; +}; +struct Primitive { + std::vector vertices; + std::vector indices; + int material = -1; +}; +struct Mesh { + std::string id, name; + std::vector primitives; +}; +struct Node { + std::string id, name, parent_id; + int mesh = -1; + // glTF right-handed, Y-up, metres; column-major matrix. + std::array local_transform{1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1}; + bool stable_source_id = false; +}; +struct Material { + std::string id, name; + std::array base_color{1, 1, 1, 1}; + std::array emissive{}; + float metallic = 1, roughness = 1, alpha_cutoff = 0.5f; + std::string alpha_mode = "OPAQUE"; + bool double_sided = false, unlit = false; + int base_color_texture = -1, metallic_roughness_texture = -1; + int normal_texture = -1, occlusion_texture = -1, emissive_texture = -1; +}; +struct Texture { + std::string id, name, mime_type; + // Encoded image bytes, owned by this value. Renderer selects an image decoder. + std::vector bytes; + int wrap_s = 10497, wrap_t = 10497, min_filter = 0, mag_filter = 0; +}; +struct CookedAsset { + std::string asset_id, generation; + std::vector meshes; + std::vector nodes; + std::vector materials; + std::vector textures; +}; + +// Read-only cooked storage. No source parser, import jobs or publication operations. +class AssetStore { + public: + explicit AssetStore(std::filesystem::path cache_root); + Json current_manifest(const std::string& asset_id) const; + CookedAsset load_asset(const std::string& asset_id) const; + std::filesystem::path generation_directory(const std::string& asset_id) const; + const std::filesystem::path& cache_root() const noexcept { + return cache_root_; + } + + protected: + std::filesystem::path cache_root_; +}; +} // namespace faset::assets diff --git a/include/faset/assets/asset_pipeline.hpp b/include/faset/assets/asset_pipeline.hpp index aa46ad1..e0a5186 100644 --- a/include/faset/assets/asset_pipeline.hpp +++ b/include/faset/assets/asset_pipeline.hpp @@ -1,4 +1,5 @@ #pragma once +#include #include #include @@ -7,69 +8,28 @@ #include #include #include +#include #include #include -#include namespace faset::assets { using Json = nlohmann::json; inline constexpr const char* importer_version = "faset-gltf-1/cgltf-1.15"; -struct Vertex { - std::array position{}; - std::array normal{0, 0, 1}; - std::array uv{}; +struct ImportProgress { + float fraction = 0; + std::string stage; }; -struct Primitive { - std::vector vertices; - std::vector indices; - int material = -1; -}; -struct Mesh { - std::string id, name; - std::vector primitives; -}; -struct Node { - std::string id, name, parent_id; - int mesh = -1; - // glTF right-handed, Y-up, metres; column-major matrix. - std::array local_transform{1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1}; - bool stable_source_id = false; -}; -struct Material { - std::string id, name; - std::array base_color{1,1,1,1}; - std::array emissive{}; - float metallic = 1, roughness = 1, alpha_cutoff = 0.5f; - std::string alpha_mode = "OPAQUE"; - bool double_sided = false, unlit = false; - int base_color_texture = -1, metallic_roughness_texture = -1; - int normal_texture = -1, occlusion_texture = -1, emissive_texture = -1; -}; -struct Texture { - std::string id, name, mime_type; - // Encoded image bytes, owned by this value. Renderer selects an image decoder. - std::vector bytes; - int wrap_s = 10497, wrap_t = 10497, min_filter = 0, mag_filter = 0; -}; -struct CookedAsset { - std::string asset_id, generation; - std::vector meshes; - std::vector nodes; - std::vector materials; - std::vector textures; -}; - -struct ImportProgress { float fraction = 0; std::string stage; }; class ImportJob { -public: + public: using Observer = std::function; explicit ImportJob(Observer observer = {}); void cancel() noexcept; bool cancelled() const noexcept; ImportProgress progress() const; void report(float fraction, std::string stage); -private: + + private: std::atomic cancelled_{false}; mutable std::mutex mutex_; ImportProgress progress_; @@ -79,7 +39,7 @@ private: enum class ImportStatus { succeeded, failed, cancelled, conflict }; struct ImportRequest { std::filesystem::path source; - std::string asset_id{}; // Empty: restore/create source.faset-import.json identity. + std::string asset_id{}; // Empty: restore/create source.faset-import.json identity. Json settings = nullptr; // Null restores the sidecar recipe; an object replaces it. // Explicit conflict resolution; false keeps the previous generation active. bool allow_removed_outputs = false; @@ -91,24 +51,20 @@ struct ImportResult { std::vector removed_output_ids; Json manifest; bool cache_hit = false; - bool ok() const noexcept { return status == ImportStatus::succeeded; } + bool ok() const noexcept { + return status == ImportStatus::succeeded; + } }; // A pipeline is an authoring service. Player only needs read-only cooked data. // Writers in one process serialize publication; a cache root has one service owner. -class AssetPipeline { -public: +class AssetPipeline : public AssetStore { + public: explicit AssetPipeline(std::filesystem::path cache_root); ImportResult import_asset(const ImportRequest& request, ImportJob& job); ImportResult import_asset(const ImportRequest& request); - Json current_manifest(const std::string& asset_id) const; - CookedAsset load_asset(const std::string& asset_id) const; // Overrides are authoring data beside the source, never generated cache contents. Json overrides(const std::string& asset_id) const; void set_overrides(const std::string& asset_id, const Json& overrides); - std::filesystem::path generation_directory(const std::string& asset_id) const; - const std::filesystem::path& cache_root() const noexcept { return cache_root_; } -private: - std::filesystem::path cache_root_; }; } // namespace faset::assets diff --git a/include/faset/authoring/schema.hpp b/include/faset/authoring/schema.hpp index 594012e..c2287bd 100644 --- a/include/faset/authoring/schema.hpp +++ b/include/faset/authoring/schema.hpp @@ -1,13 +1,13 @@ #pragma once -#include #include +#include #include #include #include namespace faset::authoring { class SchemaRegistry { -public: + public: void register_schema(const Json& schema); void register_schemas(const Json& schemas); bool contains(const std::string& type) const; @@ -18,29 +18,43 @@ public: void validate_component(const Json& component) const; Json migrate_component(const Json& component) const; void add_migration(const std::string& type, int from_version, Json field_rules); -private: - std::map schemas_; - std::map,Json> migrations_; + + private: + std::map schemas_; + std::map, Json> migrations_; }; -template class TypeRegistration { -public: - TypeRegistration(SchemaRegistry& registry, std::string id, std::string name, int version=1) - : registry_(registry),schema_{{"id",std::move(id)},{"name",std::move(name)},{"version",version},{"fields",Json::object()}} {} - template - TypeRegistration& field(std::string id, std::string name, Value T::*member, Value default_value, - std::string kind, Json constraints=Json::object()) { +template class TypeRegistration { + public: + TypeRegistration(SchemaRegistry& registry, std::string id, std::string name, int version = 1) + : registry_(registry), schema_{{"id", std::move(id)}, + {"name", std::move(name)}, + {"version", version}, + {"fields", Json::object()}} {} + template + TypeRegistration& field(std::string id, std::string name, Value T::* member, + Value default_value, std::string kind, + Json constraints = Json::object()) { static_assert(std::is_member_object_pointer_v); - require(!schema_["fields"].contains(id),"schema.duplicate_field","Duplicate stable FieldId"); + require(!schema_["fields"].contains(id), "schema.duplicate_field", + "Duplicate stable FieldId"); // Converting the typed default checks supported JSON serialization at compile time. - Json descriptor={{"id",id},{"name",std::move(name)},{"type",std::move(kind)},{"default",Json(default_value)}}; - descriptor.update(constraints); schema_["fields"][id]=std::move(descriptor); return *this; + Json descriptor = {{"id", id}, + {"name", std::move(name)}, + {"type", std::move(kind)}, + {"default", Json(default_value)}}; + descriptor.update(constraints); + schema_["fields"][id] = std::move(descriptor); + return *this; } - void commit() { registry_.register_schema(schema_); } -private: + void commit() { + registry_.register_schema(schema_); + } + + private: SchemaRegistry& registry_; Json schema_; }; SchemaRegistry builtin_schemas(); -void validate_field(const Json& value,const Json& descriptor); -} +void validate_field(const Json& value, const Json& descriptor); +} // namespace faset::authoring diff --git a/include/faset/authoring/service.hpp b/include/faset/authoring/service.hpp index c6569df..461414f 100644 --- a/include/faset/authoring/service.hpp +++ b/include/faset/authoring/service.hpp @@ -3,47 +3,58 @@ #include #include #include +#include #include #include namespace faset::authoring { -Json make_scene(std::string name,int dimension=3); -Json make_entity(const SchemaRegistry& schemas,std::string name,const std::string& parent=""); -void validate_scene(const Json& scene,const SchemaRegistry& schemas); +Json make_scene(std::string name, int dimension = 3); +Json make_entity(const SchemaRegistry& schemas, std::string name, const std::string& parent = ""); +void validate_scene(const Json& scene, const SchemaRegistry& schemas); class AuthoringService { -public: - explicit AuthoringService(std::filesystem::path project_root,SchemaRegistry schemas=builtin_schemas()); - Json create(std::string name,int dimension=3); - Json open(const std::filesystem::path& relative,bool recover=false); + public: + explicit AuthoringService(std::filesystem::path project_root, + SchemaRegistry schemas = builtin_schemas()); + Json create(std::string name, int dimension = 3); + Json open(const std::filesystem::path& relative, bool recover = false); Json query(const std::string& document) const; Json documents() const; - Json transact(const std::string& document,std::uint64_t expected_revision,const Json& operations,const std::string& idempotency_key=""); - Json undo(const std::string& document,std::uint64_t expected_revision); - Json redo(const std::string& document,std::uint64_t expected_revision); - Json save(const std::string& document,const std::filesystem::path& relative={}); + Json transact(const std::string& document, std::uint64_t expected_revision, + const Json& operations, const std::string& idempotency_key = ""); + Json undo(const std::string& document, std::uint64_t expected_revision); + Json redo(const std::string& document, std::uint64_t expected_revision); + Json save(const std::string& document, const std::filesystem::path& relative = {}); Json recovery_documents() const; - const SchemaRegistry& schemas() const {return schemas_;} + Json recover(const std::string& document, + std::optional expected_revision = std::nullopt); + const SchemaRegistry& schemas() const { + return schemas_; + } void register_schemas(const Json& manifest); - const std::filesystem::path& root() const {return root_;} -private: + void replace_external_schemas(const Json& manifest); + const std::filesystem::path& root() const { + return root_; + } + + private: struct State { Json data; - std::uint64_t revision=0; + std::uint64_t revision = 0; std::filesystem::path path; - std::string saved_hash,disk_hash; - std::vector undo,redo; - std::map> requests; + std::string saved_hash, disk_hash; + std::vector undo, redo; + std::map> requests; }; - Json summary(const State& state,bool include_data=true) const; + Json summary(const State& state, bool include_data = true) const; State& state(const std::string& document); const State& state(const std::string& document) const; void journal(const State& state) const; - void apply(Json& scene,const Json& operation); - Json history(const std::string& document,std::uint64_t revision,bool redo); + void apply(Json& scene, const Json& operation); + Json history(const std::string& document, std::uint64_t revision, bool redo); std::filesystem::path root_; SchemaRegistry schemas_; - std::map documents_; + std::map documents_; mutable std::recursive_mutex mutex_; }; -} +} // namespace faset::authoring diff --git a/include/faset/authoring/templates.hpp b/include/faset/authoring/templates.hpp index 04c129b..2bf3b55 100644 --- a/include/faset/authoring/templates.hpp +++ b/include/faset/authoring/templates.hpp @@ -4,8 +4,12 @@ #include namespace faset::authoring { -struct ResolvedScene {Json scene;Json conflicts=Json::array();}; -using SceneLoader=std::function; +struct ResolvedScene { + Json scene; + Json conflicts = Json::array(); +}; +using SceneLoader = std::function; // Source documents are immutable inputs. Conflicting records stay in the authoring file. -ResolvedScene resolve_templates(const Json& scene,const SchemaRegistry& schemas,const SceneLoader& loader); -} +ResolvedScene resolve_templates(const Json& scene, const SchemaRegistry& schemas, + const SceneLoader& loader); +} // namespace faset::authoring diff --git a/include/faset/authoring/transforms.hpp b/include/faset/authoring/transforms.hpp new file mode 100644 index 0000000..41d8f2d --- /dev/null +++ b/include/faset/authoring/transforms.hpp @@ -0,0 +1,8 @@ +#pragma once +#include +#include +namespace faset::authoring { +// Reparents authored TRS while optionally preserving the complete world transform. +// Non-invertible parents and transforms requiring shear are rejected atomically. +void reparent_entity(Json& scene, const std::string& entity, const Json& parent, bool keep_world); +} // namespace faset::authoring diff --git a/include/faset/core/error.hpp b/include/faset/core/error.hpp index 98f5c2a..cee331b 100644 --- a/include/faset/core/error.hpp +++ b/include/faset/core/error.hpp @@ -5,16 +5,23 @@ namespace faset { class Error : public std::runtime_error { -public: + public: Error(std::string code, std::string message, Json details = Json::object()) - : std::runtime_error(std::move(message)), code_(std::move(code)), details_(std::move(details)) {} - const std::string& code() const noexcept { return code_; } - Json json() const { return {{"code", code_}, {"message", what()}, {"details", details_}}; } -private: + : std::runtime_error(std::move(message)), code_(std::move(code)), + details_(std::move(details)) {} + const std::string& code() const noexcept { + return code_; + } + Json json() const { + return {{"code", code_}, {"message", what()}, {"details", details_}}; + } + + private: std::string code_; Json details_; }; inline void require(bool condition, const std::string& code, const std::string& message) { - if (!condition) throw Error(code, message); -} + if (!condition) + throw Error(code, message); } +} // namespace faset diff --git a/include/faset/core/hash.hpp b/include/faset/core/hash.hpp index d7a1307..b9f24fa 100644 --- a/include/faset/core/hash.hpp +++ b/include/faset/core/hash.hpp @@ -11,4 +11,4 @@ inline std::string sha256(std::string_view text) { return sha256(std::as_bytes(std::span(text.data(), text.size()))); } std::string sha256_file(const std::filesystem::path& path); -} +} // namespace faset diff --git a/include/faset/core/io.hpp b/include/faset/core/io.hpp index e99f75c..af17402 100644 --- a/include/faset/core/io.hpp +++ b/include/faset/core/io.hpp @@ -11,5 +11,6 @@ Json read_json(const std::filesystem::path& path); void atomic_write(const std::filesystem::path& path, std::string_view bytes); void atomic_write_json(const std::filesystem::path& path, const Json& value); // Rejects traversal and symlink escapes before project-scoped file operations. -std::filesystem::path project_path(const std::filesystem::path& root, const std::filesystem::path& relative); -} +std::filesystem::path project_path(const std::filesystem::path& root, + const std::filesystem::path& relative); +} // namespace faset diff --git a/include/faset/core/json.hpp b/include/faset/core/json.hpp index a0c2df2..b6287b3 100644 --- a/include/faset/core/json.hpp +++ b/include/faset/core/json.hpp @@ -1,3 +1,5 @@ #pragma once #include -namespace faset { using Json = nlohmann::json; } +namespace faset { +using Json = nlohmann::json; +} diff --git a/include/faset/core/process.hpp b/include/faset/core/process.hpp new file mode 100644 index 0000000..8f8fb89 --- /dev/null +++ b/include/faset/core/process.hpp @@ -0,0 +1,38 @@ +#pragma once +#include +#include +#include +#include +#include +#include + +namespace faset { +struct ProcessOptions { + // First element is the executable. Arguments are passed directly, never through a shell. + std::vector arguments; + std::filesystem::path working_directory; + std::map environment; +}; +struct ProcessPoll { + bool running{}; + std::optional exit_code; + std::string output; // Newly available stdout and stderr, combined. +}; +class Process { + public: + explicit Process(const ProcessOptions&); + ~Process(); + Process(Process&&) noexcept; + Process& operator=(Process&&) noexcept; + Process(const Process&) = delete; + Process& operator=(const Process&) = delete; + ProcessPoll poll(); + // Terminates the process group/job, including its compiler children. + void cancel(); + + private: + struct Impl; + std::unique_ptr impl_; +}; +std::filesystem::path find_executable(const std::string& name); +} // namespace faset diff --git a/include/faset/editor/build_service.hpp b/include/faset/editor/build_service.hpp new file mode 100644 index 0000000..0a12cc3 --- /dev/null +++ b/include/faset/editor/build_service.hpp @@ -0,0 +1,55 @@ +#pragma once +#include +#include +#include +#include +#include + +namespace faset::editor { +struct BuildConfig { + std::filesystem::path project_root; + std::filesystem::path engine_root; + std::filesystem::path build_directory; + std::filesystem::path cache_root; + // Separate CMake caches prevent an export from changing the active development build. + std::string configuration{"Debug"}; + std::string export_configuration{"Release"}; + std::string cmake{"cmake"}; + std::string generator{"Ninja"}; + std::vector configure_arguments; +}; +struct JobStatus { + std::string id, kind, state{"queued"}, stage{"queued"}; + double progress{}; + std::string log, error; + Json result = Json::object(); + bool finished() const { + return state == "succeeded" || state == "failed" || state == "cancelled"; + } + Json json() const; +}; +// One serialized build/cook worker per project. GUI and MCP use the same service. +// Input scenes must be resolved authoring snapshots, independent of live runtime state. +class BuildService { + public: + explicit BuildService(BuildConfig); + ~BuildService(); + BuildService(const BuildService&) = delete; + BuildService& operator=(const BuildService&) = delete; + void scaffold(const std::string& name, int dimension); + std::string start_build(); + std::string start_cook(Json resolved_scene); + // Publishes output/generations/; current.json changes only after all validation succeeds. + std::string start_export(Json resolved_scene, const std::filesystem::path& output_directory); + JobStatus job(const std::string& id) const; + std::vector jobs() const; + void cancel(const std::string& id); + JobStatus wait(const std::string& id); + const BuildConfig& config() const; + + private: + struct Impl; + std::unique_ptr impl_; +}; +void write_cooked_scene(const std::filesystem::path& path, const Json& resolved_scene); +} // namespace faset::editor diff --git a/include/faset/editor/commands.hpp b/include/faset/editor/commands.hpp new file mode 100644 index 0000000..5befd5a --- /dev/null +++ b/include/faset/editor/commands.hpp @@ -0,0 +1,31 @@ +#pragma once +#include +#include +#include +#include + +namespace faset::editor { +class Commands { + public: + using Handler = std::function; + explicit Commands(authoring::AuthoringService& authoring); + void add(std::string name, std::string description, Json input_schema, Handler handler, + bool read_only = false); + Json list() const; + void remove(const std::string& name); + Json call(const std::string& name, const Json& arguments); + Json resolved_scene(const std::string& document) const; + authoring::AuthoringService& authoring() { + return authoring_; + } + static Json object_schema(Json properties, Json required = Json::array()); + + private: + struct Command { + Json descriptor; + Handler handler; + }; + authoring::AuthoringService& authoring_; + std::map commands_; +}; +} // namespace faset::editor diff --git a/include/faset/editor/editor_ui.hpp b/include/faset/editor/editor_ui.hpp new file mode 100644 index 0000000..e0e984e --- /dev/null +++ b/include/faset/editor/editor_ui.hpp @@ -0,0 +1,28 @@ +#pragma once +#include +#include +#include + +namespace faset::editor { +// Owns authoring presentation only. Player execution and MCP transport stay in +// the application. +class EditorUI { + public: + EditorUI(Session&, render::Renderer&, const std::filesystem::path& font, + const std::filesystem::path& styles); + ~EditorUI(); + EditorUI(const EditorUI&) = delete; + EditorUI& operator=(const EditorUI&) = delete; + void frame(const std::vector&); + const render::Snapshot& snapshot() const; + ui::Context& widgets(); + const std::string& current_document() const; + void select_document(const std::string& document); + const std::string& selected_entity() const; + void select_entity(const std::string& entity); + + private: + struct Impl; + std::unique_ptr impl_; +}; +} // namespace faset::editor diff --git a/include/faset/editor/mcp.hpp b/include/faset/editor/mcp.hpp new file mode 100644 index 0000000..931e834 --- /dev/null +++ b/include/faset/editor/mcp.hpp @@ -0,0 +1,32 @@ +#pragma once +#include +#include +#include +#include + +namespace faset::editor { +// MCP is compiled exclusively into the Editor / headless authoring executable. +class McpServer { + public: + explicit McpServer(Commands& commands) : commands_(commands) {} + std::optional handle(const Json& message); + Json parse_error() const; + + private: + Commands& commands_; + bool initialized_ = false, ready_ = false; +}; +class StdioTransport { + public: + // Nonblocking: GUI and MCP can share the same authoring session and event loop. + std::vector poll(); + bool closed() const noexcept { + return closed_; + } + void send(const Json& message); + + private: + std::string buffer_; + bool closed_ = false; +}; +} // namespace faset::editor diff --git a/include/faset/editor/plugin_api.h b/include/faset/editor/plugin_api.h new file mode 100644 index 0000000..a1b49d8 --- /dev/null +++ b/include/faset/editor/plugin_api.h @@ -0,0 +1,42 @@ +#pragma once +/* Exact-build native Editor SDK. No STL types or ownership cross this ABI. */ +#include +#include +#ifdef __cplusplus +extern "C" { +#endif +#define FASET_EDITOR_API_VERSION 1u +#if defined(_WIN32) +#define FASET_PLUGIN_EXPORT __declspec(dllexport) +#else +#define FASET_PLUGIN_EXPORT __attribute__((visibility("default"))) +#endif +/* UTF-8 JSON is borrowed for the duration of a call. write() copies output in + the receiving module. Return zero on success; errors use {code,message}. */ +typedef void (*FasetWrite)(void* receiver, const char* utf8, uint64_t length); +typedef int (*FasetCommand)(void* user, const char* arguments_json, FasetWrite write, + void* receiver); +typedef struct FasetEditorHost { + uint32_t api_version; + uint32_t struct_size; + const char* build_fingerprint; + void* context; + int (*register_command)(void* context, const char* descriptor_json, FasetCommand callback, + void* user); + int (*register_panel)(void* context, const char* panel_json); + int (*invoke_command)(void* context, const char* name, const char* arguments_json, + FasetWrite write, void* receiver); + void (*log)(void* context, const char* utf8); +} FasetEditorHost; +typedef struct FasetEditorPlugin { + uint32_t api_version; + uint32_t struct_size; + const char* build_fingerprint; + void* user; + void (*shutdown)(void* user); +} FasetEditorPlugin; +/* Required exported symbol. Called once at startup, after dependencies load. */ +typedef int (*FasetPluginEntry)(const FasetEditorHost* host, FasetEditorPlugin* plugin); +#ifdef __cplusplus +} +#endif diff --git a/include/faset/editor/plugins.hpp b/include/faset/editor/plugins.hpp new file mode 100644 index 0000000..87c695c --- /dev/null +++ b/include/faset/editor/plugins.hpp @@ -0,0 +1,24 @@ +#pragma once +#include +#include +#include +namespace faset::editor { +class PluginManager { + public: + using Logger = std::function; + explicit PluginManager(Commands&, Logger); + ~PluginManager(); + PluginManager(const PluginManager&) = delete; + PluginManager& operator=(const PluginManager&) = delete; + // Discover and validate the complete dependency graph before loading code. + // Individual failures are reported; dependents are never loaded after one. + void load(const std::filesystem::path& directory); + Json status() const; + Json panels() const; + static std::string fingerprint(); + + private: + struct Impl; + std::unique_ptr impl_; +}; +} // namespace faset::editor diff --git a/include/faset/editor/session.hpp b/include/faset/editor/session.hpp new file mode 100644 index 0000000..93dc2ad --- /dev/null +++ b/include/faset/editor/session.hpp @@ -0,0 +1,69 @@ +#pragma once +#include +#include +#include +#include +#include +#include +#include +#include + +namespace faset::editor { +struct SessionConfig { + std::filesystem::path project_root, engine_root, binary_directory; +}; +class Session { + public: + explicit Session(SessionConfig); + ~Session(); + Session(const Session&) = delete; + Session& operator=(const Session&) = delete; + authoring::AuthoringService& authoring() { + return authoring_; + } + Commands& commands() { + return commands_; + } + void poll(); + const std::vector& logs() const { + return logs_; + } + Json project() const; + Json plugin_panels() const { + return plugins_ ? plugins_->panels() : Json::array(); + } + void scaffold(const std::string& name, int dimension); + const SessionConfig& config() const { + return config_; + } + bool playing() const { + return bool(player_); + } + void log(std::string message); + + private: + struct ImportTask; + void register_commands(); + Json assets_list() const; + Json jobs() const; + Json job(const std::string& id) const; + void load_schema(const std::filesystem::path& path); + void launch_player(Json scene, const std::filesystem::path& executable); + void stop_player(); + SessionConfig config_; + authoring::AuthoringService authoring_; + Commands commands_; + assets::AssetPipeline assets_; + BuildService builds_; + std::map> imports_; + std::vector workers_; + std::vector logs_; + std::map observed_jobs_; + std::unique_ptr player_; + std::filesystem::path control_path_; + std::uint64_t control_sequence_ = 0; + std::string pending_play_job_; + Json pending_play_scene_; + std::unique_ptr plugins_; +}; +} // namespace faset::editor diff --git a/include/faset/player/SceneView.hpp b/include/faset/player/SceneView.hpp new file mode 100644 index 0000000..6fac052 --- /dev/null +++ b/include/faset/player/SceneView.hpp @@ -0,0 +1,37 @@ +#pragma once +#include +#include +#include +#include + +namespace faset::player { +struct CameraSettings { + // Defaults frame the small demo scenes. An explicit editor camera overrides + // scene camera components without changing the authoring document. + bool overrideSceneCamera{false}; + render::Vec3 eye{8, 6, 10}; + render::Vec3 target{0, 0, 0}; + float verticalFovDegrees{60}; + float orthographicHeight{12}; + float nearPlane{0.1f}, farPlane{1000}; +}; +class SceneView { + public: + // cacheRoot contains assets//current.json and generation folders. + explicit SceneView(std::filesystem::path cacheRoot); + ~SceneView(); + SceneView(const SceneView&) = delete; + SceneView& operator=(const SceneView&) = delete; + render::Snapshot build(const nlohmann::json& flatSceneOrRuntimeSnapshot, float aspect, + CameraSettings camera = {}); + void clearCache(); + const std::vector& diagnostics() const; + + private: + struct Impl; + std::unique_ptr impl_; +}; + +// Reads JSON development scenes or a strict FASETSCN v1 CBOR envelope. +nlohmann::json readScene(const std::filesystem::path& path); +} // namespace faset::player diff --git a/include/faset/render/render_graph.hpp b/include/faset/render/render_graph.hpp index 9a21d55..2ac92d5 100644 --- a/include/faset/render/render_graph.hpp +++ b/include/faset/render/render_graph.hpp @@ -6,15 +6,21 @@ namespace faset::render { // Ordered single-queue graph. Reads must be imported or produced by an earlier pass. // The Vulkan executor performs barriers at each resource state transition. class RenderGraph { -public: + public: using Callback = std::function; void import(std::string resource); - void add(std::string name, std::vector reads, std::vector writes, Callback execute); + void add(std::string name, std::vector reads, std::vector writes, + Callback execute); void execute() const; std::vector pass_names() const; -private: - struct Pass {std::string name; std::vector reads, writes; Callback callback;}; + + private: + struct Pass { + std::string name; + std::vector reads, writes; + Callback callback; + }; std::vector imports_; std::vector passes_; }; -} +} // namespace faset::render diff --git a/include/faset/render/renderer.hpp b/include/faset/render/renderer.hpp index 1b06b6e..d3dec8b 100644 --- a/include/faset/render/renderer.hpp +++ b/include/faset/render/renderer.hpp @@ -11,37 +11,68 @@ using Vec2 = std::array; using Vec3 = std::array; using Color = std::array; using Mat4 = std::array; -inline constexpr Mat4 identity{1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1}; +inline constexpr Mat4 identity{1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1}; // Matrices are column-major, vectors are columns; clip depth is Vulkan's [0,1]. Mat4 multiply(const Mat4&, const Mat4&); -Mat4 transform(Vec3 position, Vec3 rotation = {}, Vec3 scale = {1,1,1}); +Mat4 transform(Vec3 position, Vec3 rotation = {}, Vec3 scale = {1, 1, 1}); Mat4 perspective(float vertical_fov_radians, float aspect, float near_plane, float far_plane); -Mat4 orthographic(float left, float right, float bottom, float top, float near_plane, float far_plane); -Mat4 look_at(Vec3 eye, Vec3 target, Vec3 up = {0,1,0}); -struct Vertex { Vec3 position{}; Vec3 normal{0,0,1}; Color color{1,1,1,1}; Vec2 uv{}; }; -struct Mesh { std::vector vertices; std::vector indices; }; +Mat4 orthographic(float left, float right, float bottom, float top, float near_plane, + float far_plane); +Mat4 look_at(Vec3 eye, Vec3 target, Vec3 up = {0, 1, 0}); +struct Vertex { + Vec3 position{}; + Vec3 normal{0, 0, 1}; + Color color{1, 1, 1, 1}; + Vec2 uv{}; +}; +struct Mesh { + std::vector vertices; + std::vector indices; +}; std::shared_ptr cube_mesh(); struct Texture; struct DrawItem { std::shared_ptr mesh; Mat4 model{identity}; - Color color{1,1,1,1}; + Color color{1, 1, 1, 1}; float roughness{0.65f}; float metallic{0.0f}; bool cast_shadow{true}; std::shared_ptr texture; }; -struct Sprite { Vec3 position{}; Vec2 size{1,1}; Color color{1,1,1,1}; float rotation{}; std::shared_ptr texture; }; -struct Texture { std::uint32_t width{}, height{}; std::vector rgba; std::uint64_t revision{}; bool srgb{false}; }; -struct Quad { float x{}, y{}, width{}, height{}; Color color{1,1,1,1}; std::shared_ptr texture; std::array uv_rect{0,0,1,1}; }; -struct Text { float x{}, y{}; std::string value; Color color{0.85f,0.87f,0.90f,1}; float size{14}; }; +struct Sprite { + Vec3 position{}; + Vec2 size{1, 1}; + Color color{1, 1, 1, 1}; + float rotation{}; + std::shared_ptr texture; +}; +struct Texture { + std::uint32_t width{}, height{}; + std::vector rgba; + std::uint64_t revision{}; + bool srgb{false}; +}; +struct Quad { + float x{}, y{}, width{}, height{}; + Color color{1, 1, 1, 1}; + std::shared_ptr texture; + std::array uv_rect{0, 0, 1, 1}; +}; +struct Text { + float x{}, y{}; + std::string value; + Color color{0.85f, 0.87f, 0.90f, 1}; + float size{14}; +}; struct Snapshot { - // Optional scene viewport in drawable pixels (x, y, width, height); zero size uses the full target. - std::array scene_rect{}; + // Optional scene viewport in drawable pixels (x, y, width, height); zero size uses the full + // target. + std::array scene_rect{}; Mat4 view_projection{identity}; - Vec3 eye{4,3,5}; - Vec3 light_direction{-0.5f,-1,-0.3f}; - Color clear_color{0.055f,0.065f,0.085f,1}; + Vec3 eye{4, 3, 5}; + Vec3 light_direction{-0.5f, -1, -0.3f}; + Color clear_color{0.055f, 0.065f, 0.085f, 1}; std::vector draws; std::vector sprites; // UI coordinates are drawable pixels, top-left origin. Order is preserved per list. @@ -55,7 +86,20 @@ struct RendererConfig { bool validation{true}; }; struct Event { - enum class Type { Quit, Resize, FocusGained, FocusLost, MouseMove, MouseDown, MouseUp, Wheel, KeyDown, KeyUp, TextInput, TextEditing }; + enum class Type { + Quit, + Resize, + FocusGained, + FocusLost, + MouseMove, + MouseDown, + MouseUp, + Wheel, + KeyDown, + KeyUp, + TextInput, + TextEditing + }; Type type{}; float x{}, y{}; int button{}; @@ -71,7 +115,7 @@ struct FrameStats { std::string device; }; class Renderer { -public: + public: explicit Renderer(const RendererConfig& = {}); ~Renderer(); Renderer(Renderer&&) noexcept; @@ -95,8 +139,9 @@ public: void set_text_input_area(float x, float y, float width, float height); void set_clipboard(const std::string&); std::string clipboard() const; -private: + + private: struct Impl; std::unique_ptr impl_; }; -} +} // namespace faset::render diff --git a/include/faset/runtime/Runtime.hpp b/include/faset/runtime/Runtime.hpp index 0a2da7c..cc39562 100644 --- a/include/faset/runtime/Runtime.hpp +++ b/include/faset/runtime/Runtime.hpp @@ -4,10 +4,10 @@ #include #include #include +#include #include #include #include -#include namespace faset::runtime { @@ -26,7 +26,9 @@ struct EntityHandle { std::uint64_t session{}; std::uint32_t slot{}; std::uint64_t generation{}; - explicit operator bool() const noexcept { return session != 0; } + explicit operator bool() const noexcept { + return session != 0; + } bool operator==(const EntityHandle&) const = default; }; @@ -37,8 +39,17 @@ struct InputState { bool interactPressed{}; }; -struct Sprite { Vec4 color{1, 1, 1, 1}; Vec2 size{1, 1}; std::string texture; int layer{}; }; -struct Mesh { std::string asset; Vec4 color{1, 1, 1, 1}; std::string primitive{"cube"}; }; +struct Sprite { + Vec4 color{1, 1, 1, 1}; + Vec2 size{1, 1}; + std::string texture; + int layer{}; +}; +struct Mesh { + std::string asset; + Vec4 color{1, 1, 1, 1}; + std::string primitive{"cube"}; +}; struct RenderEntity { std::string id; std::string name; @@ -86,7 +97,7 @@ struct CollisionEvent { // Single-owner sequential runtime. Gameplay callbacks run on the caller's thread. // No Editor, MCP, renderer or platform service is linked by this API. class Runtime { -public: + public: explicit Runtime(RuntimeConfig config = {}); ~Runtime(); Runtime(const Runtime&) = delete; @@ -111,6 +122,9 @@ public: // Configuration copy. Live poses and velocities have their own typed accessors. nlohmann::json fields(EntityHandle handle, const std::string& componentType) const; Vec3 velocity(EntityHandle handle) const; + // Support from the last completed physics step. Checks actual contact normals + // against opposite gravity (Y-up if gravity is zero), not vertical speed. + bool grounded(EntityHandle handle) const; InputState input() const noexcept; // Valid until the next fixed tick or scene replacement. No native solver pointers. const std::vector& collisions() const noexcept; @@ -135,7 +149,7 @@ public: std::uint64_t session() const noexcept; const std::vector& diagnostics() const noexcept; -private: + private: struct Impl; std::unique_ptr impl_; }; diff --git a/include/faset/ui/ui.hpp b/include/faset/ui/ui.hpp new file mode 100644 index 0000000..4768f88 --- /dev/null +++ b/include/faset/ui/ui.hpp @@ -0,0 +1,183 @@ +#pragma once +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace faset::ui { +using Json = nlohmann::json; +using Color = render::Color; +struct Rect { + float x{}, y{}, width{}, height{}; + bool contains(float px, float py) const noexcept; + Rect intersection(const Rect&) const noexcept; +}; +struct Theme { + Color background{.075f, .078f, .086f, 1}, surface{.10f, .105f, .115f, 1}; + Color raised{.135f, .14f, .15f, 1}, hover{.175f, .18f, .20f, 1}, border{.23f, .235f, .255f, 1}; + Color text{.86f, .875f, .90f, 1}, muted{.55f, .575f, .62f, 1}, accent{.65f, .60f, .88f, 1}; + Color selection{.26f, .245f, .35f, 1}, danger{.92f, .39f, .38f, 1}; + float font_size = 14, row_height = 28, padding = 8, gap = 4; + static Theme from_json(const Json&); + static Theme load(const std::filesystem::path&); + Json to_json() const; +}; + +// Byte offsets always remain valid UTF-8 boundaries. Undo is local to an +// unfinished edit. +class TextBuffer { + public: + explicit TextBuffer(std::string text = {}); + const std::string& text() const noexcept { + return text_; + } + std::size_t cursor() const noexcept { + return cursor_; + } + std::size_t anchor() const noexcept { + return anchor_; + } + bool has_selection() const noexcept { + return cursor_ != anchor_; + } + std::string selected_text() const; + void reset(std::string text); + void set_cursor(std::size_t byte_offset, bool select = false); + void select_all(); + void left(bool select = false, bool by_word = false); + void right(bool select = false, bool by_word = false); + void home(bool select = false); + void end(bool select = false); + bool insert(std::string_view utf8); + bool backspace(); + bool delete_forward(); + bool undo(); + bool redo(); + static bool valid_utf8(std::string_view); + + private: + struct State { + std::string text; + std::size_t cursor, anchor; + }; + std::string text_; + std::size_t cursor_{}, anchor_{}; + std::vector undo_, redo_; + void remember(); + void erase_selection(); +}; +class FontAtlas { + public: + explicit FontAtlas(const std::filesystem::path& font); + ~FontAtlas(); + FontAtlas(const FontAtlas&) = delete; + FontAtlas& operator=(const FontAtlas&) = delete; + float measure(std::string_view utf8, float pixels); + // y is the top of the line, not the baseline; clipping also adjusts glyph + // UVs. + void draw(render::Snapshot&, std::string_view utf8, float x, float y, float pixels, Color, + const Rect& clip); + std::shared_ptr texture() const; + + private: + struct Impl; + std::unique_ptr impl_; +}; + +enum class Kind { + Panel, + Row, + Column, + Label, + Button, + Tab, + TreeRow, + TextField, + NumberField, + Checkbox, + Divider, + Viewport +}; +struct Layout { + float width = -1, height = -1, flex = 0; + float min_width = 0, min_height = 0, max_width = 100000, max_height = 100000; + float padding = 0, gap = 4; + bool absolute = false, scroll = false, clip = true; + float x = 0, y = 0; +}; +struct Widget { + Kind kind = Kind::Panel; + std::string id, text; + Layout layout; + Rect rect, clip; + bool visible = true, enabled = true, selected = false, checked = false; + double value = 0, step = .01; + int precision = 3, indent = 0; + float scroll_y = 0, content_height = 0; + std::string error, tooltip; + Json drag_payload; + std::string dock_area, dock_panel; + std::function on_click, on_preview, on_commit, on_cancel; + std::function on_drop; + std::vector> children; + Widget* parent = nullptr; + Widget& add(Kind, const std::string& stable_id, const std::string& text = {}); + Widget* find(std::string_view stable_id); + const Widget* find(std::string_view stable_id) const; + void remove(std::string_view stable_id); +}; +// Small persistent docking model: named areas, ordered tabs/panels and explicit +// sizes. +class DockLayout { + public: + void move(const std::string& panel, const std::string& area, std::size_t index); + std::vector panels(const std::string& area) const; + void set_size(const std::string& panel, float size); + float size(const std::string& panel, float fallback) const; + Json to_json() const; + void from_json(const Json&); + void save(const std::filesystem::path&) const; + void load(const std::filesystem::path&); + + private: + std::unordered_map> areas_; + std::unordered_map sizes_; +}; + +class Context { + public: + explicit Context(const std::filesystem::path& font); + ~Context(); + Widget& root(); + Widget* find(std::string_view id); + void set_theme(Theme); + const Theme& theme() const; + // Reloads declarative widget properties; matching IDs retain callbacks and + // edit state. + void apply_layout(const Json&); + void layout(float drawable_width, float drawable_height, float dpi_scale = 1); + bool handle(const render::Event&); + void draw(render::Snapshot&); + bool update_text(const std::string& id, const std::string& value, bool force = false); + bool update_number(const std::string& id, double value, bool force = false); + bool focus(const std::string& id); + const std::string& focused_id() const; + void clear_focus(bool commit = true); + bool editing() const; + FontAtlas& font(); + void set_clipboard(std::function read, + std::function write); + // Hook to Renderer::set_text_input and set_text_input_area. + void set_ime(std::function enabled, std::function rectangle); + void set_docking(DockLayout*, std::function changed = {}); + + private: + struct Impl; + std::unique_ptr impl_; +}; +} // namespace faset::ui diff --git a/licenses/README.md b/licenses/README.md index 26e3e25..e4f7f36 100644 --- a/licenses/README.md +++ b/licenses/README.md @@ -10,3 +10,12 @@ Faset source dependencies are pinned in `dependencies.lock.json`. These notices - **cgltf** (MIT): [360db1a95480](https://github.com/jkuhlmann/cgltf/tree/360db1a95480fe102ae9c69b27c5d101167ff5ba), notice in `cgltf.txt`. - **stb** (MIT OR Unlicense): [2c980bb59875](https://github.com/nothings/stb/tree/2c980bb59875b0d32144a71867fbdebb2f77cd20), notice in `stb.txt`. - **nlohmann/json** (MIT): pinned in the dependency lock, notice in `json.txt`. + +- **FreeType** (FreeType License): pinned 2.13.3, notice in `freetype.txt`. Portions of this software are copyright © The FreeType Project (www.freetype.org). All rights reserved. +- **HarfBuzz** (MIT-style): pinned 10.4.0, copyright and permissions in `harfbuzz.txt`. +- **Noto Sans** (SIL Open Font License 1.1): editor font only; see `../assets/fonts/OFL.txt` and `../assets/fonts/NOTICE.md`. + +The default Editor build uses the pinned FreeType/HarfBuzz archives. An explicit +`FASET_USE_SYSTEM_TEXT_LIBRARIES=ON` uses installed versions; distributors must retain +the notices appropriate to those installations. These font libraries and the editor +font are not linked into or required by exported games. diff --git a/licenses/freetype.txt b/licenses/freetype.txt new file mode 100644 index 0000000..c406d15 --- /dev/null +++ b/licenses/freetype.txt @@ -0,0 +1,169 @@ + The FreeType Project LICENSE + ---------------------------- + + 2006-Jan-27 + + Copyright 1996-2002, 2006 by + David Turner, Robert Wilhelm, and Werner Lemberg + + + +Introduction +============ + + The FreeType Project is distributed in several archive packages; + some of them may contain, in addition to the FreeType font engine, + various tools and contributions which rely on, or relate to, the + FreeType Project. + + This license applies to all files found in such packages, and + which do not fall under their own explicit license. The license + affects thus the FreeType font engine, the test programs, + documentation and makefiles, at the very least. + + This license was inspired by the BSD, Artistic, and IJG + (Independent JPEG Group) licenses, which all encourage inclusion + and use of free software in commercial and freeware products + alike. As a consequence, its main points are that: + + o We don't promise that this software works. However, we will be + interested in any kind of bug reports. (`as is' distribution) + + o You can use this software for whatever you want, in parts or + full form, without having to pay us. (`royalty-free' usage) + + o You may not pretend that you wrote this software. If you use + it, or only parts of it, in a program, you must acknowledge + somewhere in your documentation that you have used the + FreeType code. (`credits') + + We specifically permit and encourage the inclusion of this + software, with or without modifications, in commercial products. + We disclaim all warranties covering The FreeType Project and + assume no liability related to The FreeType Project. + + + Finally, many people asked us for a preferred form for a + credit/disclaimer to use in compliance with this license. We thus + encourage you to use the following text: + + """ + Portions of this software are copyright © The FreeType + Project (www.freetype.org). All rights reserved. + """ + + Please replace with the value from the FreeType version you + actually use. + + +Legal Terms +=========== + +0. Definitions +-------------- + + Throughout this license, the terms `package', `FreeType Project', + and `FreeType archive' refer to the set of files originally + distributed by the authors (David Turner, Robert Wilhelm, and + Werner Lemberg) as the `FreeType Project', be they named as alpha, + beta or final release. + + `You' refers to the licensee, or person using the project, where + `using' is a generic term including compiling the project's source + code as well as linking it to form a `program' or `executable'. + This program is referred to as `a program using the FreeType + engine'. + + This license applies to all files distributed in the original + FreeType Project, including all source code, binaries and + documentation, unless otherwise stated in the file in its + original, unmodified form as distributed in the original archive. + If you are unsure whether or not a particular file is covered by + this license, you must contact us to verify this. + + The FreeType Project is copyright (C) 1996-2000 by David Turner, + Robert Wilhelm, and Werner Lemberg. All rights reserved except as + specified below. + +1. No Warranty +-------------- + + THE FREETYPE PROJECT IS PROVIDED `AS IS' WITHOUT WARRANTY OF ANY + KIND, EITHER EXPRESS OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + PURPOSE. IN NO EVENT WILL ANY OF THE AUTHORS OR COPYRIGHT HOLDERS + BE LIABLE FOR ANY DAMAGES CAUSED BY THE USE OR THE INABILITY TO + USE, OF THE FREETYPE PROJECT. + +2. Redistribution +----------------- + + This license grants a worldwide, royalty-free, perpetual and + irrevocable right and license to use, execute, perform, compile, + display, copy, create derivative works of, distribute and + sublicense the FreeType Project (in both source and object code + forms) and derivative works thereof for any purpose; and to + authorize others to exercise some or all of the rights granted + herein, subject to the following conditions: + + o Redistribution of source code must retain this license file + (`FTL.TXT') unaltered; any additions, deletions or changes to + the original files must be clearly indicated in accompanying + documentation. The copyright notices of the unaltered, + original files must be preserved in all copies of source + files. + + o Redistribution in binary form must provide a disclaimer that + states that the software is based in part of the work of the + FreeType Team, in the distribution documentation. We also + encourage you to put an URL to the FreeType web page in your + documentation, though this isn't mandatory. + + These conditions apply to any software derived from or based on + the FreeType Project, not just the unmodified files. If you use + our work, you must acknowledge us. However, no fee need be paid + to us. + +3. Advertising +-------------- + + Neither the FreeType authors and contributors nor you shall use + the name of the other for commercial, advertising, or promotional + purposes without specific prior written permission. + + We suggest, but do not require, that you use one or more of the + following phrases to refer to this software in your documentation + or advertising materials: `FreeType Project', `FreeType Engine', + `FreeType library', or `FreeType Distribution'. + + As you have not signed this license, you are not required to + accept it. However, as the FreeType Project is copyrighted + material, only this license, or another one contracted with the + authors, grants you the right to use, distribute, and modify it. + Therefore, by using, distributing, or modifying the FreeType + Project, you indicate that you understand and accept all the terms + of this license. + +4. Contacts +----------- + + There are two mailing lists related to FreeType: + + o freetype@nongnu.org + + Discusses general use and applications of FreeType, as well as + future and wanted additions to the library and distribution. + If you are looking for support, start in this list if you + haven't found anything to help you in the documentation. + + o freetype-devel@nongnu.org + + Discusses bugs, as well as engine internals, design issues, + specific licenses, porting, etc. + + Our home page can be found at + + https://www.freetype.org + + +--- end of FTL.TXT --- diff --git a/licenses/harfbuzz.txt b/licenses/harfbuzz.txt new file mode 100644 index 0000000..1dd917e --- /dev/null +++ b/licenses/harfbuzz.txt @@ -0,0 +1,42 @@ +HarfBuzz is licensed under the so-called "Old MIT" license. Details follow. +For parts of HarfBuzz that are licensed under different licenses see individual +files names COPYING in subdirectories where applicable. + +Copyright © 2010-2022 Google, Inc. +Copyright © 2015-2020 Ebrahim Byagowi +Copyright © 2019,2020 Facebook, Inc. +Copyright © 2012,2015 Mozilla Foundation +Copyright © 2011 Codethink Limited +Copyright © 2008,2010 Nokia Corporation and/or its subsidiary(-ies) +Copyright © 2009 Keith Stribley +Copyright © 2011 Martin Hosken and SIL International +Copyright © 2007 Chris Wilson +Copyright © 2005,2006,2020,2021,2022,2023 Behdad Esfahbod +Copyright © 2004,2007,2008,2009,2010,2013,2021,2022,2023 Red Hat, Inc. +Copyright © 1998-2005 David Turner and Werner Lemberg +Copyright © 2016 Igalia S.L. +Copyright © 2022 Matthias Clasen +Copyright © 2018,2021 Khaled Hosny +Copyright © 2018,2019,2020 Adobe, Inc +Copyright © 2013-2015 Alexei Podtelezhnikov + +For full copyright notices consult the individual files in the package. + + +Permission is hereby granted, without written agreement and without +license or royalty fees, to use, copy, modify, and distribute this +software and its documentation for any purpose, provided that the +above copyright notice and the following two paragraphs appear in +all copies of this software. + +IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR +DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES +ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN +IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGE. + +THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS +ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO +PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. diff --git a/licenses/json.txt b/licenses/json.txt index 2071b23..5bfa8b2 100644 --- a/licenses/json.txt +++ b/licenses/json.txt @@ -1,3 +1,9 @@ +nlohmann/json v3.12.0 +SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann +SPDX-License-Identifier: MIT + +The following license text is reproduced from upstream LICENSES/MIT.txt. + MIT License Copyright (c) diff --git a/mkdocs.yml b/mkdocs.yml index 5c018bb..2b04696 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -22,6 +22,9 @@ plugins: - search markdown_extensions: - admonition + - pymdownx.snippets: + base_path: ["."] + check_paths: true - pymdownx.details - pymdownx.superfences - pymdownx.highlight: @@ -31,5 +34,12 @@ nav: - Build from source: getting-started/build.md - C++ gameplay: - How gameplay works: scripting/index.md + - Write your first behavior: scripting/first-behavior.md - Frame and physics updates: scripting/lifecycle.md + - Physics and grounded movement: scripting/physics.md + - Runtime API: scripting/api.md + - Compiled examples: scripting/examples.md + - Editor automation: + - MCP and command line: editor/mcp.md + - Native extensions: editor/extensions.md - Contributing to this manual: contributing.md diff --git a/shaders/baseline.slang b/shaders/baseline.slang index af39aa2..92cf8da 100644 --- a/shaders/baseline.slang +++ b/shaders/baseline.slang @@ -34,8 +34,13 @@ VertexOutput vertexMain(VertexInput v) { float4 shadowMain(VertexInput v) : SV_Position { return mul(frame.lightViewProjection, float4(v.world,1)); } [shader("fragment")] float4 fragmentMain(VertexOutput v) : SV_Target { - float4 base = v.color * colorMap.Sample(colorSampler, v.uv); - if (dot(v.normal,v.normal) < 0.01) return base; + float4 sampled = colorMap.Sample(colorSampler, v.uv); + if (dot(v.normal,v.normal) < 1e-12) { + // UI/sprite tint is in display space; sRGB textures were decoded by Vulkan. + if (v.material.x > 0.5) sampled.rgb = lerp(sampled.rgb * 12.92, 1.055 * pow(max(sampled.rgb,0),float3(1.0/2.4)) - 0.055, step(0.0031308, sampled.rgb)); + return v.color * sampled; + } + float4 base = v.color * sampled; const float pi = 3.14159265; float3 n=normalize(v.normal), l=normalize(-frame.lightDirection.xyz), view=normalize(frame.eye.xyz-v.world), h=normalize(l+view); float nl=max(dot(n,l),0.0), nv=max(dot(n,view),0.001), nh=max(dot(n,h),0.0), vh=max(dot(view,h),0.0); diff --git a/src/assets/asset_data.cpp b/src/assets/asset_data.cpp new file mode 100644 index 0000000..e57f48a --- /dev/null +++ b/src/assets/asset_data.cpp @@ -0,0 +1,203 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace faset::assets { +namespace fs = std::filesystem; +namespace { +void valid_id(const std::string& id) { + if (id.empty() || id.size() > 128 || !std::all_of(id.begin(), id.end(), [](unsigned char c) { + return std::isalnum(c) || c == '-' || c == '_'; + })) + throw std::runtime_error("Invalid AssetId"); +} +std::vector read_bytes(const fs::path& path) { + std::ifstream file(path, std::ios::binary | std::ios::ate); + if (!file) + throw std::runtime_error("Cannot read cooked file: " + path.string()); + auto length = file.tellg(); + if (length < 0 || static_cast(length) > 1024ull * 1024 * 1024) + throw std::runtime_error("Cooked file exceeds 1 GiB limit"); + std::vector bytes(static_cast(length)); + file.seekg(0); + if (!bytes.empty() && !file.read(reinterpret_cast(bytes.data()), + static_cast(bytes.size()))) + throw std::runtime_error("Truncated cooked file"); + return bytes; +} +Json read_json(const fs::path& path) { + auto bytes = read_bytes(path); + if (bytes.empty()) + throw std::runtime_error("Empty cooked JSON manifest"); + return Json::parse(reinterpret_cast(bytes.data()), + reinterpret_cast(bytes.data() + bytes.size())); +} +fs::path cooked_path(const fs::path& directory, const std::string& name) { + if (name.empty()) + throw std::runtime_error("Empty cooked path"); + return faset::project_path(directory, fs::path(name)); +} +void validate_generation(const fs::path& directory, const Json& manifest) { + if (manifest.at("schema_version") != 1) + throw std::runtime_error("Unsupported asset manifest version"); + std::set files; + for (const auto& file : manifest.at("files")) { + auto name = file.at("path").get(); + if (!files.insert(name).second) + throw std::runtime_error("Duplicate cooked file path"); + auto bytes = read_bytes(cooked_path(directory, name)); + if (bytes.size() != file.at("size").get() || + faset::sha256(std::span(bytes)) != + file.at("sha256").get()) + throw std::runtime_error("Corrupt cooked file: " + name); + } + for (const auto& mesh : manifest.at("meshes")) + for (const auto& primitive : mesh.at("primitives")) + if (!files.contains(primitive.at("path").get())) + throw std::runtime_error("Mesh payload is missing from its manifest"); + for (const auto& texture : manifest.at("textures")) + if (!files.contains(texture.at("path").get())) + throw std::runtime_error("Texture payload is missing from its manifest"); +} +struct BinaryReader { + const std::vector& bytes; + std::size_t cursor = 0; + std::uint32_t u32() { + if (bytes.size() - cursor < 4) + throw std::runtime_error("Truncated cooked mesh"); + std::uint32_t v = 0; + for (int i = 0; i < 4; ++i) + v |= std::to_integer(bytes[cursor++]) << (8 * i); + return v; + } + float number() { + auto v = std::bit_cast(u32()); + if (!std::isfinite(v)) + throw std::runtime_error("Invalid cooked float"); + return v; + } +}; +Primitive decode_primitive(const std::vector& bytes, int material) { + BinaryReader in{bytes}; + if (in.u32() != 0x48534d46 || in.u32() != 1) + throw std::runtime_error("Unsupported cooked mesh format"); + const auto nv = in.u32(), ni = in.u32(); + if (static_cast(nv) * 32 + static_cast(ni) * 4 + 16 != + bytes.size()) + throw std::runtime_error("Invalid cooked mesh size"); + Primitive p; + p.material = material; + p.vertices.resize(nv); + p.indices.resize(ni); + for (auto& v : p.vertices) { + for (auto& x : v.position) + x = in.number(); + for (auto& x : v.normal) + x = in.number(); + for (auto& x : v.uv) + x = in.number(); + } + for (auto& i : p.indices) { + i = in.u32(); + if (i >= nv) + throw std::runtime_error("Cooked mesh index out of range"); + } + return p; +} +} // namespace +AssetStore::AssetStore(fs::path root) + : cache_root_(fs::absolute(std::move(root)).lexically_normal()) {} +fs::path AssetStore::generation_directory(const std::string& id) const { + valid_id(id); + const auto root = faset::project_path(cache_root_, fs::path("assets") / id); + const auto pointer = read_json(root / "current.json"); + const auto generation = pointer.at("generation").get(); + valid_id(generation); + return faset::project_path(root, fs::path("generations") / generation); +} +Json AssetStore::current_manifest(const std::string& id) const { + valid_id(id); + const auto root = faset::project_path(cache_root_, fs::path("assets") / id); + const auto pointer = read_json(root / "current.json"); + const auto generation = pointer.at("generation").get(); + valid_id(generation); + auto manifest = read_json( + faset::project_path(root, fs::path("generations") / generation / "manifest.json")); + if (manifest.at("asset_id").get() != id || + manifest.at("generation").get() != generation) + throw std::runtime_error("Cooked manifest identity does not match its generation"); + // One pointer snapshot prevents mixing two concurrently published generations. + manifest["source"] = pointer.at("source"); + return manifest; +} +CookedAsset AssetStore::load_asset(const std::string& id) const { + const auto directory = generation_directory(id); + const auto m = read_json(directory / "manifest.json"); + validate_generation(directory, m); + if (m.at("asset_id").get() != id || + m.at("generation").get() != directory.filename().string()) + throw std::runtime_error("Cooked asset identity does not match its generation"); + CookedAsset asset; + asset.asset_id = m.at("asset_id"); + asset.generation = m.at("generation"); + for (const auto& n : m.at("nodes")) { + Node node; + node.id = n.at("id"); + node.name = n.at("name"); + node.parent_id = n.at("parent_id"); + node.mesh = n.at("mesh"); + node.local_transform = n.at("local_transform").get>(); + node.stable_source_id = n.at("stable_source_id"); + asset.nodes.push_back(std::move(node)); + } + for (const auto& j : m.at("meshes")) { + Mesh mesh; + mesh.id = j.at("id"); + mesh.name = j.at("name"); + for (const auto& primitive : j.at("primitives")) + mesh.primitives.push_back(decode_primitive( + read_bytes(cooked_path(directory, primitive.at("path").get())), + primitive.at("material"))); + asset.meshes.push_back(std::move(mesh)); + } + for (const auto& j : m.at("materials")) { + Material material; + material.id = j.at("id"); + material.name = j.at("name"); + material.base_color = j.at("base_color").get>(); + material.emissive = j.at("emissive").get>(); + material.metallic = j.at("metallic"); + material.roughness = j.at("roughness"); + material.alpha_mode = j.at("alpha_mode"); + material.alpha_cutoff = j.at("alpha_cutoff"); + material.double_sided = j.at("double_sided"); + material.unlit = j.at("unlit"); + material.base_color_texture = j.at("base_color_texture"); + material.metallic_roughness_texture = j.at("metallic_roughness_texture"); + material.normal_texture = j.at("normal_texture"); + material.occlusion_texture = j.at("occlusion_texture"); + material.emissive_texture = j.at("emissive_texture"); + asset.materials.push_back(std::move(material)); + } + for (const auto& j : m.at("textures")) { + Texture texture; + texture.id = j.at("id"); + texture.name = j.at("name"); + texture.mime_type = j.at("mime_type"); + texture.bytes = read_bytes(cooked_path(directory, j.at("path").get())); + texture.wrap_s = j.at("wrap_s"); + texture.wrap_t = j.at("wrap_t"); + texture.min_filter = j.at("min_filter"); + texture.mag_filter = j.at("mag_filter"); + asset.textures.push_back(std::move(texture)); + } + return asset; +} +} // namespace faset::assets diff --git a/src/assets/asset_pipeline.cpp b/src/assets/asset_pipeline.cpp index ca18cc7..aec3e62 100644 --- a/src/assets/asset_pipeline.cpp +++ b/src/assets/asset_pipeline.cpp @@ -1,6 +1,23 @@ +#include #include #include -#include +// Import validation owns a private decoder; Player's decoder remains a separate +// binary boundary. +#define STB_IMAGE_IMPLEMENTATION +#define STB_IMAGE_STATIC +#define STBI_ONLY_PNG +#define STBI_ONLY_JPEG +#define STBI_NO_STDIO +#define STBI_NO_HDR +#define STBI_NO_LINEAR +#if defined(__GNUC__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-function" +#endif +#include +#if defined(__GNUC__) +#pragma GCC diagnostic pop +#endif #include #include #include @@ -29,360 +46,775 @@ std::mutex writer_mutex; struct Cancelled {}; void checkpoint(ImportJob& job, float fraction, const std::string& stage) { job.report(fraction, stage); - if (job.cancelled()) throw Cancelled{}; + if (job.cancelled()) + throw Cancelled{}; } std::string uuid() { std::random_device random; std::ostringstream out; - for (int i=0; i<4; ++i) out << std::hex << std::setw(8) << std::setfill('0') << random(); + for (int i = 0; i < 4; ++i) + out << std::hex << std::setw(8) << std::setfill('0') << random(); return out.str(); } void valid_id(const std::string& id) { - if (id.empty() || id.size()>128 || !std::all_of(id.begin(),id.end(),[](unsigned char c){return std::isalnum(c)||c=='-'||c=='_';})) + if (id.empty() || id.size() > 128 || !std::all_of(id.begin(), id.end(), [](unsigned char c) { + return std::isalnum(c) || c == '-' || c == '_'; + })) throw std::runtime_error("Invalid AssetId"); } std::vector read_bytes(const fs::path& path) { - std::ifstream file(path, std::ios::binary|std::ios::ate); - if (!file) throw std::runtime_error("Cannot read: "+path.string()); - const auto length=file.tellg(); - if (length<0 || static_cast(length)>1024ull*1024*1024) throw std::runtime_error("Input exceeds 1 GiB limit: "+path.string()); - std::vector data(static_cast(length)); file.seekg(0); - if (!data.empty()&&!file.read(reinterpret_cast(data.data()),static_cast(data.size()))) - throw std::runtime_error("Short read: "+path.string()); + std::ifstream file(path, std::ios::binary | std::ios::ate); + if (!file) + throw std::runtime_error("Cannot read: " + path.string()); + const auto length = file.tellg(); + if (length < 0 || static_cast(length) > 1024ull * 1024 * 1024) + throw std::runtime_error("Input exceeds 1 GiB limit: " + path.string()); + std::vector data(static_cast(length)); + file.seekg(0); + if (!data.empty() && + !file.read(reinterpret_cast(data.data()), static_cast(data.size()))) + throw std::runtime_error("Short read: " + path.string()); return data; } void write_bytes(const fs::path& path, const std::vector& data) { - fs::create_directories(path.parent_path()); std::ofstream out(path,std::ios::binary|std::ios::trunc); - if (!out || (!data.empty()&&!out.write(reinterpret_cast(data.data()),static_cast(data.size())))) throw std::runtime_error("Cannot write: "+path.string()); - out.close(); if (!out) throw std::runtime_error("Cannot close: "+path.string()); + fs::create_directories(path.parent_path()); + std::ofstream out(path, std::ios::binary | std::ios::trunc); + if (!out || (!data.empty() && !out.write(reinterpret_cast(data.data()), + static_cast(data.size())))) + throw std::runtime_error("Cannot write: " + path.string()); + out.close(); + if (!out) + throw std::runtime_error("Cannot close: " + path.string()); } Json read_json(const fs::path& path) { - std::ifstream in(path); if(!in)throw std::runtime_error("Cannot read JSON: "+path.string()); + std::ifstream in(path); + if (!in) + throw std::runtime_error("Cannot read JSON: " + path.string()); return Json::parse(in); } -void write_json(const fs::path& path,const Json& value) { - const auto text=value.dump(2)+"\n"; - write_bytes(path,std::vector(reinterpret_cast(text.data()),reinterpret_cast(text.data()+text.size()))); +void write_json(const fs::path& path, const Json& value) { + const auto text = value.dump(2) + "\n"; + write_bytes(path, std::vector( + reinterpret_cast(text.data()), + reinterpret_cast(text.data() + text.size()))); } -void atomic_json(const fs::path& path,const Json& value) { - fs::create_directories(path.parent_path()); auto temporary=path; temporary+=".tmp-"+uuid(); +void atomic_json(const fs::path& path, const Json& value) { + fs::create_directories(path.parent_path()); + auto temporary = path; + temporary += ".tmp-" + uuid(); try { - write_json(temporary,value); + write_json(temporary, value); #ifdef _WIN32 - if(!MoveFileExW(temporary.c_str(),path.c_str(),MOVEFILE_REPLACE_EXISTING|MOVEFILE_WRITE_THROUGH)) throw std::runtime_error("Atomic replace failed: "+path.string()); + if (!MoveFileExW(temporary.c_str(), path.c_str(), + MOVEFILE_REPLACE_EXISTING | MOVEFILE_WRITE_THROUGH)) + throw std::runtime_error("Atomic replace failed: " + path.string()); #else - fs::rename(temporary,path); + fs::rename(temporary, path); #endif - } catch(...) { std::error_code ec;fs::remove(temporary,ec);throw; } + } catch (...) { + std::error_code ec; + fs::remove(temporary, ec); + throw; + } +} +std::string hash_bytes(const std::vector& bytes) { + return faset::sha256(std::span(bytes)); +} +std::string stable_id(const std::string& kind, const std::string& key) { + return kind + "-" + faset::sha256(kind + ":" + key).substr(0, 32); +} +std::string safe_name(const char* name) { + return name ? name : ""; } -std::string hash_bytes(const std::vector& bytes) { return faset::sha256(std::span(bytes)); } -std::string stable_id(const std::string& kind,const std::string& key) { return kind+"-"+faset::sha256(kind+":"+key).substr(0,32); } -std::string safe_name(const char* name) { return name?name:""; } std::string source_id(const cgltf_extras& extras) { - if(!extras.data)return {}; - auto value=Json::parse(extras.data,nullptr,false); - if(value.is_object()&&value.contains("faset_id")&&value["faset_id"].is_string()) return value["faset_id"].get(); + if (!extras.data) + return {}; + auto value = Json::parse(extras.data, nullptr, false); + if (value.is_object() && value.contains("faset_id") && value["faset_id"].is_string()) + return value["faset_id"].get(); return {}; } std::string uri_decode(std::string value) { std::string result; - for(std::size_t i=0;i(c);i+=2; - } else result+=value[i]; + for (std::size_t i = 0; i < value.size(); ++i) { + if (value[i] == '%' && i + 2 < value.size()) { + const auto hex = value.substr(i + 1, 2); + std::size_t count = 0; + const int c = std::stoi(hex, &count, 16); + if (count != 2 || c == 0) + throw std::runtime_error("Invalid URI escape"); + result += static_cast(c); + i += 2; + } else + result += value[i]; } return result; } std::vector decode_data_uri(const std::string& uri) { - const auto comma=uri.find(','); - if(comma==std::string::npos||uri.substr(0,comma).find(";base64")==std::string::npos) throw std::runtime_error("Only base64 data URIs are supported"); - constexpr std::string_view alphabet="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; - std::vector data; std::uint32_t bits=0;int count=0; - for(std::size_t i=comma+1;i(v);count+=6; - if(count>=8){count-=8;data.push_back(static_cast((bits>>count)&255));} + const auto comma = uri.find(','); + if (comma == std::string::npos || uri.substr(0, comma).find(";base64") == std::string::npos) + throw std::runtime_error("Only base64 data URIs are supported"); + constexpr std::string_view alphabet = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + std::vector data; + std::uint32_t bits = 0; + int count = 0; + for (std::size_t i = comma + 1; i < uri.size(); ++i) { + if (uri[i] == '=') + break; + const auto v = alphabet.find(uri[i]); + if (v == std::string_view::npos) + throw std::runtime_error("Invalid base64 image"); + bits = (bits << 6) | static_cast(v); + count += 6; + if (count >= 8) { + count -= 8; + data.push_back(static_cast((bits >> count) & 255)); + } } return data; } -fs::path external_path(const fs::path& source,const std::string& uri) { - if(uri.find("://")!=std::string::npos)throw std::runtime_error("Network URI is not an import dependency: "+uri); - const fs::path relative=uri_decode(uri); - if(relative.is_absolute())throw std::runtime_error("glTF URI must be relative"); - return (source.parent_path()/relative).lexically_normal(); +fs::path external_path(const fs::path& source, const std::string& uri) { + if (uri.find("://") != std::string::npos) + throw std::runtime_error("Network URI is not an import dependency: " + uri); + const fs::path relative = uri_decode(uri); + if (relative.is_absolute()) + throw std::runtime_error("glTF URI must be relative"); + return (source.parent_path() / relative).lexically_normal(); } -struct Dependency { fs::path path; std::string digest; std::vector bytes; }; -using Dependencies=std::map; -std::vector dependency_bytes(const fs::path& source,const std::string& uri,Dependencies& dependencies) { - if(auto found=dependencies.find(uri);found!=dependencies.end())return found->second.bytes; - auto path=external_path(source,uri);auto bytes=read_bytes(path);dependencies[uri]={path,hash_bytes(bytes),bytes};return bytes; +struct Dependency { + fs::path path; + std::string digest; + std::vector bytes; +}; +using Dependencies = std::map; +std::vector dependency_bytes(const fs::path& source, const std::string& uri, + Dependencies& dependencies) { + if (auto found = dependencies.find(uri); found != dependencies.end()) + return found->second.bytes; + auto path = external_path(source, uri); + auto bytes = read_bytes(path); + dependencies[uri] = {path, hash_bytes(bytes), bytes}; + return bytes; } -std::string image_mime(const cgltf_image& image,const std::vector& bytes) { - if(image.mime_type)return image.mime_type; - if(bytes.size()>=4&&bytes[0]==std::byte{0x89}&&bytes[1]==std::byte{'P'})return "image/png"; - if(bytes.size()>=2&&bytes[0]==std::byte{0xff}&&bytes[1]==std::byte{0xd8})return "image/jpeg"; +std::string image_mime(const cgltf_image& image, const std::vector& bytes) { + if (image.mime_type) + return image.mime_type; + if (bytes.size() >= 4 && bytes[0] == std::byte{0x89} && bytes[1] == std::byte{'P'}) + return "image/png"; + if (bytes.size() >= 2 && bytes[0] == std::byte{0xff} && bytes[1] == std::byte{0xd8}) + return "image/jpeg"; return "application/octet-stream"; } -std::vector image_bytes(const cgltf_image& image,const fs::path& source,Dependencies& dependencies) { - if(image.uri) { - const std::string uri=image.uri; - return uri.starts_with("data:")?decode_data_uri(uri):dependency_bytes(source,uri,dependencies); +std::vector image_bytes(const cgltf_image& image, const fs::path& source, + Dependencies& dependencies) { + if (image.uri) { + const std::string uri = image.uri; + return uri.starts_with("data:") ? decode_data_uri(uri) + : dependency_bytes(source, uri, dependencies); } - if(image.buffer_view&&image.buffer_view->buffer&&image.buffer_view->buffer->data) { - const auto& view=*image.buffer_view; - if(view.offset>view.buffer->size||view.size>view.buffer->size-view.offset)throw std::runtime_error("Image buffer view out of bounds"); - const auto* begin=static_cast(view.buffer->data)+view.offset; - return {begin,begin+view.size}; + if (image.buffer_view && image.buffer_view->buffer && image.buffer_view->buffer->data) { + const auto& view = *image.buffer_view; + if (view.offset > view.buffer->size || view.size > view.buffer->size - view.offset) + throw std::runtime_error("Image buffer view out of bounds"); + const auto* begin = static_cast(view.buffer->data) + view.offset; + return {begin, begin + view.size}; } throw std::runtime_error("Texture has no supported image payload"); } -void put_u32(std::vector& out,std::uint32_t v) {for(int i=0;i<4;++i)out.push_back(static_cast((v>>(8*i))&255));} -void put_float(std::vector& out,float v) {if(!std::isfinite(v))throw std::runtime_error("Non-finite mesh value");put_u32(out,std::bit_cast(v));} -struct BinaryReader { - const std::vector& bytes;std::size_t cursor=0; - std::uint32_t u32(){if(bytes.size()-cursor<4)throw std::runtime_error("Truncated cooked mesh");std::uint32_t v=0;for(int i=0;i<4;++i)v|=std::to_integer(bytes[cursor++])<<(8*i);return v;} - float number(){auto v=std::bit_cast(u32());if(!std::isfinite(v))throw std::runtime_error("Invalid cooked float");return v;} -}; +void put_u32(std::vector& out, std::uint32_t v) { + for (int i = 0; i < 4; ++i) + out.push_back(static_cast((v >> (8 * i)) & 255)); +} +void put_float(std::vector& out, float v) { + if (!std::isfinite(v)) + throw std::runtime_error("Non-finite mesh value"); + put_u32(out, std::bit_cast(v)); +} std::vector encode_primitive(const Primitive& p) { - std::vector out;put_u32(out,0x48534d46);put_u32(out,1);put_u32(out,static_cast(p.vertices.size()));put_u32(out,static_cast(p.indices.size())); - for(const auto& v:p.vertices){for(auto f:v.position)put_float(out,f);for(auto f:v.normal)put_float(out,f);for(auto f:v.uv)put_float(out,f);} - for(auto i:p.indices)put_u32(out,i);return out; + std::vector out; + put_u32(out, 0x48534d46); + put_u32(out, 1); + put_u32(out, static_cast(p.vertices.size())); + put_u32(out, static_cast(p.indices.size())); + for (const auto& v : p.vertices) { + for (auto f : v.position) + put_float(out, f); + for (auto f : v.normal) + put_float(out, f); + for (auto f : v.uv) + put_float(out, f); + } + for (auto i : p.indices) + put_u32(out, i); + return out; } -Primitive decode_primitive(const std::vector& bytes,int material) { - BinaryReader in{bytes};if(in.u32()!=0x48534d46||in.u32()!=1)throw std::runtime_error("Unsupported cooked mesh format"); - const auto nv=in.u32(),ni=in.u32(); - if(static_cast(nv)*32+static_cast(ni)*4+16!=bytes.size())throw std::runtime_error("Invalid cooked mesh size"); - Primitive p;p.material=material;p.vertices.resize(nv);p.indices.resize(ni); - for(auto& v:p.vertices){for(auto& x:v.position)x=in.number();for(auto& x:v.normal)x=in.number();for(auto& x:v.uv)x=in.number();} - for(auto& i:p.indices){i=in.u32();if(i>=nv)throw std::runtime_error("Cooked mesh index out of range");}return p; -} -std::vector unpack(const cgltf_accessor* accessor,std::size_t elements) { - if(!accessor || cgltf_num_components(accessor->type)!=elements)throw std::runtime_error("Unexpected vertex attribute type"); - if(accessor->count>10000000)throw std::runtime_error("Mesh exceeds vertex limit"); - std::vector values(accessor->count*elements); - if(cgltf_accessor_unpack_floats(accessor,values.data(),values.size())!=values.size())throw std::runtime_error("Cannot unpack vertex attribute"); - if(!std::all_of(values.begin(),values.end(),[](float v){return std::isfinite(v);}))throw std::runtime_error("Non-finite vertex attribute");return values; +std::vector unpack(const cgltf_accessor* accessor, std::size_t elements) { + if (!accessor || cgltf_num_components(accessor->type) != elements) + throw std::runtime_error("Unexpected vertex attribute type"); + if (accessor->count > 10000000) + throw std::runtime_error("Mesh exceeds vertex limit"); + std::vector values(accessor->count * elements); + if (cgltf_accessor_unpack_floats(accessor, values.data(), values.size()) != values.size()) + throw std::runtime_error("Cannot unpack vertex attribute"); + if (!std::all_of(values.begin(), values.end(), [](float v) { return std::isfinite(v); })) + throw std::runtime_error("Non-finite vertex attribute"); + return values; } void calculate_normals(Primitive& primitive) { - for(auto& v:primitive.vertices)v.normal={0,0,0}; - for(std::size_t i=0;i u{},v{},n{};for(int j=0;j<3;++j){u[j]=b.position[j]-a.position[j];v[j]=c.position[j]-a.position[j];} - n={u[1]*v[2]-u[2]*v[1],u[2]*v[0]-u[0]*v[2],u[0]*v[1]-u[1]*v[0]}; - for(auto* vertex:{&a,&b,&c})for(int j=0;j<3;++j)vertex->normal[j]+=n[j]; + for (auto& v : primitive.vertices) + v.normal = {0, 0, 0}; + for (std::size_t i = 0; i < primitive.indices.size(); i += 3) { + auto& a = primitive.vertices[primitive.indices[i]]; + auto& b = primitive.vertices[primitive.indices[i + 1]]; + auto& c = primitive.vertices[primitive.indices[i + 2]]; + std::array u{}, v{}, n{}; + for (int j = 0; j < 3; ++j) { + u[j] = b.position[j] - a.position[j]; + v[j] = c.position[j] - a.position[j]; + } + n = {u[1] * v[2] - u[2] * v[1], u[2] * v[0] - u[0] * v[2], u[0] * v[1] - u[1] * v[0]}; + for (auto* vertex : {&a, &b, &c}) + for (int j = 0; j < 3; ++j) + vertex->normal[j] += n[j]; + } + for (auto& v : primitive.vertices) { + const auto length = + std::sqrt(std::inner_product(v.normal.begin(), v.normal.end(), v.normal.begin(), 0.f)); + if (length > 1e-12f) + for (auto& n : v.normal) + n /= length; + else + v.normal = {0, 0, 1}; } - for(auto& v:primitive.vertices){const auto length=std::sqrt(std::inner_product(v.normal.begin(),v.normal.end(),v.normal.begin(),0.f));if(length>1e-12f)for(auto& n:v.normal)n/=length;else v.normal={0,0,1};} } -int texture_index(const cgltf_texture_view& view,const cgltf_data& data) { - if(!view.texture)return -1; - if(view.texcoord!=0||view.has_transform)throw std::runtime_error("Only TEXCOORD_0 without texture transform is supported by this import profile"); - return static_cast(view.texture-data.textures); +int texture_index(const cgltf_texture_view& view, const cgltf_data& data) { + if (!view.texture) + return -1; + if (view.texcoord != 0 || view.has_transform) + throw std::runtime_error("Only TEXCOORD_0 without texture transform is " + "supported by this import profile"); + return static_cast(view.texture - data.textures); } -void add_file(Json& manifest,const fs::path& stage,const std::string& path,const std::vector& bytes) { - write_bytes(stage/path,bytes);manifest["files"].push_back({{"path",path},{"sha256",hash_bytes(bytes)},{"size",bytes.size()}}); +void add_file(Json& manifest, const fs::path& stage, const std::string& path, + const std::vector& bytes) { + write_bytes(stage / path, bytes); + manifest["files"].push_back( + {{"path", path}, {"sha256", hash_bytes(bytes)}, {"size", bytes.size()}}); } -void validate_generation(const fs::path& directory,const Json& manifest) { - if(manifest.at("schema_version")!=1)throw std::runtime_error("Unsupported asset manifest version"); - for(const auto& file:manifest.at("files")) { - const fs::path relative=file.at("path").get(); - if(relative.is_absolute()||relative.string().find("..")!=std::string::npos)throw std::runtime_error("Invalid cooked file path"); - auto bytes=read_bytes(directory/relative); - if(bytes.size()!=file.at("size").get()||hash_bytes(bytes)!=file.at("sha256").get())throw std::runtime_error("Corrupt cooked file: "+relative.string()); +void validate_generation(const fs::path& directory, const Json& manifest) { + if (manifest.at("schema_version") != 1) + throw std::runtime_error("Unsupported asset manifest version"); + for (const auto& file : manifest.at("files")) { + const fs::path relative = file.at("path").get(); + if (relative.is_absolute() || relative.string().find("..") != std::string::npos) + throw std::runtime_error("Invalid cooked file path"); + auto bytes = read_bytes(directory / relative); + if (bytes.size() != file.at("size").get() || + hash_bytes(bytes) != file.at("sha256").get()) + throw std::runtime_error("Corrupt cooked file: " + relative.string()); } } Json material_json(const Material& m) { - return {{"id",m.id},{"name",m.name},{"base_color",m.base_color},{"metallic",m.metallic},{"roughness",m.roughness},{"emissive",m.emissive},{"alpha_mode",m.alpha_mode},{"alpha_cutoff",m.alpha_cutoff},{"double_sided",m.double_sided},{"unlit",m.unlit},{"base_color_texture",m.base_color_texture},{"metallic_roughness_texture",m.metallic_roughness_texture},{"normal_texture",m.normal_texture},{"occlusion_texture",m.occlusion_texture},{"emissive_texture",m.emissive_texture}}; -} + return {{"id", m.id}, + {"name", m.name}, + {"base_color", m.base_color}, + {"metallic", m.metallic}, + {"roughness", m.roughness}, + {"emissive", m.emissive}, + {"alpha_mode", m.alpha_mode}, + {"alpha_cutoff", m.alpha_cutoff}, + {"double_sided", m.double_sided}, + {"unlit", m.unlit}, + {"base_color_texture", m.base_color_texture}, + {"metallic_roughness_texture", m.metallic_roughness_texture}, + {"normal_texture", m.normal_texture}, + {"occlusion_texture", m.occlusion_texture}, + {"emissive_texture", m.emissive_texture}}; } +} // namespace -ImportJob::ImportJob(Observer observer):observer_(std::move(observer)){} -void ImportJob::cancel() noexcept {cancelled_.store(true);} -bool ImportJob::cancelled() const noexcept {return cancelled_.load();} -ImportProgress ImportJob::progress() const {std::lock_guard lock(mutex_);return progress_;} -void ImportJob::report(float fraction,std::string stage) { - ImportProgress progress{fraction,std::move(stage)};{std::lock_guard lock(mutex_);progress_=progress;} - if(observer_) { try { observer_(progress); } catch(...) { /* Observers cannot roll back a published result. */ } } +ImportJob::ImportJob(Observer observer) : observer_(std::move(observer)) {} +void ImportJob::cancel() noexcept { + cancelled_.store(true); } -AssetPipeline::AssetPipeline(fs::path root):cache_root_(fs::absolute(std::move(root)).lexically_normal()){} -ImportResult AssetPipeline::import_asset(const ImportRequest& request){ImportJob job;return import_asset(request,job);} -ImportResult AssetPipeline::import_asset(const ImportRequest& request,ImportJob& job) { - std::lock_guard writer(writer_mutex);ImportResult result;fs::path stage; +bool ImportJob::cancelled() const noexcept { + return cancelled_.load(); +} +ImportProgress ImportJob::progress() const { + std::lock_guard lock(mutex_); + return progress_; +} +void ImportJob::report(float fraction, std::string stage) { + ImportProgress progress{fraction, std::move(stage)}; + { + std::lock_guard lock(mutex_); + progress_ = progress; + } + if (observer_) { + try { + observer_(progress); + } catch (...) { /* Observers cannot roll back a published result. */ + } + } +} +AssetPipeline::AssetPipeline(fs::path root) : AssetStore(std::move(root)) {} +ImportResult AssetPipeline::import_asset(const ImportRequest& request) { + ImportJob job; + return import_asset(request, job); +} +ImportResult AssetPipeline::import_asset(const ImportRequest& request, ImportJob& job) { + std::lock_guard writer(writer_mutex); + ImportResult result; + fs::path stage; try { - checkpoint(job,0,"reading source"); - const auto logical_source=fs::absolute(request.source).lexically_normal(); - auto source=logical_source; - const auto logical_bytes=read_bytes(logical_source);const auto logical_hash=hash_bytes(logical_bytes); + checkpoint(job, 0, "reading source"); + const auto logical_source = fs::absolute(request.source).lexically_normal(); + auto source = logical_source; + const auto logical_bytes = read_bytes(logical_source); + const auto logical_hash = hash_bytes(logical_bytes); std::string bundle_asset_id; std::vector payload_snapshot; - if(logical_source.extension()==".json") { - auto bundle=Json::parse(reinterpret_cast(logical_bytes.data()),reinterpret_cast(logical_bytes.data()+logical_bytes.size())); - if(bundle.at("schema_version")!=1||bundle.at("files").empty())throw std::runtime_error("Invalid bundle manifest"); - bundle_asset_id=bundle.at("asset_id").get();valid_id(bundle_asset_id); - bool found_payload=false; - for(const auto& file:bundle.at("files")) { - const auto relative=fs::path(file.at("path").get()); - if(relative.is_absolute()||relative.string().find("..")!=std::string::npos)throw std::runtime_error("Invalid bundle payload path"); - const auto candidate=logical_source.parent_path()/relative;const auto bytes=read_bytes(candidate); - if(hash_bytes(bytes)!=file.at("sha256").get())throw std::runtime_error("Bundle payload digest mismatch"); - if(file.contains("size")&&file.at("size").get()!=bytes.size())throw std::runtime_error("Bundle payload size mismatch"); - if(!found_payload&&relative.extension()==".glb"){source=candidate;payload_snapshot=bytes;found_payload=true;} + if (logical_source.extension() == ".json") { + auto bundle = Json::parse( + reinterpret_cast(logical_bytes.data()), + reinterpret_cast(logical_bytes.data() + logical_bytes.size())); + if (bundle.at("schema_version") != 1 || bundle.at("files").empty()) + throw std::runtime_error("Invalid bundle manifest"); + bundle_asset_id = bundle.at("asset_id").get(); + valid_id(bundle_asset_id); + bool found_payload = false; + for (const auto& file : bundle.at("files")) { + const auto relative = fs::path(file.at("path").get()); + if (relative.is_absolute() || relative.string().find("..") != std::string::npos) + throw std::runtime_error("Invalid bundle payload path"); + const auto candidate = logical_source.parent_path() / relative; + const auto bytes = read_bytes(candidate); + if (hash_bytes(bytes) != file.at("sha256").get()) + throw std::runtime_error("Bundle payload digest mismatch"); + if (file.contains("size") && file.at("size").get() != bytes.size()) + throw std::runtime_error("Bundle payload size mismatch"); + if (!found_payload && relative.extension() == ".glb") { + source = candidate; + payload_snapshot = bytes; + found_payload = true; + } } - if(!found_payload)throw std::runtime_error("Bundle has no GLB payload"); + if (!found_payload) + throw std::runtime_error("Bundle has no GLB payload"); } - const auto source_bytes=source==logical_source?logical_bytes:payload_snapshot;const auto source_hash=hash_bytes(source_bytes); - const auto sidecar=fs::path(logical_source.string()+".faset-import.json"); - Json metadata=fs::exists(sidecar)?read_json(sidecar):Json::object(); - const auto settings=request.settings.is_null()?metadata.value("settings",Json::object()):request.settings; - if(!settings.is_object())throw std::runtime_error("Import settings must be an object"); - result.asset_id=request.asset_id.empty()?metadata.value("asset_id",bundle_asset_id.empty()?uuid():bundle_asset_id):request.asset_id;valid_id(result.asset_id); - if(!bundle_asset_id.empty()&&bundle_asset_id!=result.asset_id)throw std::runtime_error("Bundle AssetId disagrees with import identity"); - if(metadata.contains("asset_id")&&metadata.at("asset_id")!=result.asset_id)throw std::runtime_error("Explicit AssetId disagrees with source sidecar"); - const auto asset_root=cache_root_/"assets"/result.asset_id; - Json previous=fs::exists(asset_root/"current.json")?current_manifest(result.asset_id):Json(); - if(!previous.is_null()) { - const auto previous_source=fs::path(previous.at("source").get()); - if(previous_source!=logical_source&&fs::exists(previous_source))throw std::runtime_error("Duplicate AssetId: previous source still exists"); + const auto source_bytes = source == logical_source ? logical_bytes : payload_snapshot; + const auto source_hash = hash_bytes(source_bytes); + const auto sidecar = fs::path(logical_source.string() + ".faset-import.json"); + Json metadata = fs::exists(sidecar) ? read_json(sidecar) : Json::object(); + const auto settings = request.settings.is_null() + ? metadata.value("settings", Json::object()) + : request.settings; + if (!settings.is_object()) + throw std::runtime_error("Import settings must be an object"); + result.asset_id = + request.asset_id.empty() + ? metadata.value("asset_id", bundle_asset_id.empty() ? uuid() : bundle_asset_id) + : request.asset_id; + valid_id(result.asset_id); + if (!bundle_asset_id.empty() && bundle_asset_id != result.asset_id) + throw std::runtime_error("Bundle AssetId disagrees with import identity"); + if (metadata.contains("asset_id") && metadata.at("asset_id") != result.asset_id) + throw std::runtime_error("Explicit AssetId disagrees with source sidecar"); + const auto asset_root = cache_root_ / "assets" / result.asset_id; + Json previous = + fs::exists(asset_root / "current.json") ? current_manifest(result.asset_id) : Json(); + if (!previous.is_null()) { + const auto previous_source = fs::path(previous.at("source").get()); + if (previous_source != logical_source && fs::exists(previous_source)) + throw std::runtime_error("Duplicate AssetId: previous source still exists"); } - cgltf_options options{};cgltf_data* raw=nullptr; - auto parse=cgltf_parse(&options,source_bytes.data(),source_bytes.size(),&raw); - if(parse!=cgltf_result_success)throw std::runtime_error("Invalid glTF/GLB (parse "+std::to_string(parse)+")"); - std::unique_ptr data(raw,cgltf_free); - for(std::size_t i=0;iextensions_required_count;++i) - if(std::string(data->extensions_required[i])!="KHR_materials_unlit")throw std::runtime_error("Unsupported required extension: "+std::string(data->extensions_required[i])); Dependencies dependencies; - for(std::size_t i=0;ibuffers_count;++i) { - const auto* uri=data->buffers[i].uri; - if(uri&&!std::string_view(uri).starts_with("data:")) { - dependency_bytes(source,uri,dependencies); - auto& snapshot=dependencies.at(uri).bytes; - if(snapshot.size()buffers[i].size)throw std::runtime_error("External buffer shorter than declared"); - data->buffers[i].data=snapshot.data(); - data->buffers[i].data_free_method=cgltf_data_free_method_none; + CookedAsset asset; + asset.asset_id = result.asset_id; + auto extension = source.extension().string(); + std::transform(extension.begin(), extension.end(), extension.begin(), + [](unsigned char c) { return static_cast(std::tolower(c)); }); + const bool standalone_image = + extension == ".png" || extension == ".jpg" || extension == ".jpeg"; + const std::string recipe_version = + standalone_image ? "faset-image-1/stb-2.30" : importer_version; + Json image_info; + if (standalone_image) { + checkpoint(job, .15f, "validating image"); + if (source_bytes.size() > static_cast(std::numeric_limits::max())) + throw std::runtime_error("Encoded image exceeds decoder limit"); + const auto* encoded = reinterpret_cast(source_bytes.data()); + const auto length = static_cast(source_bytes.size()); + int width = 0, height = 0, channels = 0; + if (!stbi_info_from_memory(encoded, length, &width, &height, &channels)) + throw std::runtime_error("Invalid PNG/JPEG image header"); + if (width <= 0 || height <= 0 || width > 16384 || height > 16384 || + std::uint64_t(width) * std::uint64_t(height) > 64 * 1024 * 1024) + throw std::runtime_error("Image exceeds 16384 dimension or 64 megapixel limit"); + auto* pixels = stbi_load_from_memory(encoded, length, &width, &height, &channels, 4); + if (!pixels) + throw std::runtime_error( + "Cannot decode PNG/JPEG image: " + + std::string(stbi_failure_reason() ? stbi_failure_reason() : "invalid image")); + stbi_image_free(pixels); + const auto pixels_per_unit = settings.value("pixels_per_unit", 100.0); + if (!std::isfinite(pixels_per_unit) || pixels_per_unit <= 0 || + pixels_per_unit > 1000000) + throw std::runtime_error("pixels_per_unit must be a finite positive " + "number no greater than 1000000"); + image_info = {{"width", width}, + {"height", height}, + {"channels", channels}, + {"pixels_per_unit", pixels_per_unit}}; + Texture texture; + texture.id = stable_id("texture", "image:" + result.asset_id); + texture.name = "Image"; + texture.mime_type = extension == ".png" ? "image/png" : "image/jpeg"; + texture.bytes = source_bytes; + texture.wrap_s = texture.wrap_t = 33071; + asset.textures.push_back(std::move(texture)); + checkpoint(job, .5f, "preparing image payload"); + } else { + cgltf_options options{}; + cgltf_data* raw = nullptr; + auto parse = cgltf_parse(&options, source_bytes.data(), source_bytes.size(), &raw); + if (parse != cgltf_result_success) + throw std::runtime_error("Invalid glTF/GLB (parse " + std::to_string(parse) + ")"); + std::unique_ptr data(raw, cgltf_free); + for (std::size_t i = 0; i < data->extensions_required_count; ++i) + if (std::string(data->extensions_required[i]) != "KHR_materials_unlit") + throw std::runtime_error("Unsupported required extension: " + + std::string(data->extensions_required[i])); + for (std::size_t i = 0; i < data->buffers_count; ++i) { + const auto* uri = data->buffers[i].uri; + if (uri && !std::string_view(uri).starts_with("data:")) { + dependency_bytes(source, uri, dependencies); + auto& snapshot = dependencies.at(uri).bytes; + if (snapshot.size() < data->buffers[i].size) + throw std::runtime_error("External buffer shorter than declared"); + data->buffers[i].data = snapshot.data(); + data->buffers[i].data_free_method = cgltf_data_free_method_none; + } } - } - if(cgltf_load_buffers(&options,data.get(),source.string().c_str())!=cgltf_result_success)throw std::runtime_error("Cannot load glTF buffers"); - if(cgltf_validate(data.get())!=cgltf_result_success)throw std::runtime_error("Invalid glTF buffer/accessor layout"); - checkpoint(job,.15f,"extracting geometry"); - CookedAsset asset;asset.asset_id=result.asset_id; - std::set identifiers; - auto identify=[&](const std::string& kind,const cgltf_extras& extras,const std::string& fallback){ - const auto source_identity=source_id(extras);const auto id=stable_id(kind,source_identity.empty()?"fallback:"+fallback:"source:"+source_identity); - if(!identifiers.insert(id).second)throw std::runtime_error("DuplicateSourceId: "+kind+" "+source_identity); - return id; - }; - for(std::size_t mi=0;mimeshes_count;++mi) { - checkpoint(job,.15f+.3f*static_cast(mi)/std::max(1,data->meshes_count),"extracting meshes"); - const auto& mesh=data->meshes[mi];Mesh cooked;cooked.name=safe_name(mesh.name);cooked.id=identify("mesh",mesh.extras,std::to_string(mi)+":"+cooked.name); - for(std::size_t pi=0;pi{};const auto tex=uv?unpack(uv,2):std::vector{}; - const auto count=xyz.size()/3;if((normals&&normal.size()!=count*3)||(uv&&tex.size()!=count*2))throw std::runtime_error("Vertex attribute counts differ"); - Primitive output;output.material=primitive.material?static_cast(primitive.material-data->materials):-1;output.vertices.resize(count); - for(std::size_t i=0;iis_sparse||primitive.indices->type!=cgltf_type_scalar|| - (primitive.indices->component_type!=cgltf_component_type_r_8u&&primitive.indices->component_type!=cgltf_component_type_r_16u&&primitive.indices->component_type!=cgltf_component_type_r_32u))) - throw std::runtime_error("Indices require a dense unsigned integer accessor"); - const auto index_count=primitive.indices?primitive.indices->count:count; - if(index_count%3||index_count>30000000)throw std::runtime_error("Invalid triangle index count"); - output.indices.resize(index_count); - for(std::size_t i=0;i=count)throw std::runtime_error("Index outside vertex array");output.indices[i]=static_cast(index);} - if(!normals)calculate_normals(output);cooked.primitives.push_back(std::move(output)); - if(primitive.targets_count)result.diagnostics.push_back("Morph targets imported as static base geometry"); - } - asset.meshes.push_back(std::move(cooked)); - } - for(std::size_t ni=0;ninodes_count;++ni) { - const auto& node=data->nodes[ni];Node output;output.name=safe_name(node.name);output.stable_source_id=!source_id(node.extras).empty(); - output.id=identify("node",node.extras,std::to_string(ni)+":"+output.name);output.mesh=node.mesh?static_cast(node.mesh-data->meshes):-1; - cgltf_node_transform_local(&node,output.local_transform.data()); - if(!std::all_of(output.local_transform.begin(),output.local_transform.end(),[](float v){return std::isfinite(v);}))throw std::runtime_error("Non-finite node transform"); - asset.nodes.push_back(std::move(output));if(node.skin)result.diagnostics.push_back("Skinned node imported in static rest pose; animation playback is not cooked"); - } - for(std::size_t ni=0;ninodes_count;++ni)if(data->nodes[ni].parent)asset.nodes[ni].parent_id=asset.nodes[static_cast(data->nodes[ni].parent-data->nodes)].id; - // Only instantiate the selected/default scene. Unused resources remain reusable outputs. - if(data->scenes_count) { - const auto* selected=data->scene?data->scene:&data->scenes[0]; - std::set active_nodes; - std::function visit=[&](const cgltf_node* n){ - auto index=static_cast(n-data->nodes);if(!active_nodes.insert(index).second)return; - for(std::size_t i=0;ichildren_count;++i)visit(n->children[i]); + if (cgltf_load_buffers(&options, data.get(), source.string().c_str()) != + cgltf_result_success) + throw std::runtime_error("Cannot load glTF buffers"); + if (cgltf_validate(data.get()) != cgltf_result_success) + throw std::runtime_error("Invalid glTF buffer/accessor layout"); + checkpoint(job, .15f, "extracting geometry"); + std::set identifiers; + auto identify = [&](const std::string& kind, const cgltf_extras& extras, + const std::string& fallback) { + const auto source_identity = source_id(extras); + const auto id = + stable_id(kind, source_identity.empty() ? "fallback:" + fallback + : "source:" + source_identity); + if (!identifiers.insert(id).second) + throw std::runtime_error("DuplicateSourceId: " + kind + " " + source_identity); + return id; }; - for(std::size_t i=0;inodes_count;++i)visit(selected->nodes[i]); - std::vector active;for(std::size_t i=0;imeshes_count; ++mi) { + checkpoint(job, + .15f + .3f * static_cast(mi) / + std::max(1, data->meshes_count), + "extracting meshes"); + const auto& mesh = data->meshes[mi]; + Mesh cooked; + cooked.name = safe_name(mesh.name); + cooked.id = identify("mesh", mesh.extras, std::to_string(mi) + ":" + cooked.name); + for (std::size_t pi = 0; pi < mesh.primitives_count; ++pi) { + const auto& primitive = mesh.primitives[pi]; + if (primitive.type != cgltf_primitive_type_triangles || + primitive.has_draco_mesh_compression) + throw std::runtime_error( + "Only uncompressed triangle primitives are supported"); + const cgltf_accessor *positions = nullptr, *normals = nullptr, *uv = nullptr; + for (std::size_t ai = 0; ai < primitive.attributes_count; ++ai) { + const auto& a = primitive.attributes[ai]; + if (a.type == cgltf_attribute_type_position) + positions = a.data; + if (a.type == cgltf_attribute_type_normal) + normals = a.data; + if (a.type == cgltf_attribute_type_texcoord && a.index == 0) + uv = a.data; + } + const auto xyz = unpack(positions, 3); + const auto normal = normals ? unpack(normals, 3) : std::vector{}; + const auto tex = uv ? unpack(uv, 2) : std::vector{}; + const auto count = xyz.size() / 3; + if ((normals && normal.size() != count * 3) || (uv && tex.size() != count * 2)) + throw std::runtime_error("Vertex attribute counts differ"); + Primitive output; + output.material = primitive.material + ? static_cast(primitive.material - data->materials) + : -1; + output.vertices.resize(count); + for (std::size_t i = 0; i < count; ++i) { + if (i % 4096 == 0 && job.cancelled()) + throw Cancelled{}; + std::copy_n(xyz.data() + i * 3, 3, output.vertices[i].position.begin()); + if (normals) + std::copy_n(normal.data() + i * 3, 3, + output.vertices[i].normal.begin()); + if (uv) + std::copy_n(tex.data() + i * 2, 2, output.vertices[i].uv.begin()); + } + if (primitive.indices && + (primitive.indices->is_sparse || + primitive.indices->type != cgltf_type_scalar || + (primitive.indices->component_type != cgltf_component_type_r_8u && + primitive.indices->component_type != cgltf_component_type_r_16u && + primitive.indices->component_type != cgltf_component_type_r_32u))) + throw std::runtime_error( + "Indices require a dense unsigned integer accessor"); + const auto index_count = primitive.indices ? primitive.indices->count : count; + if (index_count % 3 || index_count > 30000000) + throw std::runtime_error("Invalid triangle index count"); + output.indices.resize(index_count); + for (std::size_t i = 0; i < index_count; ++i) { + if (i % 4096 == 0 && job.cancelled()) + throw Cancelled{}; + const auto index = + primitive.indices ? cgltf_accessor_read_index(primitive.indices, i) : i; + if (index >= count) + throw std::runtime_error("Index outside vertex array"); + output.indices[i] = static_cast(index); + } + if (!normals) + calculate_normals(output); + cooked.primitives.push_back(std::move(output)); + if (primitive.targets_count) + result.diagnostics.push_back( + "Morph targets imported as static base geometry"); + } + asset.meshes.push_back(std::move(cooked)); + } + for (std::size_t ni = 0; ni < data->nodes_count; ++ni) { + const auto& node = data->nodes[ni]; + Node output; + output.name = safe_name(node.name); + output.stable_source_id = !source_id(node.extras).empty(); + output.id = identify("node", node.extras, std::to_string(ni) + ":" + output.name); + output.mesh = node.mesh ? static_cast(node.mesh - data->meshes) : -1; + cgltf_node_transform_local(&node, output.local_transform.data()); + if (!std::all_of(output.local_transform.begin(), output.local_transform.end(), + [](float v) { return std::isfinite(v); })) + throw std::runtime_error("Non-finite node transform"); + asset.nodes.push_back(std::move(output)); + if (node.skin) + result.diagnostics.push_back( + "Skinned node imported in static rest pose; animation playback " + "is not cooked"); + } + for (std::size_t ni = 0; ni < data->nodes_count; ++ni) + if (data->nodes[ni].parent) + asset.nodes[ni].parent_id = + asset.nodes[static_cast(data->nodes[ni].parent - data->nodes)] + .id; + // Only instantiate the selected/default scene. Unused resources remain + // reusable outputs. + if (data->scenes_count) { + const auto* selected = data->scene ? data->scene : &data->scenes[0]; + std::set active_nodes; + std::function visit = [&](const cgltf_node* n) { + auto index = static_cast(n - data->nodes); + if (!active_nodes.insert(index).second) + return; + for (std::size_t i = 0; i < n->children_count; ++i) + visit(n->children[i]); + }; + for (std::size_t i = 0; i < selected->nodes_count; ++i) + visit(selected->nodes[i]); + std::vector active; + for (std::size_t i = 0; i < asset.nodes.size(); ++i) + if (active_nodes.contains(i)) + active.push_back(std::move(asset.nodes[i])); + asset.nodes = std::move(active); + } + checkpoint(job, .5f, "extracting materials and textures"); + for (std::size_t mi = 0; mi < data->materials_count; ++mi) { + const auto& m = data->materials[mi]; + Material out; + out.name = safe_name(m.name); + out.id = identify("material", m.extras, std::to_string(mi) + ":" + out.name); + if (m.has_pbr_metallic_roughness) { + const auto& p = m.pbr_metallic_roughness; + std::copy_n(p.base_color_factor, 4, out.base_color.begin()); + out.metallic = p.metallic_factor; + out.roughness = p.roughness_factor; + out.base_color_texture = texture_index(p.base_color_texture, *data); + out.metallic_roughness_texture = + texture_index(p.metallic_roughness_texture, *data); + } + std::copy_n(m.emissive_factor, 3, out.emissive.begin()); + out.alpha_mode = m.alpha_mode == cgltf_alpha_mode_blend ? "BLEND" + : m.alpha_mode == cgltf_alpha_mode_mask ? "MASK" + : "OPAQUE"; + out.alpha_cutoff = m.alpha_cutoff; + out.double_sided = m.double_sided; + out.unlit = m.unlit; + out.normal_texture = texture_index(m.normal_texture, *data); + out.occlusion_texture = texture_index(m.occlusion_texture, *data); + out.emissive_texture = texture_index(m.emissive_texture, *data); + asset.materials.push_back(std::move(out)); + } + for (std::size_t ti = 0; ti < data->textures_count; ++ti) { + const auto& texture = data->textures[ti]; + if (!texture.image) + throw std::runtime_error("Texture extension has no supported fallback image"); + Texture out; + out.name = safe_name(texture.name); + out.id = identify("texture", texture.extras, std::to_string(ti) + ":" + out.name); + out.bytes = image_bytes(*texture.image, source, dependencies); + out.mime_type = image_mime(*texture.image, out.bytes); + if (texture.sampler) { + out.wrap_s = texture.sampler->wrap_s; + out.wrap_t = texture.sampler->wrap_t; + out.min_filter = texture.sampler->min_filter; + out.mag_filter = texture.sampler->mag_filter; + } + asset.textures.push_back(std::move(out)); + } } - checkpoint(job,.5f,"extracting materials and textures"); - for(std::size_t mi=0;mimaterials_count;++mi) { - const auto& m=data->materials[mi];Material out;out.name=safe_name(m.name);out.id=identify("material",m.extras,std::to_string(mi)+":"+out.name); - if(m.has_pbr_metallic_roughness){const auto& p=m.pbr_metallic_roughness;std::copy_n(p.base_color_factor,4,out.base_color.begin());out.metallic=p.metallic_factor;out.roughness=p.roughness_factor;out.base_color_texture=texture_index(p.base_color_texture,*data);out.metallic_roughness_texture=texture_index(p.metallic_roughness_texture,*data);} - std::copy_n(m.emissive_factor,3,out.emissive.begin());out.alpha_mode=m.alpha_mode==cgltf_alpha_mode_blend?"BLEND":m.alpha_mode==cgltf_alpha_mode_mask?"MASK":"OPAQUE";out.alpha_cutoff=m.alpha_cutoff;out.double_sided=m.double_sided;out.unlit=m.unlit; - out.normal_texture=texture_index(m.normal_texture,*data);out.occlusion_texture=texture_index(m.occlusion_texture,*data);out.emissive_texture=texture_index(m.emissive_texture,*data);asset.materials.push_back(std::move(out)); + Json key{{"source", source_hash}, + {"settings", settings}, + {"importer", recipe_version}, + {"dependencies", Json::object()}}; + if (source != logical_source) + key["bundle_sha256"] = logical_hash; + for (const auto& [name, item] : dependencies) + key["dependencies"][name] = item.digest; + result.generation = faset::sha256(key.dump()); + asset.generation = result.generation; + Json manifest{{"schema_version", 1}, + {"asset_id", result.asset_id}, + {"generation", result.generation}, + {"source", logical_source.string()}, + {"payload_source", source.string()}, + {"source_sha256", source_hash}, + {"importer", recipe_version}, + {"settings", settings}, + {"input_key", key}, + {"nodes", Json::array()}, + {"meshes", Json::array()}, + {"materials", Json::array()}, + {"textures", Json::array()}, + {"files", Json::array()}, + {"outputs", Json::array()}}; + manifest["kind"] = standalone_image ? "image" : "scene"; + if (standalone_image) + manifest["image"] = image_info; + stage = cache_root_ / "staging" / uuid(); + fs::create_directories(stage); + for (const auto& node : asset.nodes) { + manifest["nodes"].push_back({{"id", node.id}, + {"name", node.name}, + {"parent_id", node.parent_id}, + {"mesh", node.mesh}, + {"local_transform", node.local_transform}, + {"stable_source_id", node.stable_source_id}}); + manifest["outputs"].push_back(node.id); } - for(std::size_t ti=0;titextures_count;++ti) { - const auto& texture=data->textures[ti];if(!texture.image)throw std::runtime_error("Texture extension has no supported fallback image"); - Texture out;out.name=safe_name(texture.name);out.id=identify("texture",texture.extras,std::to_string(ti)+":"+out.name);out.bytes=image_bytes(*texture.image,source,dependencies);out.mime_type=image_mime(*texture.image,out.bytes); - if(texture.sampler){out.wrap_s=texture.sampler->wrap_s;out.wrap_t=texture.sampler->wrap_t;out.min_filter=texture.sampler->min_filter;out.mag_filter=texture.sampler->mag_filter;}asset.textures.push_back(std::move(out)); + for (const auto& mesh : asset.meshes) { + Json m{{"id", mesh.id}, {"name", mesh.name}, {"primitives", Json::array()}}; + for (std::size_t i = 0; i < mesh.primitives.size(); ++i) { + const auto file = "meshes/" + mesh.id + "-" + std::to_string(i) + ".fmesh"; + add_file(manifest, stage, file, encode_primitive(mesh.primitives[i])); + m["primitives"].push_back( + {{"path", file}, {"material", mesh.primitives[i].material}}); + } + manifest["meshes"].push_back(m); + manifest["outputs"].push_back(mesh.id); } - Json key{{"source",source_hash},{"settings",settings},{"importer",importer_version},{"dependencies",Json::object()}}; - if(source!=logical_source)key["bundle_sha256"]=logical_hash; - for(const auto& [name,item]:dependencies)key["dependencies"][name]=item.digest; - result.generation=faset::sha256(key.dump());asset.generation=result.generation; - Json manifest{{"schema_version",1},{"asset_id",result.asset_id},{"generation",result.generation},{"source",logical_source.string()},{"payload_source",source.string()},{"source_sha256",source_hash},{"importer",importer_version},{"settings",settings},{"input_key",key},{"nodes",Json::array()},{"meshes",Json::array()},{"materials",Json::array()},{"textures",Json::array()},{"files",Json::array()},{"outputs",Json::array()}}; - stage=cache_root_/"staging"/uuid();fs::create_directories(stage); - for(const auto& node:asset.nodes){manifest["nodes"].push_back({{"id",node.id},{"name",node.name},{"parent_id",node.parent_id},{"mesh",node.mesh},{"local_transform",node.local_transform},{"stable_source_id",node.stable_source_id}});manifest["outputs"].push_back(node.id);} - for(const auto& mesh:asset.meshes){Json m{{"id",mesh.id},{"name",mesh.name},{"primitives",Json::array()}};for(std::size_t i=0;i>(); - if(!previous.is_null())for(const auto& old:previous.at("outputs"))if(!published_ids.contains(old.get()))result.removed_output_ids.push_back(old.get()); - result.manifest=manifest; - if(!result.removed_output_ids.empty()&&!request.allow_removed_outputs){result.status=ImportStatus::conflict;result.diagnostics.push_back("Removed or renamed outputs require explicit remap/removal approval; active generation preserved");fs::remove_all(stage);return result;} - if(hash_bytes(read_bytes(source))!=source_hash)throw std::runtime_error("Source changed during import; retry"); - if(source!=logical_source&&hash_bytes(read_bytes(logical_source))!=logical_hash)throw std::runtime_error("Bundle manifest changed during import; retry"); - for(const auto& [name,item]:dependencies)if(hash_bytes(read_bytes(item.path))!=item.digest)throw std::runtime_error("Dependency changed during import: "+name); - write_json(stage/"manifest.json",manifest); - checkpoint(job,.9f,"publishing generation"); - const auto destination=asset_root/"generations"/result.generation;fs::create_directories(destination.parent_path()); - if(fs::exists(destination)){auto existing=read_json(destination/"manifest.json");validate_generation(destination,existing);if(existing.at("input_key")!=key)throw std::runtime_error("Digest collision detected");result.cache_hit=true;fs::remove_all(stage);}else fs::rename(stage,destination); - // Persist identity outside the disposable cache, then atomically publish one pointer. - metadata={{"schema_version",1},{"asset_id",result.asset_id},{"settings",settings}};atomic_json(sidecar,metadata); - if(job.cancelled())throw Cancelled{}; - atomic_json(asset_root/"current.json",{{"schema_version",1},{"generation",result.generation},{"source",logical_source.string()}}); - result.status=ImportStatus::succeeded;job.report(1,"complete"); - } catch(const Cancelled&) {result.status=ImportStatus::cancelled;result.diagnostics.push_back("Import cancelled; active generation unchanged");} - catch(const std::exception& e){result.status=ImportStatus::failed;result.diagnostics.push_back(e.what());} - if(!stage.empty()){std::error_code ec;fs::remove_all(stage,ec);}return result; -} -fs::path AssetPipeline::generation_directory(const std::string& id) const { - valid_id(id);const auto root=cache_root_/"assets"/id;const auto pointer=read_json(root/"current.json");const auto generation=pointer.at("generation").get();valid_id(generation);return root/"generations"/generation; -} -Json AssetPipeline::current_manifest(const std::string& id) const { - valid_id(id);const auto root=cache_root_/"assets"/id;const auto pointer=read_json(root/"current.json"); - const auto generation=pointer.at("generation").get();valid_id(generation); - auto manifest=read_json(root/"generations"/generation/"manifest.json"); - // One pointer snapshot prevents mixing two concurrently published generations. - manifest["source"]=pointer.at("source");return manifest; -} -CookedAsset AssetPipeline::load_asset(const std::string& id) const { - const auto directory=generation_directory(id);const auto m=read_json(directory/"manifest.json");validate_generation(directory,m); - CookedAsset asset;asset.asset_id=m.at("asset_id");asset.generation=m.at("generation"); - for(const auto& n:m.at("nodes")){Node node;node.id=n.at("id");node.name=n.at("name");node.parent_id=n.at("parent_id");node.mesh=n.at("mesh");node.local_transform=n.at("local_transform").get>();node.stable_source_id=n.at("stable_source_id");asset.nodes.push_back(std::move(node));} - for(const auto& j:m.at("meshes")){Mesh mesh;mesh.id=j.at("id");mesh.name=j.at("name");for(const auto& primitive:j.at("primitives"))mesh.primitives.push_back(decode_primitive(read_bytes(directory/primitive.at("path").get()),primitive.at("material")));asset.meshes.push_back(std::move(mesh));} - for(const auto& j:m.at("materials")){Material material;material.id=j.at("id");material.name=j.at("name");material.base_color=j.at("base_color").get>();material.emissive=j.at("emissive").get>();material.metallic=j.at("metallic");material.roughness=j.at("roughness");material.alpha_mode=j.at("alpha_mode");material.alpha_cutoff=j.at("alpha_cutoff");material.double_sided=j.at("double_sided");material.unlit=j.at("unlit");material.base_color_texture=j.at("base_color_texture");material.metallic_roughness_texture=j.at("metallic_roughness_texture");material.normal_texture=j.at("normal_texture");material.occlusion_texture=j.at("occlusion_texture");material.emissive_texture=j.at("emissive_texture");asset.materials.push_back(std::move(material));} - for(const auto& j:m.at("textures")){Texture texture;texture.id=j.at("id");texture.name=j.at("name");texture.mime_type=j.at("mime_type");texture.bytes=read_bytes(directory/j.at("path").get());texture.wrap_s=j.at("wrap_s");texture.wrap_t=j.at("wrap_t");texture.min_filter=j.at("min_filter");texture.mag_filter=j.at("mag_filter");asset.textures.push_back(std::move(texture));}return asset; + for (const auto& material : asset.materials) { + manifest["materials"].push_back(material_json(material)); + manifest["outputs"].push_back(material.id); + } + for (const auto& texture : asset.textures) { + const auto file = "textures/" + texture.id + ".image"; + add_file(manifest, stage, file, texture.bytes); + manifest["textures"].push_back({{"id", texture.id}, + {"name", texture.name}, + {"mime_type", texture.mime_type}, + {"path", file}, + {"wrap_s", texture.wrap_s}, + {"wrap_t", texture.wrap_t}, + {"min_filter", texture.min_filter}, + {"mag_filter", texture.mag_filter}}); + manifest["outputs"].push_back(texture.id); + } + checkpoint(job, .75f, "validating candidate generation"); + validate_generation(stage, manifest); + const auto published_ids = manifest.at("outputs").get>(); + if (!previous.is_null()) + for (const auto& old : previous.at("outputs")) + if (!published_ids.contains(old.get())) + result.removed_output_ids.push_back(old.get()); + result.manifest = manifest; + if (!result.removed_output_ids.empty() && !request.allow_removed_outputs) { + result.status = ImportStatus::conflict; + result.diagnostics.push_back( + "Removed or renamed outputs require explicit remap/removal approval; " + "active generation preserved"); + fs::remove_all(stage); + return result; + } + if (hash_bytes(read_bytes(source)) != source_hash) + throw std::runtime_error("Source changed during import; retry"); + if (source != logical_source && hash_bytes(read_bytes(logical_source)) != logical_hash) + throw std::runtime_error("Bundle manifest changed during import; retry"); + for (const auto& [name, item] : dependencies) + if (hash_bytes(read_bytes(item.path)) != item.digest) + throw std::runtime_error("Dependency changed during import: " + name); + write_json(stage / "manifest.json", manifest); + checkpoint(job, .9f, "publishing generation"); + const auto destination = asset_root / "generations" / result.generation; + fs::create_directories(destination.parent_path()); + if (fs::exists(destination)) { + auto existing = read_json(destination / "manifest.json"); + validate_generation(destination, existing); + if (existing.at("input_key") != key) + throw std::runtime_error("Digest collision detected"); + result.cache_hit = true; + fs::remove_all(stage); + } else + fs::rename(stage, destination); + // Persist identity outside the disposable cache, then atomically publish + // one pointer. + metadata = {{"schema_version", 1}, {"asset_id", result.asset_id}, {"settings", settings}}; + atomic_json(sidecar, metadata); + if (job.cancelled()) + throw Cancelled{}; + atomic_json(asset_root / "current.json", {{"schema_version", 1}, + {"generation", result.generation}, + {"source", logical_source.string()}}); + result.status = ImportStatus::succeeded; + job.report(1, "complete"); + } catch (const Cancelled&) { + result.status = ImportStatus::cancelled; + result.diagnostics.push_back("Import cancelled; active generation unchanged"); + } catch (const std::exception& e) { + result.status = ImportStatus::failed; + result.diagnostics.push_back(e.what()); + } + if (!stage.empty()) { + std::error_code ec; + fs::remove_all(stage, ec); + } + return result; } Json AssetPipeline::overrides(const std::string& id) const { - const auto source=current_manifest(id).at("source").get();const auto path=fs::path(source+".faset-overrides.json");return fs::exists(path)?read_json(path):Json::object(); + const auto source = current_manifest(id).at("source").get(); + const auto path = fs::path(source + ".faset-overrides.json"); + return fs::exists(path) ? read_json(path) : Json::object(); } -void AssetPipeline::set_overrides(const std::string& id,const Json& values) { - if(!values.is_object())throw std::runtime_error("Overrides must be an object keyed by stable output IDs");std::lock_guard lock(writer_mutex); - atomic_json(fs::path(current_manifest(id).at("source").get()+".faset-overrides.json"),values); +void AssetPipeline::set_overrides(const std::string& id, const Json& values) { + if (!values.is_object()) + throw std::runtime_error("Overrides must be an object keyed by stable output IDs"); + std::lock_guard lock(writer_mutex); + atomic_json( + fs::path(current_manifest(id).at("source").get() + ".faset-overrides.json"), + values); } } // namespace faset::assets diff --git a/src/authoring/schema.cpp b/src/authoring/schema.cpp index 5870cea..057e53f 100644 --- a/src/authoring/schema.cpp +++ b/src/authoring/schema.cpp @@ -1,120 +1,207 @@ -#include #include #include +#include #include namespace faset::authoring { -void validate_field(const Json& value,const Json& descriptor) { - const auto kind=descriptor.value("type",std::string("any")); - bool valid=true; - if(kind=="number"||kind=="float") valid=value.is_number()&&std::isfinite(value.get()); - else if(kind=="integer"||kind=="int") valid=value.is_number_integer(); - else if(kind=="boolean"||kind=="bool") valid=value.is_boolean(); - else if(kind=="string"||kind=="asset_ref"||kind=="entity_ref") valid=value.is_string(); - else if(kind=="vec2"||kind=="vec3"||kind=="vec4"||kind=="color") { - const auto size=kind=="vec2"?2u:(kind=="vec3"?3u:4u); - valid=value.is_array()&&value.size()==size; - if(valid) for(const auto& entry:value) valid=valid&&entry.is_number()&&std::isfinite(entry.get()); - } else if(kind=="array") valid=value.is_array(); - else if(kind=="object") valid=value.is_object(); - else require(kind=="any","schema.field_type","Unsupported schema field type: "+kind); - require(valid,"validation.field_type","Invalid value for field "+descriptor.value("id",std::string("?"))+" (expected "+kind+")"); - if(value.is_number()) { - if(descriptor.contains("min")) require(value.get()>=descriptor["min"].get(),"validation.minimum","Field is below its minimum"); - if(descriptor.contains("max")) require(value.get()<=descriptor["max"].get(),"validation.maximum","Field exceeds its maximum"); +void validate_field(const Json& value, const Json& descriptor) { + const auto kind = descriptor.value("type", std::string("any")); + bool valid = true; + if (kind == "number" || kind == "float") + valid = value.is_number() && std::isfinite(value.get()); + else if (kind == "integer" || kind == "int") + valid = value.is_number_integer(); + else if (kind == "boolean" || kind == "bool") + valid = value.is_boolean(); + else if (kind == "string" || kind == "asset_ref" || kind == "entity_ref") + valid = value.is_string(); + else if (kind == "vec2" || kind == "vec3" || kind == "vec4" || kind == "color") { + const auto size = kind == "vec2" ? 2u : (kind == "vec3" ? 3u : 4u); + valid = value.is_array() && value.size() == size; + if (valid) + for (const auto& entry : value) + valid = valid && entry.is_number() && std::isfinite(entry.get()); + } else if (kind == "array") + valid = value.is_array(); + else if (kind == "object") + valid = value.is_object(); + else + require(kind == "any", "schema.field_type", "Unsupported schema field type: " + kind); + require(valid, "validation.field_type", + "Invalid value for field " + descriptor.value("id", std::string("?")) + " (expected " + + kind + ")"); + if (value.is_number()) { + if (descriptor.contains("min")) + require(value.get() >= descriptor["min"].get(), "validation.minimum", + "Field is below its minimum"); + if (descriptor.contains("max")) + require(value.get() <= descriptor["max"].get(), "validation.maximum", + "Field exceeds its maximum"); } - if(descriptor.contains("enum")) { - bool found=false;for(const auto& option:descriptor["enum"])found=found||option==value; - require(found,"validation.enum","Field value is not an allowed choice"); + if (descriptor.contains("enum")) { + bool found = false; + for (const auto& option : descriptor["enum"]) + found = found || option == value; + require(found, "validation.enum", "Field value is not an allowed choice"); } } void SchemaRegistry::register_schema(const Json& value) { - require(value.is_object()&&value.contains("id")&&value["id"].is_string()&&value.contains("fields")&&value["fields"].is_object(),"schema.invalid","Invalid component schema"); - Json normalized=value; - const auto id=value.at("id").get(); - require(!id.empty(),"schema.invalid","TypeId cannot be empty"); - require(value.value("version",1)>0,"schema.invalid","Schema version must be positive"); - for(auto& [key,field]:normalized["fields"].items()) { - require(field.is_object()&&field.contains("default"),"schema.invalid","Each field requires a typed default"); - require(field.value("id",key)==key,"schema.field_id","Field map keys must be stable FieldIds"); - field["id"]=key;validate_field(field["default"],field); + require(value.is_object() && value.contains("id") && value["id"].is_string() && + value.contains("fields") && value["fields"].is_object(), + "schema.invalid", "Invalid component schema"); + Json normalized = value; + const auto id = value.at("id").get(); + require(!id.empty(), "schema.invalid", "TypeId cannot be empty"); + require(value.value("version", 1) > 0, "schema.invalid", "Schema version must be positive"); + for (auto& [key, field] : normalized["fields"].items()) { + require(field.is_object() && field.contains("default"), "schema.invalid", + "Each field requires a typed default"); + require(field.value("id", key) == key, "schema.field_id", + "Field map keys must be stable FieldIds"); + field["id"] = key; + validate_field(field["default"], field); } - if(auto found=schemas_.find(id);found!=schemas_.end()) require(found->second==normalized,"schema.duplicate_type","A different schema is already registered for "+id); - schemas_[id]=std::move(normalized); + if (auto found = schemas_.find(id); found != schemas_.end()) + require(found->second == normalized, "schema.duplicate_type", + "A different schema is already registered for " + id); + schemas_[id] = std::move(normalized); } void SchemaRegistry::register_schemas(const Json& values) { - const auto& array=values.is_array()?values:values.at("types"); - auto candidate=*this;for(const auto& schema:array)candidate.register_schema(schema);*this=std::move(candidate); + const auto& array = values.is_array() ? values : values.at("types"); + auto candidate = *this; + for (const auto& schema : array) + candidate.register_schema(schema); + *this = std::move(candidate); } -bool SchemaRegistry::contains(const std::string& type)const{return schemas_.contains(type);} -Json SchemaRegistry::schema(const std::string& type)const { - const auto found=schemas_.find(type);require(found!=schemas_.end(),"schema.missing","Component schema unavailable: "+type);return found->second; +bool SchemaRegistry::contains(const std::string& type) const { + return schemas_.contains(type); } -Json SchemaRegistry::manifest()const {Json types=Json::array();for(const auto& [id,type]:schemas_)types.push_back(type);return {{"format","faset.schema"},{"version",1},{"types",types}};} -Json SchemaRegistry::default_fields(const std::string& type)const {Json fields=Json::object();const auto metadata=schema(type);for(const auto& [id,field]:metadata["fields"].items())fields[id]=field["default"];return fields;} -void SchemaRegistry::validate_component(const Json& component)const { - require(component.is_object()&&component.contains("type")&&component["type"].is_string()&&component.contains("fields")&&component["fields"].is_object(),"component.invalid","Invalid component record"); - const auto type=component.at("type").get(); - if(!contains(type))return; - const auto metadata=schema(type); +Json SchemaRegistry::schema(const std::string& type) const { + const auto found = schemas_.find(type); + require(found != schemas_.end(), "schema.missing", "Component schema unavailable: " + type); + return found->second; +} +Json SchemaRegistry::manifest() const { + Json types = Json::array(); + for (const auto& [id, type] : schemas_) + types.push_back(type); + return {{"format", "faset.schema"}, {"version", 1}, {"types", types}}; +} +Json SchemaRegistry::default_fields(const std::string& type) const { + Json fields = Json::object(); + const auto metadata = schema(type); + for (const auto& [id, field] : metadata["fields"].items()) + fields[id] = field["default"]; + return fields; +} +void SchemaRegistry::validate_component(const Json& component) const { + require(component.is_object() && component.contains("type") && component["type"].is_string() && + component.contains("fields") && component["fields"].is_object(), + "component.invalid", "Invalid component record"); + const auto type = component.at("type").get(); + if (!contains(type)) + return; + const auto metadata = schema(type); // Future or missing-module schemas are preserved, not interpreted with the wrong version. - if(component.value("version",1)!=metadata.value("version",1))return; - for(const auto& [id,value]:component["fields"].items())if(metadata["fields"].contains(id))validate_field(value,metadata["fields"][id]); + if (component.value("version", 1) != metadata.value("version", 1)) + return; + for (const auto& [id, value] : component["fields"].items()) + if (metadata["fields"].contains(id)) + validate_field(value, metadata["fields"][id]); } -void SchemaRegistry::add_migration(const std::string& type,int from_version,Json rules) { - require(from_version>0&&rules.is_object(),"migration.invalid","Invalid migration"); - require(!migrations_.contains({type,from_version}),"migration.duplicate","Migration already exists"); - migrations_[{type,from_version}]=std::move(rules); +void SchemaRegistry::add_migration(const std::string& type, int from_version, Json rules) { + require(from_version > 0 && rules.is_object(), "migration.invalid", "Invalid migration"); + require(!migrations_.contains({type, from_version}), "migration.duplicate", + "Migration already exists"); + migrations_[{type, from_version}] = std::move(rules); } -Json SchemaRegistry::migrate_component(const Json& source)const { - Json result=source;const auto type=result.at("type").get(); - if(!contains(type))return result; - const auto current=schema(type).value("version",1); - auto version=result.value("version",1); - if(version>current)return result; - while(versionsecond.items()) { - if(rule.contains("default")&&!result["fields"].contains(field))result["fields"][field]=rule["default"]; - if(rule.contains("scale")&&result["fields"].contains(field)) { - require(result["fields"][field].is_number(),"migration.type","Cannot scale a nonnumeric field"); - result["fields"][field]=result["fields"][field].get()*rule["scale"].get(); +Json SchemaRegistry::migrate_component(const Json& source) const { + Json result = source; + const auto type = result.at("type").get(); + if (!contains(type)) + return result; + const auto current = schema(type).value("version", 1); + auto version = result.value("version", 1); + if (version > current) + return result; + while (version < current) { + const auto found = migrations_.find({type, version}); + require(found != migrations_.end(), "migration.required", + "Explicit migration required for " + type); + for (const auto& [field, rule] : found->second.items()) { + if (rule.contains("default") && !result["fields"].contains(field)) + result["fields"][field] = rule["default"]; + if (rule.contains("scale") && result["fields"].contains(field)) { + require(result["fields"][field].is_number(), "migration.type", + "Cannot scale a nonnumeric field"); + result["fields"][field] = + result["fields"][field].get() * rule["scale"].get(); } - if(rule.value("require_manual",false)&&result["fields"].contains(field))throw Error("migration.manual","Field requires explicit manual migration",{{"type",type},{"field",field}}); + if (rule.value("require_manual", false) && result["fields"].contains(field)) + throw Error("migration.manual", "Field requires explicit manual migration", + {{"type", type}, {"field", field}}); } - result["version"]=++version; + result["version"] = ++version; } - const auto metadata=schema(type); - for(const auto& [field,descriptor]:metadata["fields"].items())if(!result["fields"].contains(field))result["fields"][field]=descriptor["default"]; - validate_component(result);return result; + const auto metadata = schema(type); + for (const auto& [field, descriptor] : metadata["fields"].items()) + if (!result["fields"].contains(field)) + result["fields"][field] = descriptor["default"]; + validate_component(result); + return result; } SchemaRegistry builtin_schemas() { SchemaRegistry registry; - struct Transform {std::array position,rotation,scale;}; - TypeRegistration(registry,"faset.transform","Transform") - .field("position","Position",&Transform::position,std::array{0,0,0},"vec3") - .field("rotation","Rotation",&Transform::rotation,std::array{0,0,0},"vec3",{{"unit","radians"}}) - .field("scale","Scale",&Transform::scale,std::array{1,1,1},"vec3").commit(); - auto add=[&](std::string id,std::string name,Json fields){registry.register_schema({{"id",id},{"name",name},{"version",1},{"fields",fields}});}; - auto field=[](std::string type,Json value){return Json{{"type",type},{"default",value}};}; - add("faset.sprite","Sprite",{{"color",field("color",{0.65,0.6,0.85,1.0})},{"size",field("vec2",{1,1})},{"texture",field("asset_ref","")},{"layer",field("integer",0)}}); - add("faset.mesh","Mesh",{{"asset",field("asset_ref","")},{"color",field("color",{0.65,0.65,0.68,1.0})},{"primitive",Json{{"type","string"},{"default","cube"},{"enum",{"cube","plane","asset"}}}}}); - add("faset.camera","Camera",{{"fov",Json{{"type","number"},{"default",60.0},{"min",1.0},{"max",179.0}}},{"near",Json{{"type","number"},{"default",0.1},{"min",0.001}}},{"far",Json{{"type","number"},{"default",1000.0},{"min",0.01}}}}); - add("faset.light","Directional Light",{{"color",field("color",{1,1,1,1})},{"intensity",Json{{"type","number"},{"default",1.0},{"min",0.0}}}}); - for(int dimension:{2,3}) { - Json vector=dimension==2?Json{0,0}:Json{0,0,0};Json extents=dimension==2?Json{0.5,0.5}:Json{0.5,0.5,0.5}; - add("faset.rigid_body_"+std::to_string(dimension)+"d","Rigid Body "+std::to_string(dimension)+"D",{ - {"body_type",Json{{"type","string"},{"default","dynamic"},{"enum",{"static","dynamic","kinematic"}}}}, - {"half_extents",field(dimension==2?"vec2":"vec3",extents)}, - {"linear_velocity",field(dimension==2?"vec2":"vec3",vector)}, - {"density",Json{{"type","number"},{"default",1.0},{"min",0.001}}}, - {"friction",Json{{"type","number"},{"default",0.5},{"min",0.0}}}, - {"restitution",Json{{"type","number"},{"default",0.0},{"min",0.0},{"max",1.0}}}, - {"gravity_scale",field("number",1.0)}, - {"category_bits",Json{{"type","integer"},{"default",1},{"min",0}}}, - {"mask_bits",Json{{"type","integer"},{"default",65535},{"min",0}}}}); + struct Transform { + std::array position, rotation, scale; + }; + TypeRegistration(registry, "faset.transform", "Transform") + .field("position", "Position", &Transform::position, std::array{0, 0, 0}, "vec3") + .field("rotation", "Rotation", &Transform::rotation, std::array{0, 0, 0}, "vec3", + {{"unit", "radians"}}) + .field("scale", "Scale", &Transform::scale, std::array{1, 1, 1}, "vec3") + .commit(); + auto add = [&](std::string id, std::string name, Json fields) { + registry.register_schema({{"id", id}, {"name", name}, {"version", 1}, {"fields", fields}}); + }; + auto field = [](std::string type, Json value) { + return Json{{"type", type}, {"default", value}}; + }; + add("faset.sprite", "Sprite", + {{"color", field("color", {0.65, 0.6, 0.85, 1.0})}, + {"size", field("vec2", {1, 1})}, + {"texture", field("asset_ref", "")}, + {"layer", field("integer", 0)}}); + add("faset.mesh", "Mesh", + {{"asset", field("asset_ref", "")}, + {"color", field("color", {0.65, 0.65, 0.68, 1.0})}, + {"primitive", + Json{{"type", "string"}, {"default", "cube"}, {"enum", {"cube", "plane", "asset"}}}}}); + add("faset.camera", "Camera", + {{"fov", Json{{"type", "number"}, {"default", 60.0}, {"min", 1.0}, {"max", 179.0}}}, + {"near", Json{{"type", "number"}, {"default", 0.1}, {"min", 0.001}}}, + {"far", Json{{"type", "number"}, {"default", 1000.0}, {"min", 0.01}}}}); + add("faset.light", "Directional Light", + {{"color", field("color", {1, 1, 1, 1})}, + {"intensity", Json{{"type", "number"}, {"default", 1.0}, {"min", 0.0}}}}); + for (int dimension : {2, 3}) { + Json vector = dimension == 2 ? Json{0, 0} : Json{0, 0, 0}; + Json extents = dimension == 2 ? Json{0.5, 0.5} : Json{0.5, 0.5, 0.5}; + add("faset.rigid_body_" + std::to_string(dimension) + "d", + "Rigid Body " + std::to_string(dimension) + "D", + {{"body_type", Json{{"type", "string"}, + {"default", "dynamic"}, + {"enum", {"static", "dynamic", "kinematic"}}}}, + {"half_extents", field(dimension == 2 ? "vec2" : "vec3", extents)}, + {"linear_velocity", field(dimension == 2 ? "vec2" : "vec3", vector)}, + {"density", Json{{"type", "number"}, {"default", 1.0}, {"min", 0.001}}}, + {"friction", Json{{"type", "number"}, {"default", 0.5}, {"min", 0.0}}}, + {"restitution", + Json{{"type", "number"}, {"default", 0.0}, {"min", 0.0}, {"max", 1.0}}}, + {"gravity_scale", field("number", 1.0)}, + {"category_bits", Json{{"type", "integer"}, {"default", 1}, {"min", 0}}}, + {"mask_bits", Json{{"type", "integer"}, {"default", 65535}, {"min", 0}}}}); } return registry; } -} +} // namespace faset::authoring diff --git a/src/authoring/service.cpp b/src/authoring/service.cpp index 6f4b7fb..4688b71 100644 --- a/src/authoring/service.cpp +++ b/src/authoring/service.cpp @@ -1,201 +1,511 @@ -#include -#include -#include #include #include +#include +#include +#include +#include #include namespace faset::authoring { namespace { -Json& entity(Json& scene,const std::string& id) { - for(auto& item:scene["entities"])if(item.at("id")==id)return item; - throw Error("entity.missing","Entity does not exist",{{"entity",id}}); +Json& entity(Json& scene, const std::string& id) { + for (auto& item : scene["entities"]) + if (item.at("id") == id) + return item; + throw Error("entity.missing", "Entity does not exist", {{"entity", id}}); } -Json& component(Json& item,const std::string& id) { - for(auto& value:item["components"])if(value.at("id")==id)return value; - throw Error("component.missing","Component does not exist",{{"component",id}}); +Json& component(Json& item, const std::string& id) { + for (auto& value : item["components"]) + if (value.at("id") == id) + return value; + throw Error("component.missing", "Component does not exist", {{"component", id}}); } -std::string parent_id(const Json& item) {return item.contains("parent")&&!item["parent"].is_null()?item["parent"].get():"";} -void check_revision(std::uint64_t current,std::uint64_t expected) { - if(current!=expected)throw Error("revision.conflict","Document changed since it was read",{{"expected",expected},{"current",current}}); +std::string parent_id(const Json& item) { + return item.contains("parent") && !item["parent"].is_null() ? item["parent"].get() + : ""; +} +void check_revision(std::uint64_t current, std::uint64_t expected) { + if (current != expected) + throw Error("revision.conflict", "Document changed since it was read", + {{"expected", expected}, {"current", current}}); } bool finite_json(const Json& value) { - if(value.is_number_float())return std::isfinite(value.get()); - if(value.is_structured())for(const auto& child:value)if(!finite_json(child))return false; + if (value.is_number_float()) + return std::isfinite(value.get()); + if (value.is_structured()) + for (const auto& child : value) + if (!finite_json(child)) + return false; return true; } +bool valid_id(const Json& value) { + if (!value.is_string()) + return false; + const auto& text = value.get_ref(); + return !text.empty() && text.size() <= 128 && + text.find_first_not_of( + "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_.:") == + std::string::npos; } -Json make_scene(std::string name,int dimension) { - require(dimension==2||dimension==3,"scene.dimension","Scene dimension must be 2 or 3"); - return {{"format","faset.scene"},{"version",1},{"id",new_id()},{"name",std::move(name)},{"dimension",dimension},{"entities",Json::array()},{"instances",Json::array()}}; +} // namespace +Json make_scene(std::string name, int dimension) { + require(dimension == 2 || dimension == 3, "scene.dimension", "Scene dimension must be 2 or 3"); + return {{"format", "faset.scene"}, {"version", 1}, {"id", new_id()}, + {"name", std::move(name)}, {"dimension", dimension}, {"entities", Json::array()}, + {"instances", Json::array()}}; } -Json make_entity(const SchemaRegistry& schemas,std::string name,const std::string& parent) { - Json transform={{"id",new_id()},{"type","faset.transform"},{"version",1},{"fields",schemas.default_fields("faset.transform")}}; - return {{"id",new_id()},{"name",std::move(name)},{"parent",parent.empty()?Json(nullptr):Json(parent)},{"components",Json::array({transform})}}; +Json make_entity(const SchemaRegistry& schemas, std::string name, const std::string& parent) { + Json transform = {{"id", new_id()}, + {"type", "faset.transform"}, + {"version", 1}, + {"fields", schemas.default_fields("faset.transform")}}; + return {{"id", new_id()}, + {"name", std::move(name)}, + {"parent", parent.empty() ? Json(nullptr) : Json(parent)}, + {"components", Json::array({transform})}}; } -void validate_scene(const Json& scene,const SchemaRegistry& schemas) { - require(scene.is_object()&&scene.value("format",std::string())=="faset.scene","scene.format","Expected a Faset scene"); - require(scene.value("version",0)==1,"scene.version","Unsupported scene format version"); - require(scene.contains("id")&&scene["id"].is_string()&&!scene["id"].get().empty(),"scene.id","Scene requires a stable ID"); - require(scene.contains("name")&&scene["name"].is_string(),"scene.name","Scene name must be text"); - require(scene.value("dimension",0)==2||scene.value("dimension",0)==3,"scene.dimension","Scene dimension must be 2 or 3"); - require(scene.contains("entities")&&scene["entities"].is_array(),"scene.entities","Scene entities must be an array"); - require(finite_json(scene),"validation.finite","Scene contains a non-finite number"); - std::set ids;std::map parents; - auto insert_id=[&](const Json& value) {require(value.is_string()&&!value.get().empty(),"id.invalid","ID must be nonempty text");require(ids.insert(value.get()).second,"id.duplicate","Duplicate document ID");}; - for(const auto& item:scene["entities"]) { - require(item.is_object()&&item.contains("id")&&item.contains("name")&&item["name"].is_string(),"entity.invalid","Invalid entity record"); - insert_id(item["id"]);parents[item["id"].get()]=parent_id(item); - require(item.contains("components")&&item["components"].is_array(),"entity.components","Entity components must be an array"); +void validate_scene(const Json& scene, const SchemaRegistry& schemas) { + require(scene.is_object() && scene.value("format", std::string()) == "faset.scene", + "scene.format", "Expected a Faset scene"); + require(scene.value("version", 0) == 1, "scene.version", "Unsupported scene format version"); + require(scene.contains("id") && valid_id(scene["id"]), "scene.id", + "Scene requires a safe stable ID"); + require(scene.contains("name") && scene["name"].is_string(), "scene.name", + "Scene name must be text"); + require(scene.value("dimension", 0) == 2 || scene.value("dimension", 0) == 3, "scene.dimension", + "Scene dimension must be 2 or 3"); + require(scene.contains("entities") && scene["entities"].is_array(), "scene.entities", + "Scene entities must be an array"); + require(finite_json(scene), "validation.finite", "Scene contains a non-finite number"); + std::set ids; + std::map parents; + auto insert_id = [&](const Json& value) { + require(valid_id(value), "id.invalid", + "ID must contain at most 128 ASCII identifier characters"); + require(ids.insert(value.get()).second, "id.duplicate", + "Duplicate document ID"); + }; + for (const auto& item : scene["entities"]) { + require(item.is_object() && item.contains("id") && item.contains("name") && + item["name"].is_string(), + "entity.invalid", "Invalid entity record"); + insert_id(item["id"]); + parents[item["id"].get()] = parent_id(item); + require(item.contains("components") && item["components"].is_array(), "entity.components", + "Entity components must be an array"); std::set types; - for(const auto& value:item["components"]) { - require(value.contains("id"),"component.id","Component requires stable ID");insert_id(value["id"]);schemas.validate_component(value); - require(types.insert(value.at("type").get()).second,"component.duplicate_type","One component of each type is supported per entity"); + for (const auto& value : item["components"]) { + require(value.contains("id"), "component.id", "Component requires stable ID"); + insert_id(value["id"]); + schemas.validate_component(value); + require(types.insert(value.at("type").get()).second, + "component.duplicate_type", + "One component of each type is supported per entity"); } } - for(const auto& [id,parent]:parents) { - std::set visited{id};auto current=parent; - while(!current.empty()) {require(parents.contains(current),"entity.parent_missing","Parent entity is missing");require(visited.insert(current).second,"entity.cycle","Hierarchy contains a cycle");current=parents.at(current);} + for (const auto& [id, parent] : parents) { + std::set visited{id}; + auto current = parent; + while (!current.empty()) { + require(parents.contains(current), "entity.parent_missing", "Parent entity is missing"); + require(visited.insert(current).second, "entity.cycle", "Hierarchy contains a cycle"); + current = parents.at(current); + } } - if(scene.contains("instances")) { - require(scene["instances"].is_array(),"template.instances","Template instances must be an array"); - for(const auto& instance:scene["instances"]) { - require(instance.contains("id")&&instance.contains("source")&&instance["source"].is_string(),"template.instance","Invalid template instance"); + if (scene.contains("instances")) { + require(scene["instances"].is_array(), "template.instances", + "Template instances must be an array"); + for (const auto& instance : scene["instances"]) { + require(instance.contains("id") && instance.contains("source") && + instance["source"].is_string(), + "template.instance", "Invalid template instance"); insert_id(instance["id"]); } } } -AuthoringService::AuthoringService(std::filesystem::path root,SchemaRegistry schemas):root_(std::filesystem::absolute(std::move(root)).lexically_normal()),schemas_(std::move(schemas)) {std::filesystem::create_directories(root_);} -AuthoringService::State& AuthoringService::state(const std::string& id) {auto found=documents_.find(id);require(found!=documents_.end(),"document.missing","Document is not open");return found->second;} -const AuthoringService::State& AuthoringService::state(const std::string& id)const {auto found=documents_.find(id);require(found!=documents_.end(),"document.missing","Document is not open");return found->second;} -Json AuthoringService::summary(const State& value,bool include_data)const { - Json result={{"id",value.data.at("id")},{"name",value.data.at("name")},{"revision",value.revision},{"dirty",sha256(value.data.dump())!=value.saved_hash},{"path",value.path.generic_string()},{"can_undo",!value.undo.empty()},{"can_redo",!value.redo.empty()}}; - if(include_data) result["scene"]=value.data; +AuthoringService::AuthoringService(std::filesystem::path root, SchemaRegistry schemas) + : root_(std::filesystem::absolute(std::move(root)).lexically_normal()), + schemas_(std::move(schemas)) { + std::filesystem::create_directories(root_); +} +AuthoringService::State& AuthoringService::state(const std::string& id) { + auto found = documents_.find(id); + require(found != documents_.end(), "document.missing", "Document is not open"); + return found->second; +} +const AuthoringService::State& AuthoringService::state(const std::string& id) const { + auto found = documents_.find(id); + require(found != documents_.end(), "document.missing", "Document is not open"); + return found->second; +} +Json AuthoringService::summary(const State& value, bool include_data) const { + Json result = {{"id", value.data.at("id")}, + {"name", value.data.at("name")}, + {"revision", value.revision}, + {"dirty", sha256(value.data.dump()) != value.saved_hash}, + {"path", value.path.generic_string()}, + {"can_undo", !value.undo.empty()}, + {"can_redo", !value.redo.empty()}}; + if (include_data) + result["scene"] = value.data; return result; } -void AuthoringService::journal(const State& value)const { - atomic_write_json(project_path(root_,std::filesystem::path(".faset/recovery")/(value.data.at("id").get()+".json")),{{"format","faset.recovery"},{"version",1},{"path",value.path.generic_string()},{"revision",value.revision},{"saved_hash",value.saved_hash},{"disk_hash",value.disk_hash},{"scene",value.data}}); +void AuthoringService::journal(const State& value) const { + atomic_write_json(project_path(root_, std::filesystem::path(".faset/recovery") / + (value.data.at("id").get() + ".json")), + {{"format", "faset.recovery"}, + {"version", 1}, + {"path", value.path.generic_string()}, + {"revision", value.revision}, + {"saved_hash", value.saved_hash}, + {"disk_hash", value.disk_hash}, + {"scene", value.data}}); } -Json AuthoringService::create(std::string name,int dimension) { - std::lock_guard lock(mutex_);State value;value.data=make_scene(std::move(name),dimension);journal(value); - const auto id=value.data["id"].get();documents_.emplace(id,std::move(value));return summary(state(id)); +Json AuthoringService::create(std::string name, int dimension) { + std::lock_guard lock(mutex_); + State value; + value.data = make_scene(std::move(name), dimension); + journal(value); + const auto id = value.data["id"].get(); + documents_.emplace(id, std::move(value)); + return summary(state(id)); } -Json AuthoringService::open(const std::filesystem::path& relative,bool recover) { - std::lock_guard lock(mutex_);auto path=project_path(root_,relative);Json data=read_json(path);validate_scene(data,schemas_); - const auto id=data.at("id").get(); - if(documents_.contains(id)) {require(state(id).path==relative.lexically_normal(),"document.id_collision","Another open file has the same document ID");return summary(state(id));} - State value;value.data=data;value.path=relative.lexically_normal();value.saved_hash=sha256(data.dump());value.disk_hash=sha256_file(path); - const auto recovery=project_path(root_,std::filesystem::path(".faset/recovery")/(id+".json")); - if(recover&&std::filesystem::exists(recovery)) { - const auto recovered=read_json(recovery); - require(recovered.value("disk_hash",std::string())==value.disk_hash,"recovery.disk_conflict","Scene file changed since recovery was written"); - validate_scene(recovered.at("scene"),schemas_);value.data=recovered.at("scene");value.revision=recovered.value("revision",0u); +Json AuthoringService::open(const std::filesystem::path& relative, bool recover) { + std::lock_guard lock(mutex_); + auto path = project_path(root_, relative); + Json data = read_json(path); + validate_scene(data, schemas_); + const auto id = data.at("id").get(); + if (documents_.contains(id)) { + require(state(id).path == relative.lexically_normal(), "document.id_collision", + "Another open file has the same document ID"); + return recover ? this->recover(id, state(id).revision) : summary(state(id)); } - for(auto& item:value.data["entities"])for(auto& component:item["components"])component=schemas_.migrate_component(component); - documents_.emplace(id,std::move(value));return summary(state(id)); + State value; + value.data = data; + value.path = relative.lexically_normal(); + value.saved_hash = sha256(data.dump()); + value.disk_hash = sha256_file(path); + const auto recovery = + project_path(root_, std::filesystem::path(".faset/recovery") / (id + ".json")); + if (recover && std::filesystem::exists(recovery)) { + const auto recovered = read_json(recovery); + require(recovered.value("disk_hash", std::string()) == value.disk_hash, + "recovery.disk_conflict", "Scene file changed since recovery was written"); + validate_scene(recovered.at("scene"), schemas_); + require(recovered.at("scene").at("id") == id, "recovery.id", + "Recovery ID does not match its document"); + value.data = recovered.at("scene"); + value.revision = recovered.value("revision", 0u); + } + for (auto& item : value.data["entities"]) + for (auto& component : item["components"]) + component = schemas_.migrate_component(component); + documents_.emplace(id, std::move(value)); + return summary(state(id)); } -Json AuthoringService::query(const std::string& id)const {std::lock_guard lock(mutex_);return summary(state(id));} -Json AuthoringService::documents()const {std::lock_guard lock(mutex_);Json result=Json::array();for(const auto& [id,value]:documents_)result.push_back(summary(value,false));return result;} -void AuthoringService::register_schemas(const Json& manifest) {std::lock_guard lock(mutex_);schemas_.register_schemas(manifest);} -void AuthoringService::apply(Json& scene,const Json& command) { - require(command.is_object()&&command.contains("op")&&command["op"].is_string(),"command.invalid","Command requires an operation name"); - const auto op=command.at("op").get(); - if(op=="entity.create") { - Json value=command.contains("entity")&&command["entity"].is_object()?command["entity"]:make_entity(schemas_,command.value("name",std::string("Object")),command.value("parent",std::string())); - if(!value.contains("id")) value["id"]=new_id(); +Json AuthoringService::query(const std::string& id) const { + std::lock_guard lock(mutex_); + return summary(state(id)); +} +Json AuthoringService::documents() const { + std::lock_guard lock(mutex_); + Json result = Json::array(); + for (const auto& [id, value] : documents_) + result.push_back(summary(value, false)); + return result; +} +void AuthoringService::register_schemas(const Json& manifest) { + std::lock_guard lock(mutex_); + schemas_.register_schemas(manifest); +} +void AuthoringService::replace_external_schemas(const Json& manifest) { + std::lock_guard lock(mutex_); + auto candidate = builtin_schemas(); + candidate.register_schemas(manifest); + schemas_ = std::move(candidate); +} +void AuthoringService::apply(Json& scene, const Json& command) { + require(command.is_object() && command.contains("op") && command["op"].is_string(), + "command.invalid", "Command requires an operation name"); + const auto op = command.at("op").get(); + if (op == "entity.create") { + Json value = command.contains("entity") && command["entity"].is_object() + ? command["entity"] + : make_entity(schemas_, command.value("name", std::string("Object")), + command.value("parent", std::string())); + if (!value.contains("id")) + value["id"] = new_id(); scene["entities"].push_back(std::move(value)); - } else if(op=="entity.rename") { - entity(scene,command.at("entity").get())["name"]=command.at("name"); - } else if(op=="entity.delete") { - const auto id=command.at("entity").get();entity(scene,id); - std::set removed{id};bool changed=true; - while(changed) {changed=false;for(const auto& item:scene["entities"])if(removed.contains(parent_id(item)))changed=removed.insert(item.at("id").get()).second||changed;} - auto& values=scene["entities"];values.erase(std::remove_if(values.begin(),values.end(),[&](const Json& value){return removed.contains(value.at("id").get());}),values.end()); - } else if(op=="entity.reparent") { - auto& value=entity(scene,command.at("entity").get()); - require(!command.value("keep_world",false),"transform.unsupported","World-preserving reparent requires the transform resolver"); - const auto parent=command.value("parent",Json(nullptr));if(!parent.is_null())entity(scene,parent.get());value["parent"]=parent; - } else if(op=="component.add") { - auto& value=entity(scene,command.at("entity").get());const auto type=command.at("type").get(); - const auto metadata=schemas_.schema(type);Json fields=schemas_.default_fields(type);if(command.contains("fields"))fields.update(command["fields"]); - value["components"].push_back({{"id",command.value("id",new_id())},{"type",type},{"version",metadata.value("version",1)},{"fields",fields}}); - } else if(op=="component.remove") { - auto& values=entity(scene,command.at("entity").get())["components"];const auto id=command.at("component").get(); - auto found=std::find_if(values.begin(),values.end(),[&](const Json& value){return value.at("id")==id;});require(found!=values.end(),"component.missing","Component does not exist");values.erase(found); - } else if(op=="component.set") { - auto& value=component(entity(scene,command.at("entity").get()),command.at("component").get()); - const auto field=command.at("field").get();require(!field.empty(),"field.invalid","FieldId cannot be empty");value["fields"][field]=command.at("value"); - } else if(op=="entity.duplicate") { - const auto id=command.at("entity").get();entity(scene,id); - std::set subtree{id};bool changed=true; - while(changed) {changed=false;for(const auto& item:scene["entities"])if(subtree.contains(parent_id(item)))changed=subtree.insert(item.at("id").get()).second||changed;} - std::map mapping; - for(const auto& item:scene["entities"])if(subtree.contains(item.at("id").get())) {mapping[item.at("id")]=new_id();for(const auto& component:item["components"])mapping[component.at("id")]=new_id();} - Json duplicates=Json::array(); - for(const auto& item:scene["entities"])if(subtree.contains(item.at("id").get())) { - auto copy=item;copy["id"]=mapping.at(item.at("id").get());const auto parent=parent_id(item);if(mapping.contains(parent))copy["parent"]=mapping.at(parent); - if(item.at("id")==id)copy["name"]=item.at("name").get()+" Copy"; - for(auto& component:copy["components"]) { - component["id"]=mapping.at(component.at("id").get());const auto type=component.at("type").get(); - if(!schemas_.contains(type))continue; - const auto metadata=schemas_.schema(type); - for(auto& [field,value]:component["fields"].items())if(metadata["fields"].contains(field)&&metadata["fields"][field].value("type",std::string())=="entity_ref"&&value.is_string()&&mapping.contains(value.get()))value=mapping.at(value.get()); - } - duplicates.push_back(std::move(copy)); + } else if (op == "entity.rename") { + entity(scene, command.at("entity").get())["name"] = command.at("name"); + } else if (op == "entity.delete") { + const auto id = command.at("entity").get(); + entity(scene, id); + std::set removed{id}; + bool changed = true; + while (changed) { + changed = false; + for (const auto& item : scene["entities"]) + if (removed.contains(parent_id(item))) + changed = removed.insert(item.at("id").get()).second || changed; } - for(auto& value:duplicates)scene["entities"].push_back(std::move(value)); - } else if(op=="scene.rename")scene["name"]=command.at("name"); - else if(op=="template.instance") { - Json value=command.at("instance");if(!value.contains("id"))value["id"]=new_id();if(!scene.contains("instances"))scene["instances"]=Json::array();scene["instances"].push_back(std::move(value)); - } else if(op=="template.override"||op=="template.revert"||op=="template.suppress"||op=="template.add"||op=="template.reparent") { - auto& instances=scene["instances"];const auto id=command.at("instance").get(); - auto found=std::find_if(instances.begin(),instances.end(),[&](const Json& value){return value.at("id")==id;});require(found!=instances.end(),"template.missing","Instance not found"); - const std::string key=op=="template.suppress"?"suppressed":op=="template.add"?"additions":op=="template.reparent"?"reparents":"overrides"; - if(!found->contains(key)) (*found)[key]=Json::array(); - auto& records=(*found)[key]; - if(key=="overrides") { - const auto address=command.at("address"); - auto old=std::find_if(records.begin(),records.end(),[&](const Json& value){return value.at("address")==address;}); - if(old!=records.end())records.erase(old); - if(op!="template.revert")records.push_back({{"address",address},{"value",command.at("value")}}); - } else records.push_back(command.at("value")); - } else throw Error("command.unknown","Unknown authoring command: "+op); + auto& values = scene["entities"]; + values.erase(std::remove_if(values.begin(), values.end(), + [&](const Json& value) { + return removed.contains(value.at("id").get()); + }), + values.end()); + } else if (op == "entity.reparent") { + reparent_entity(scene, command.at("entity").get(), + command.value("parent", Json(nullptr)), command.value("keep_world", false)); + } else if (op == "component.add") { + auto& value = entity(scene, command.at("entity").get()); + const auto type = command.at("type").get(); + const auto metadata = schemas_.schema(type); + Json fields = schemas_.default_fields(type); + if (command.contains("fields")) + fields.update(command["fields"]); + value["components"].push_back({{"id", command.value("id", new_id())}, + {"type", type}, + {"version", metadata.value("version", 1)}, + {"fields", fields}}); + } else if (op == "component.remove") { + auto& values = entity(scene, command.at("entity").get())["components"]; + const auto id = command.at("component").get(); + auto found = std::find_if(values.begin(), values.end(), + [&](const Json& value) { return value.at("id") == id; }); + require(found != values.end(), "component.missing", "Component does not exist"); + values.erase(found); + } else if (op == "component.set") { + auto& value = component(entity(scene, command.at("entity").get()), + command.at("component").get()); + const auto field = command.at("field").get(); + require(!field.empty(), "field.invalid", "FieldId cannot be empty"); + value["fields"][field] = command.at("value"); + } else if (op == "entity.duplicate") { + const auto id = command.at("entity").get(); + entity(scene, id); + std::set subtree{id}; + bool changed = true; + while (changed) { + changed = false; + for (const auto& item : scene["entities"]) + if (subtree.contains(parent_id(item))) + changed = subtree.insert(item.at("id").get()).second || changed; + } + std::map mapping; + for (const auto& item : scene["entities"]) + if (subtree.contains(item.at("id").get())) { + mapping[item.at("id")] = new_id(); + for (const auto& component : item["components"]) + mapping[component.at("id")] = new_id(); + } + Json duplicates = Json::array(); + for (const auto& item : scene["entities"]) + if (subtree.contains(item.at("id").get())) { + auto copy = item; + copy["id"] = mapping.at(item.at("id").get()); + const auto parent = parent_id(item); + if (mapping.contains(parent)) + copy["parent"] = mapping.at(parent); + if (item.at("id") == id) + copy["name"] = item.at("name").get() + " Copy"; + for (auto& component : copy["components"]) { + component["id"] = mapping.at(component.at("id").get()); + const auto type = component.at("type").get(); + if (!schemas_.contains(type)) + continue; + const auto metadata = schemas_.schema(type); + for (auto& [field, value] : component["fields"].items()) + if (metadata["fields"].contains(field) && + metadata["fields"][field].value("type", std::string()) == + "entity_ref" && + value.is_string() && mapping.contains(value.get())) + value = mapping.at(value.get()); + } + duplicates.push_back(std::move(copy)); + } + for (auto& value : duplicates) + scene["entities"].push_back(std::move(value)); + } else if (op == "scene.rename") + scene["name"] = command.at("name"); + else if (op == "template.instance") { + Json value = command.at("instance"); + if (!value.contains("id")) + value["id"] = new_id(); + if (!scene.contains("instances")) + scene["instances"] = Json::array(); + scene["instances"].push_back(std::move(value)); + } else if (op == "template.override" || op == "template.revert" || op == "template.suppress" || + op == "template.add" || op == "template.reparent") { + auto& instances = scene["instances"]; + const auto id = command.at("instance").get(); + auto found = std::find_if(instances.begin(), instances.end(), + [&](const Json& value) { return value.at("id") == id; }); + require(found != instances.end(), "template.missing", "Instance not found"); + const std::string key = op == "template.suppress" ? "suppressed" + : op == "template.add" ? "additions" + : op == "template.reparent" ? "reparents" + : "overrides"; + if (!found->contains(key)) + (*found)[key] = Json::array(); + auto& records = (*found)[key]; + if (key == "overrides") { + const auto address = command.at("address"); + auto old = std::find_if(records.begin(), records.end(), [&](const Json& value) { + return value.at("address") == address; + }); + if (old != records.end()) + records.erase(old); + if (op != "template.revert") + records.push_back({{"address", address}, {"value", command.at("value")}}); + } else + records.push_back(command.at("value")); + } else + throw Error("command.unknown", "Unknown authoring command: " + op); } -Json AuthoringService::transact(const std::string& id,std::uint64_t revision,const Json& operations,const std::string& key) { - std::lock_guard lock(mutex_);auto& current=state(id);require(operations.is_array()&&!operations.empty(),"transaction.empty","Transaction requires an array of operations"); - const auto fingerprint=sha256(Json{{"revision",revision},{"operations",operations}}.dump()); - if(!key.empty()&¤t.requests.contains(key)) { - const auto& request=current.requests.at(key);require(request.first==fingerprint,"idempotency.conflict","Idempotency key was used with another payload");return request.second; +Json AuthoringService::transact(const std::string& id, std::uint64_t revision, + const Json& operations, const std::string& key) { + std::lock_guard lock(mutex_); + auto& current = state(id); + require(operations.is_array() && !operations.empty(), "transaction.empty", + "Transaction requires an array of operations"); + const auto fingerprint = + sha256(Json{{"revision", revision}, {"operations", operations}}.dump()); + if (!key.empty() && current.requests.contains(key)) { + const auto& request = current.requests.at(key); + require(request.first == fingerprint, "idempotency.conflict", + "Idempotency key was used with another payload"); + return request.second; } - check_revision(current.revision,revision);State candidate=current; - for(const auto& operation:operations)apply(candidate.data,operation); - validate_scene(candidate.data,schemas_); - candidate.undo.push_back(current.data);if(candidate.undo.size()>100)candidate.undo.erase(candidate.undo.begin());candidate.redo.clear();++candidate.revision; - journal(candidate);auto result=summary(candidate); - if(!key.empty()) {if(candidate.requests.size()>=256)candidate.requests.erase(candidate.requests.begin());candidate.requests[key]={fingerprint,result};} - current=std::move(candidate);return result; -} -Json AuthoringService::history(const std::string& id,std::uint64_t revision,bool forward) { - std::lock_guard lock(mutex_);auto& current=state(id);check_revision(current.revision,revision);State candidate=current; - auto& source=forward?candidate.redo:candidate.undo;auto& target=forward?candidate.undo:candidate.redo; - require(!source.empty(),"history.empty",forward?"Nothing to redo":"Nothing to undo");target.push_back(candidate.data);candidate.data=source.back();source.pop_back();++candidate.revision;journal(candidate);current=std::move(candidate);return summary(current); -} -Json AuthoringService::undo(const std::string& id,std::uint64_t revision){return history(id,revision,false);} -Json AuthoringService::redo(const std::string& id,std::uint64_t revision){return history(id,revision,true);} -Json AuthoringService::save(const std::string& id,const std::filesystem::path& relative) { - std::lock_guard lock(mutex_);auto& current=state(id);const auto selected=relative.empty()?current.path:relative.lexically_normal();require(!selected.empty(),"save.path","Choose a scene path before saving"); - const auto path=project_path(root_,selected); - if(std::filesystem::exists(path)) { - require(selected==current.path&&!current.disk_hash.empty(),"save.exists","Save As will not overwrite another file"); - require(sha256_file(path)==current.disk_hash,"save.disk_conflict","File changed outside the Editor; reload or save to another path"); + check_revision(current.revision, revision); + State candidate = current; + for (const auto& operation : operations) + apply(candidate.data, operation); + validate_scene(candidate.data, schemas_); + candidate.undo.push_back(current.data); + if (candidate.undo.size() > 100) + candidate.undo.erase(candidate.undo.begin()); + candidate.redo.clear(); + ++candidate.revision; + journal(candidate); + auto result = summary(candidate); + if (!key.empty()) { + if (candidate.requests.size() >= 256) + candidate.requests.erase(candidate.requests.begin()); + candidate.requests[key] = {fingerprint, result}; } - atomic_write_json(path,current.data);current.path=selected;current.saved_hash=sha256(current.data.dump());current.disk_hash=sha256_file(path); - journal(current);return summary(current); + current = std::move(candidate); + return result; } -Json AuthoringService::recovery_documents()const { - std::lock_guard lock(mutex_);Json result=Json::array();const auto path=project_path(root_,".faset/recovery");if(!std::filesystem::exists(path))return result; - for(const auto& entry:std::filesystem::directory_iterator(path))if(entry.is_regular_file()&&entry.path().extension()==".json") { - try {const auto value=read_json(entry.path());result.push_back({{"id",value.at("scene").at("id")},{"name",value.at("scene").at("name")},{"path",value.at("path")},{"dirty",sha256(value.at("scene").dump())!=value.value("saved_hash",std::string())}});}catch(const std::exception&) {result.push_back({{"error","Invalid recovery record"},{"file",entry.path().filename().string()}});} - }return result; +Json AuthoringService::history(const std::string& id, std::uint64_t revision, bool forward) { + std::lock_guard lock(mutex_); + auto& current = state(id); + check_revision(current.revision, revision); + State candidate = current; + auto& source = forward ? candidate.redo : candidate.undo; + auto& target = forward ? candidate.undo : candidate.redo; + require(!source.empty(), "history.empty", forward ? "Nothing to redo" : "Nothing to undo"); + target.push_back(candidate.data); + candidate.data = source.back(); + source.pop_back(); + ++candidate.revision; + journal(candidate); + current = std::move(candidate); + return summary(current); } +Json AuthoringService::undo(const std::string& id, std::uint64_t revision) { + return history(id, revision, false); } +Json AuthoringService::redo(const std::string& id, std::uint64_t revision) { + return history(id, revision, true); +} +Json AuthoringService::save(const std::string& id, const std::filesystem::path& relative) { + std::lock_guard lock(mutex_); + auto& current = state(id); + const auto selected = relative.empty() ? current.path : relative.lexically_normal(); + require(!selected.empty(), "save.path", "Choose a scene path before saving"); + const auto path = project_path(root_, selected); + if (std::filesystem::exists(path)) { + require(selected == current.path && !current.disk_hash.empty(), "save.exists", + "Save As will not overwrite another file"); + require(sha256_file(path) == current.disk_hash, "save.disk_conflict", + "File changed outside the Editor; reload or save to another path"); + } + atomic_write_json(path, current.data); + current.path = selected; + current.saved_hash = sha256(current.data.dump()); + current.disk_hash = sha256_file(path); + journal(current); + return summary(current); +} +Json AuthoringService::recover(const std::string& id, + std::optional expected_revision) { + std::lock_guard lock(mutex_); + require(valid_id(Json(id)), "id.invalid", "Invalid recovery document ID"); + const auto record = + read_json(project_path(root_, std::filesystem::path(".faset/recovery") / (id + ".json"))); + require(record.value("format", std::string()) == "faset.recovery" && + record.value("version", 0) == 1, + "recovery.format", "Unsupported recovery record"); + State candidate; + candidate.data = record.at("scene"); + validate_scene(candidate.data, schemas_); + require(candidate.data.at("id") == id, "recovery.id", + "Recovery ID does not match its document"); + candidate.path = record.at("path").get(); + candidate.saved_hash = record.value("saved_hash", std::string()); + candidate.disk_hash = record.value("disk_hash", std::string()); + candidate.revision = record.value("revision", std::uint64_t(0)); + if (!candidate.path.empty()) { + const auto disk = project_path(root_, candidate.path); + require(std::filesystem::exists(disk) && sha256_file(disk) == candidate.disk_hash, + "recovery.disk_conflict", + "Scene file changed or disappeared since recovery was written"); + } + for (auto& item : candidate.data["entities"]) + for (auto& component : item["components"]) + component = schemas_.migrate_component(component); + validate_scene(candidate.data, schemas_); + if (documents_.contains(id)) { + const auto& current = state(id); + require(expected_revision.has_value(), "recovery.revision_required", + "Recovering an open document requires its current revision"); + check_revision(current.revision, *expected_revision); + require(current.path == candidate.path, "document.id_collision", + "Recovery path differs from the open document"); + if (candidate.data == current.data) + return summary(current); + candidate.undo = current.undo; + candidate.undo.push_back(current.data); + candidate.revision = std::max(current.revision, candidate.revision) + 1; + } else if (!candidate.path.empty()) + candidate.undo.push_back(read_json(project_path(root_, candidate.path))); + journal(candidate); + documents_[id] = std::move(candidate); + return summary(state(id)); +} +Json AuthoringService::recovery_documents() const { + std::lock_guard lock(mutex_); + Json result = Json::array(); + const auto path = project_path(root_, ".faset/recovery"); + if (!std::filesystem::exists(path)) + return result; + for (const auto& entry : std::filesystem::directory_iterator(path)) + if (entry.is_regular_file() && entry.path().extension() == ".json") { + try { + const auto value = read_json(entry.path()); + result.push_back({{"id", value.at("scene").at("id")}, + {"name", value.at("scene").at("name")}, + {"path", value.at("path")}, + {"dirty", sha256(value.at("scene").dump()) != + value.value("saved_hash", std::string())}}); + } catch (const std::exception&) { + result.push_back({{"error", "Invalid recovery record"}, + {"file", entry.path().filename().string()}}); + } + } + return result; +} +} // namespace faset::authoring diff --git a/src/authoring/templates.cpp b/src/authoring/templates.cpp index a845ad9..4843955 100644 --- a/src/authoring/templates.cpp +++ b/src/authoring/templates.cpp @@ -1,99 +1,199 @@ -#include -#include -#include #include +#include +#include +#include +#include #include namespace faset::authoring { namespace { -std::string scoped_id(const std::string& root,const Json& path,const std::string& source) { - const auto digest=sha256(Json::array({root,path,source}).dump()); - return digest.substr(0,8)+"-"+digest.substr(8,4)+"-5"+digest.substr(13,3)+"-a"+digest.substr(17,3)+"-"+digest.substr(20,12); +std::string scoped_id(const std::string& root, const Json& path, const std::string& source) { + const auto digest = sha256(Json::array({root, path, source}).dump()); + return digest.substr(0, 8) + "-" + digest.substr(8, 4) + "-5" + digest.substr(13, 3) + "-a" + + digest.substr(17, 3) + "-" + digest.substr(20, 12); } struct Resolver { const SchemaRegistry& schemas; const SceneLoader& loader; std::string root; - Json conflicts=Json::array(); + Json conflicts = Json::array(); std::set sources; - void conflict(const Json& path,std::string code,const Json& record) {conflicts.push_back({{"instance_path",path},{"code",std::move(code)},{"record",record}});} - Json* target(Json& entities,const Json& path,const Json& address) { - Json full=path;for(const auto& entry:address.value("path",Json::array()))full.push_back(entry); - for(auto& item:entities)if(item.at("origin").at("path")==full&&item.at("origin").at("object")==address.at("object"))return &item; + void conflict(const Json& path, std::string code, const Json& record) { + conflicts.push_back( + {{"instance_path", path}, {"code", std::move(code)}, {"record", record}}); + } + Json* target(Json& entities, const Json& path, const Json& address) { + Json full = path; + for (const auto& entry : address.value("path", Json::array())) + full.push_back(entry); + for (auto& item : entities) + if (item.at("origin").at("path") == full && + item.at("origin").at("object") == address.at("object")) + return &item; return nullptr; } - Json expand(const Json& scene,const Json& path) { - require(path.size()<=32,"template.depth","Maximum template nesting depth exceeded"); - validate_scene(scene,schemas); - Json output=Json::array();std::map ids; - for(const auto& item:scene["entities"]) { - const auto id=item.at("id").get();ids[id]=path.empty()?id:scoped_id(root,path,id); - for(const auto& component:item["components"]) {const auto cid=component.at("id").get();ids[cid]=path.empty()?cid:scoped_id(root,path,cid);} + Json expand(const Json& scene, const Json& path) { + require(path.size() <= 32, "template.depth", "Maximum template nesting depth exceeded"); + validate_scene(scene, schemas); + Json output = Json::array(); + std::map ids; + for (const auto& item : scene["entities"]) { + const auto id = item.at("id").get(); + ids[id] = path.empty() ? id : scoped_id(root, path, id); + for (const auto& component : item["components"]) { + const auto cid = component.at("id").get(); + ids[cid] = path.empty() ? cid : scoped_id(root, path, cid); + } } - for(const auto& source:scene["entities"]) { - Json item=source;item["id"]=ids.at(source.at("id").get()); - item["origin"]={{"path",path},{"object",source.at("id")},{"scene",scene.at("id")}}; - if(source.contains("parent")&&!source["parent"].is_null())item["parent"]=ids.at(source["parent"].get()); - for(auto& component:item["components"]) { - const auto source_id=component.at("id").get();component["id"]=ids.at(source_id);component["source_id"]=source_id; - const auto type=component.at("type").get();if(!schemas.contains(type))continue; - const auto metadata=schemas.schema(type); - for(auto& [field,value]:component["fields"].items())if(metadata["fields"].contains(field)&&metadata["fields"][field].value("type",std::string())=="entity_ref"&&value.is_string()&&ids.contains(value.get()))value=ids.at(value.get()); + for (const auto& source : scene["entities"]) { + Json item = source; + item["id"] = ids.at(source.at("id").get()); + item["origin"] = { + {"path", path}, {"object", source.at("id")}, {"scene", scene.at("id")}}; + if (source.contains("parent") && !source["parent"].is_null()) + item["parent"] = ids.at(source["parent"].get()); + for (auto& component : item["components"]) { + const auto source_id = component.at("id").get(); + component["id"] = ids.at(source_id); + component["source_id"] = source_id; + const auto type = component.at("type").get(); + if (!schemas.contains(type)) + continue; + const auto metadata = schemas.schema(type); + for (auto& [field, value] : component["fields"].items()) + if (metadata["fields"].contains(field) && + metadata["fields"][field].value("type", std::string()) == "entity_ref" && + value.is_string() && ids.contains(value.get())) + value = ids.at(value.get()); } output.push_back(std::move(item)); } - for(const auto& instance:scene.value("instances",Json::array())) { - Json nested_path=path;nested_path.push_back(instance.at("id"));const auto source_name=instance.at("source").get(); - Json expanded=Json::array();std::string source_id; + for (const auto& instance : scene.value("instances", Json::array())) { + Json nested_path = path; + nested_path.push_back(instance.at("id")); + const auto source_name = instance.at("source").get(); + Json expanded = Json::array(); + std::string source_id; + bool inserted = false; try { - const auto source=loader(source_name);source_id=source.at("id").get(); - require(sources.insert(source_id).second,"template.cycle","Template source cycle detected"); - expanded=expand(source,nested_path);sources.erase(source_id); - } catch(const std::exception& error) { - if(!source_id.empty())sources.erase(source_id); - conflict(nested_path,"template.source_unavailable",{{"source",source_name},{"message",error.what()}});continue; + const auto source = loader(source_name); + source_id = source.at("id").get(); + inserted = sources.insert(source_id).second; + require(inserted, "template.cycle", "Template source cycle detected"); + expanded = expand(source, nested_path); + sources.erase(source_id); + } catch (const std::exception& error) { + if (inserted) + sources.erase(source_id); + conflict(nested_path, "template.source_unavailable", + {{"source", source_name}, {"message", error.what()}}); + continue; } - for(const auto& addition:instance.value("additions",Json::array())) { - Json item=addition;const auto id=item.at("id").get();item["id"]=scoped_id(root,nested_path,id); - item["origin"]={{"path",nested_path},{"object",id},{"local",true}}; - if(item.contains("parent")&&!item["parent"].is_null())item["parent"]=scoped_id(root,nested_path,item["parent"].get()); - for(auto& component:item["components"]) {const auto cid=component.at("id").get();component["source_id"]=cid;component["id"]=scoped_id(root,nested_path,cid);} + for (const auto& addition : instance.value("additions", Json::array())) { + Json item = addition; + const auto id = item.at("id").get(); + item["id"] = scoped_id(root, nested_path, id); + item["origin"] = {{"path", nested_path}, {"object", id}, {"local", true}}; + if (item.contains("parent") && !item["parent"].is_null()) + item["parent"] = + scoped_id(root, nested_path, item["parent"].get()); + for (auto& component : item["components"]) { + const auto cid = component.at("id").get(); + component["source_id"] = cid; + component["id"] = scoped_id(root, nested_path, cid); + } expanded.push_back(std::move(item)); } - for(const auto& change:instance.value("overrides",Json::array())) { - const auto& address=change.at("address");auto* item=target(expanded,nested_path,address); - if(!item){conflict(nested_path,"override.object_missing",change);continue;} - auto found=std::find_if((*item)["components"].begin(),(*item)["components"].end(),[&](const Json& value){return value.at("source_id")==address.at("component");}); - if(found==(*item)["components"].end()){conflict(nested_path,"override.component_missing",change);continue;} - const auto type=found->at("type").get();const auto field=address.at("field").get(); - if(!schemas.contains(type)||!schemas.schema(type)["fields"].contains(field)){conflict(nested_path,"override.field_unavailable",change);continue;} - try {validate_field(change.at("value"),schemas.schema(type)["fields"][field]);(*found)["fields"][field]=change.at("value");} - catch(const std::exception& error){conflict(nested_path,"override.invalid",{{"change",change},{"message",error.what()}});} + for (const auto& change : instance.value("overrides", Json::array())) { + const auto& address = change.at("address"); + auto* item = target(expanded, nested_path, address); + if (!item) { + conflict(nested_path, "override.object_missing", change); + continue; + } + auto found = + std::find_if((*item)["components"].begin(), (*item)["components"].end(), + [&](const Json& value) { + return value.at("source_id") == address.at("component"); + }); + if (found == (*item)["components"].end()) { + conflict(nested_path, "override.component_missing", change); + continue; + } + const auto type = found->at("type").get(); + const auto field = address.at("field").get(); + if (!schemas.contains(type) || !schemas.schema(type)["fields"].contains(field)) { + conflict(nested_path, "override.field_unavailable", change); + continue; + } + try { + validate_field(change.at("value"), schemas.schema(type)["fields"][field]); + (*found)["fields"][field] = change.at("value"); + } catch (const std::exception& error) { + conflict(nested_path, "override.invalid", + {{"change", change}, {"message", error.what()}}); + } } std::set suppressed; - for(const auto& address:instance.value("suppressed",Json::array())) { - auto* item=target(expanded,nested_path,address);if(item)suppressed.insert(item->at("id").get());else conflict(nested_path,"suppression.object_missing",address); + for (const auto& address : instance.value("suppressed", Json::array())) { + auto* item = target(expanded, nested_path, address); + if (item) + suppressed.insert(item->at("id").get()); + else + conflict(nested_path, "suppression.object_missing", address); } - bool changed=true; - while(changed) {changed=false;for(const auto& item:expanded)if(item.contains("parent")&&item["parent"].is_string()&&suppressed.contains(item["parent"].get()))changed=suppressed.insert(item.at("id").get()).second||changed;} - expanded.erase(std::remove_if(expanded.begin(),expanded.end(),[&](const Json& item){return suppressed.contains(item.at("id").get());}),expanded.end()); - for(const auto& reparent:instance.value("reparents",Json::array())) { - auto* item=target(expanded,nested_path,reparent.at("object")); - auto* parent=reparent.at("parent").is_null()?nullptr:target(expanded,nested_path,reparent.at("parent")); - if(!item||(!reparent.at("parent").is_null()&&!parent)){conflict(nested_path,"reparent.target_missing",reparent);continue;} - if(reparent.value("keep_world",false)){conflict(nested_path,"reparent.world_transform_required",reparent);continue;} - (*item)["parent"]=parent?parent->at("id"):Json(nullptr); + bool changed = true; + while (changed) { + changed = false; + for (const auto& item : expanded) + if (item.contains("parent") && item["parent"].is_string() && + suppressed.contains(item["parent"].get())) + changed = + suppressed.insert(item.at("id").get()).second || changed; } - for(auto& item:expanded)output.push_back(std::move(item)); - require(output.size()<=100000,"template.size","Resolved scene exceeds object limit"); + expanded.erase(std::remove_if(expanded.begin(), expanded.end(), + [&](const Json& item) { + return suppressed.contains( + item.at("id").get()); + }), + expanded.end()); + for (const auto& reparent : instance.value("reparents", Json::array())) { + auto* item = target(expanded, nested_path, reparent.at("object")); + auto* parent = reparent.at("parent").is_null() + ? nullptr + : target(expanded, nested_path, reparent.at("parent")); + if (!item || (!reparent.at("parent").is_null() && !parent)) { + conflict(nested_path, "reparent.target_missing", reparent); + continue; + } + const auto id = item->at("id").get(); + const Json parent_id = parent ? parent->at("id") : Json(nullptr); + Json temporary = {{"entities", expanded}}; + try { + reparent_entity(temporary, id, parent_id, reparent.value("keep_world", false)); + expanded = temporary["entities"]; + } catch (const std::exception& error) { + conflict(nested_path, "reparent.transform_conflict", + {{"record", reparent}, {"message", error.what()}}); + } + } + for (auto& item : expanded) + output.push_back(std::move(item)); + require(output.size() <= 100000, "template.size", + "Resolved scene exceeds object limit"); } return output; } }; +} // namespace +ResolvedScene resolve_templates(const Json& scene, const SchemaRegistry& schemas, + const SceneLoader& loader) { + Resolver resolver{schemas, loader, scene.at("id").get()}; + resolver.sources.insert(scene.at("id").get()); + Json output = scene; + output["entities"] = resolver.expand(scene, Json::array()); + output["instances"] = Json::array(); + validate_scene(output, schemas); + return {output, resolver.conflicts}; } -ResolvedScene resolve_templates(const Json& scene,const SchemaRegistry& schemas,const SceneLoader& loader) { - Resolver resolver{schemas,loader,scene.at("id").get()};resolver.sources.insert(scene.at("id").get()); - Json output=scene;output["entities"]=resolver.expand(scene,Json::array());output["instances"]=Json::array(); - validate_scene(output,schemas);return {output,resolver.conflicts}; -} -} +} // namespace faset::authoring diff --git a/src/authoring/transforms.cpp b/src/authoring/transforms.cpp new file mode 100644 index 0000000..1b1b73f --- /dev/null +++ b/src/authoring/transforms.cpp @@ -0,0 +1,156 @@ +#include +#include +#include +#include +#include +#include + +namespace faset::authoring { +namespace { +using Matrix = std::array; +constexpr Matrix identity{1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1}; +Json& find_entity(Json& scene, const std::string& id) { + for (auto& item : scene["entities"]) + if (item.at("id") == id) + return item; + throw Error("entity.missing", "Entity does not exist: " + id); +} +Json* transform(Json& entity) { + for (auto& component : entity["components"]) + if (component.at("type") == "faset.transform") + return &component; + return nullptr; +} +Matrix multiply(const Matrix& a, const Matrix& b) { + Matrix result{}; + for (int row = 0; row < 4; ++row) + for (int column = 0; column < 4; ++column) + for (int k = 0; k < 4; ++k) + result[column * 4 + row] += a[k * 4 + row] * b[column * 4 + k]; + return result; +} +Matrix local(Json& entity) { + const auto* component = transform(entity); + if (!component) + return identity; + const auto& fields = component->at("fields"); + const auto p = fields.value("position", std::array{0, 0, 0}), + r = fields.value("rotation", std::array{0, 0, 0}), + s = fields.value("scale", std::array{1, 1, 1}); + const auto cx = std::cos(r[0]), sx = std::sin(r[0]), cy = std::cos(r[1]), sy = std::sin(r[1]), + cz = std::cos(r[2]), sz = std::sin(r[2]); + return {cz * cy * s[0], + sz * cy * s[0], + -sy * s[0], + 0, + (cz * sy * sx - sz * cx) * s[1], + (sz * sy * sx + cz * cx) * s[1], + cy * sx * s[1], + 0, + (cz * sy * cx + sz * sx) * s[2], + (sz * sy * cx - cz * sx) * s[2], + cy * cx * s[2], + 0, + p[0], + p[1], + p[2], + 1}; +} +Matrix world(Json& scene, const std::string& id, std::set& visited) { + require(visited.insert(id).second, "entity.cycle", "Hierarchy contains a cycle"); + auto& item = find_entity(scene, id); + auto result = local(item); + if (item.contains("parent") && !item["parent"].is_null()) + result = multiply(world(scene, item["parent"].get(), visited), result); + return result; +} +Matrix world(Json& scene, const std::string& id) { + std::set visited; + return world(scene, id, visited); +} +Matrix inverse(const Matrix& matrix) { + std::array, 4> rows{}; + for (int r = 0; r < 4; ++r) { + for (int c = 0; c < 4; ++c) + rows[r][c] = matrix[c * 4 + r]; + rows[r][r + 4] = 1; + } + for (int column = 0; column < 4; ++column) { + int pivot = column; + for (int row = column + 1; row < 4; ++row) + if (std::abs(rows[row][column]) > std::abs(rows[pivot][column])) + pivot = row; + require(std::abs(rows[pivot][column]) > 1e-12, "transform.singular", + "Cannot preserve world transform under a non-invertible parent"); + std::swap(rows[pivot], rows[column]); + const auto scale = rows[column][column]; + for (auto& entry : rows[column]) + entry /= scale; + for (int row = 0; row < 4; ++row) + if (row != column) { + const auto factor = rows[row][column]; + for (int c = 0; c < 8; ++c) + rows[row][c] -= factor * rows[column][c]; + } + } + Matrix result{}; + for (int row = 0; row < 4; ++row) + for (int column = 0; column < 4; ++column) + result[column * 4 + row] = rows[row][column + 4]; + return result; +} +Json decompose(const Matrix& matrix) { + std::array scale{}; + Matrix rotation = matrix; + for (int c = 0; c < 3; ++c) { + scale[c] = std::sqrt(matrix[c * 4] * matrix[c * 4] + matrix[c * 4 + 1] * matrix[c * 4 + 1] + + matrix[c * 4 + 2] * matrix[c * 4 + 2]); + require(scale[c] > 1e-12, "transform.singular", "Cannot decompose zero scale"); + } + const double determinant = matrix[0] * (matrix[5] * matrix[10] - matrix[9] * matrix[6]) - + matrix[4] * (matrix[1] * matrix[10] - matrix[9] * matrix[2]) + + matrix[8] * (matrix[1] * matrix[6] - matrix[5] * matrix[2]); + if (determinant < 0) + scale[0] = -scale[0]; + for (int c = 0; c < 3; ++c) + for (int r = 0; r < 3; ++r) + rotation[c * 4 + r] /= scale[c]; + for (int a = 0; a < 3; ++a) + for (int b = a + 1; b < 3; ++b) { + double dot = 0; + for (int r = 0; r < 3; ++r) + dot += rotation[a * 4 + r] * rotation[b * 4 + r]; + require(std::abs(dot) < 1e-5, "transform.shear", + "Preserving this world transform would require shear; choose keep local or " + "change parent scale"); + } + std::array angles{}; + angles[1] = std::asin(std::clamp(-rotation[2], -1.0, 1.0)); + if (std::abs(std::cos(angles[1])) > 1e-7) { + angles[0] = std::atan2(rotation[6], rotation[10]); + angles[2] = std::atan2(rotation[1], rotation[0]); + } else { + angles[0] = std::atan2(-rotation[9], rotation[5]); + angles[2] = 0; + } + return { + {"position", {matrix[12], matrix[13], matrix[14]}}, {"rotation", angles}, {"scale", scale}}; +} +} // namespace +void reparent_entity(Json& scene, const std::string& id, const Json& parent, bool keep_world) { + auto& item = find_entity(scene, id); + if (!parent.is_null()) + find_entity(scene, parent.get()); + if (keep_world) { + auto* component = transform(item); + require(component != nullptr, "transform.required", + "World-preserving reparent requires a Transform component"); + const auto previous = world(scene, id); + const auto basis = parent.is_null() ? identity : world(scene, parent.get()); + const auto fields = decompose(multiply(inverse(basis), previous)); + for (const auto& [field, value] : fields.items()) + (*component)["fields"][field] = value; + } + item["parent"] = parent; +} +} // namespace faset::authoring diff --git a/src/core/hash.cpp b/src/core/hash.cpp index c48732a..19adefe 100644 --- a/src/core/hash.cpp +++ b/src/core/hash.cpp @@ -1,72 +1,116 @@ -#include -#include #include #include #include +#include +#include #include #include namespace faset { namespace { -constexpr std::array constants = { - 0x428a2f98,0x71374491,0xb5c0fbcf,0xe9b5dba5,0x3956c25b,0x59f111f1,0x923f82a4,0xab1c5ed5, - 0xd807aa98,0x12835b01,0x243185be,0x550c7dc3,0x72be5d74,0x80deb1fe,0x9bdc06a7,0xc19bf174, - 0xe49b69c1,0xefbe4786,0x0fc19dc6,0x240ca1cc,0x2de92c6f,0x4a7484aa,0x5cb0a9dc,0x76f988da, - 0x983e5152,0xa831c66d,0xb00327c8,0xbf597fc7,0xc6e00bf3,0xd5a79147,0x06ca6351,0x14292967, - 0x27b70a85,0x2e1b2138,0x4d2c6dfc,0x53380d13,0x650a7354,0x766a0abb,0x81c2c92e,0x92722c85, - 0xa2bfe8a1,0xa81a664b,0xc24b8b70,0xc76c51a3,0xd192e819,0xd6990624,0xf40e3585,0x106aa070, - 0x19a4c116,0x1e376c08,0x2748774c,0x34b0bcb5,0x391c0cb3,0x4ed8aa4a,0x5b9cca4f,0x682e6ff3, - 0x748f82ee,0x78a5636f,0x84c87814,0x8cc70208,0x90befffa,0xa4506ceb,0xbef9a3f7,0xc67178f2 -}; +constexpr std::array constants = { + 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, + 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, + 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, + 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, + 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, + 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, + 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, + 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2}; class Digest { - std::array state_{0x6a09e667,0xbb67ae85,0x3c6ef372,0xa54ff53a,0x510e527f,0x9b05688c,0x1f83d9ab,0x5be0cd19}; - std::array pending_{}; - std::uint64_t count_=0; - std::size_t used_=0; + std::array state_{0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, + 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19}; + std::array pending_{}; + std::uint64_t count_ = 0; + std::size_t used_ = 0; void block() { - std::array w{}; - for (int i=0;i<16;++i) w[i]=(std::uint32_t(pending_[i*4])<<24)|(std::uint32_t(pending_[i*4+1])<<16)|(std::uint32_t(pending_[i*4+2])<<8)|pending_[i*4+3]; - for (int i=16;i<64;++i) { - const auto x=w[i-15],y=w[i-2]; - w[i]=w[i-16]+(std::rotr(x,7)^std::rotr(x,18)^(x>>3))+w[i-7]+(std::rotr(y,17)^std::rotr(y,19)^(y>>10)); + std::array w{}; + for (int i = 0; i < 16; ++i) + w[i] = (std::uint32_t(pending_[i * 4]) << 24) | + (std::uint32_t(pending_[i * 4 + 1]) << 16) | + (std::uint32_t(pending_[i * 4 + 2]) << 8) | pending_[i * 4 + 3]; + for (int i = 16; i < 64; ++i) { + const auto x = w[i - 15], y = w[i - 2]; + w[i] = w[i - 16] + (std::rotr(x, 7) ^ std::rotr(x, 18) ^ (x >> 3)) + w[i - 7] + + (std::rotr(y, 17) ^ std::rotr(y, 19) ^ (y >> 10)); } - auto a=state_[0],b=state_[1],c=state_[2],d=state_[3],e=state_[4],f=state_[5],g=state_[6],h=state_[7]; - for (int i=0;i<64;++i) { - const auto t1=h+(std::rotr(e,6)^std::rotr(e,11)^std::rotr(e,25))+((e&f)^(~e&g))+constants[i]+w[i]; - const auto t2=(std::rotr(a,2)^std::rotr(a,13)^std::rotr(a,22))+((a&b)^(a&c)^(b&c)); - h=g;g=f;f=e;e=d+t1;d=c;c=b;b=a;a=t1+t2; + auto a = state_[0], b = state_[1], c = state_[2], d = state_[3], e = state_[4], + f = state_[5], g = state_[6], h = state_[7]; + for (int i = 0; i < 64; ++i) { + const auto t1 = h + (std::rotr(e, 6) ^ std::rotr(e, 11) ^ std::rotr(e, 25)) + + ((e & f) ^ (~e & g)) + constants[i] + w[i]; + const auto t2 = (std::rotr(a, 2) ^ std::rotr(a, 13) ^ std::rotr(a, 22)) + + ((a & b) ^ (a & c) ^ (b & c)); + h = g; + g = f; + f = e; + e = d + t1; + d = c; + c = b; + b = a; + a = t1 + t2; } - state_[0]+=a;state_[1]+=b;state_[2]+=c;state_[3]+=d;state_[4]+=e;state_[5]+=f;state_[6]+=g;state_[7]+=h; + state_[0] += a; + state_[1] += b; + state_[2] += c; + state_[3] += d; + state_[4] += e; + state_[5] += f; + state_[6] += g; + state_[7] += h; } -public: + + public: void update(std::span bytes) { - count_+=bytes.size(); - for (auto byte:bytes) { - pending_[used_++]=std::to_integer(byte); - if (used_==64) { block();used_=0; } + count_ += bytes.size(); + for (auto byte : bytes) { + pending_[used_++] = std::to_integer(byte); + if (used_ == 64) { + block(); + used_ = 0; + } } } std::string finish() { - const std::uint64_t bits=count_*8; - pending_[used_++]=0x80; - if (used_>56) { while(used_<64) pending_[used_++]=0;block();used_=0; } - while(used_<56) pending_[used_++]=0; - for (int i=7;i>=0;--i) pending_[used_++]=std::uint8_t(bits>>(i*8)); + const std::uint64_t bits = count_ * 8; + pending_[used_++] = 0x80; + if (used_ > 56) { + while (used_ < 64) + pending_[used_++] = 0; + block(); + used_ = 0; + } + while (used_ < 56) + pending_[used_++] = 0; + for (int i = 7; i >= 0; --i) + pending_[used_++] = std::uint8_t(bits >> (i * 8)); block(); - constexpr char hex[]="0123456789abcdef"; - std::string result;result.reserve(64); - for (auto word:state_) for (int i=7;i>=0;--i) result+=hex[(word>>(i*4))&15]; + constexpr char hex[] = "0123456789abcdef"; + std::string result; + result.reserve(64); + for (auto word : state_) + for (int i = 7; i >= 0; --i) + result += hex[(word >> (i * 4)) & 15]; return result; } }; -} -std::string sha256(std::span bytes) { Digest digest;digest.update(bytes);return digest.finish(); } -std::string sha256_file(const std::filesystem::path& path) { - std::ifstream stream(path,std::ios::binary); - require(bool(stream),"io.open","Cannot open file for hashing: "+path.string()); - Digest digest;std::array buffer{}; - while(stream) { stream.read(buffer.data(),buffer.size());digest.update(std::as_bytes(std::span(buffer.data(),static_cast(stream.gcount())))); } - require(stream.eof(),"io.read","Cannot read file for hashing: "+path.string()); +} // namespace +std::string sha256(std::span bytes) { + Digest digest; + digest.update(bytes); return digest.finish(); } +std::string sha256_file(const std::filesystem::path& path) { + std::ifstream stream(path, std::ios::binary); + require(bool(stream), "io.open", "Cannot open file for hashing: " + path.string()); + Digest digest; + std::array buffer{}; + while (stream) { + stream.read(buffer.data(), buffer.size()); + digest.update( + std::as_bytes(std::span(buffer.data(), static_cast(stream.gcount())))); + } + require(stream.eof(), "io.read", "Cannot read file for hashing: " + path.string()); + return digest.finish(); } +} // namespace faset diff --git a/src/core/io.cpp b/src/core/io.cpp index ca3e3b3..9fab6c2 100644 --- a/src/core/io.cpp +++ b/src/core/io.cpp @@ -1,9 +1,9 @@ -#include -#include #include +#include +#include #include -#include #include +#include #ifdef _WIN32 #define NOMINMAX #include @@ -16,57 +16,111 @@ namespace faset { std::string new_id() { static std::mutex mutex; static std::random_device random; - std::array bytes{}; - { std::lock_guard lock(mutex); for(auto& byte:bytes) byte=static_cast(random()); } - bytes[6]=(bytes[6]&0x0f)|0x40;bytes[8]=(bytes[8]&0x3f)|0x80; - constexpr char hex[]="0123456789abcdef"; - std::string result;result.reserve(36); - for(std::size_t i=0;i>4];result+=hex[bytes[i]&15]; } + std::array bytes{}; + { + std::lock_guard lock(mutex); + for (auto& byte : bytes) + byte = static_cast(random()); + } + bytes[6] = (bytes[6] & 0x0f) | 0x40; + bytes[8] = (bytes[8] & 0x3f) | 0x80; + constexpr char hex[] = "0123456789abcdef"; + std::string result; + result.reserve(36); + for (std::size_t i = 0; i < bytes.size(); ++i) { + if (i == 4 || i == 6 || i == 8 || i == 10) + result += '-'; + result += hex[bytes[i] >> 4]; + result += hex[bytes[i] & 15]; + } return result; } std::string read_text(const std::filesystem::path& path) { - std::ifstream stream(path,std::ios::binary); - require(bool(stream),"io.open","Cannot open file: "+path.string()); - std::string value((std::istreambuf_iterator(stream)),{}); - require(!stream.bad(),"io.read","Cannot read file: "+path.string());return value; + std::ifstream stream(path, std::ios::binary); + require(bool(stream), "io.open", "Cannot open file: " + path.string()); + std::string value((std::istreambuf_iterator(stream)), {}); + require(!stream.bad(), "io.read", "Cannot read file: " + path.string()); + return value; } Json read_json(const std::filesystem::path& path) { - try { return Json::parse(read_text(path)); } - catch(const Json::exception& error) { throw Error("format.json","Invalid JSON in "+path.string(),{{"reason",error.what()}}); } + try { + return Json::parse(read_text(path)); + } catch (const Json::exception& error) { + throw Error("format.json", "Invalid JSON in " + path.string(), {{"reason", error.what()}}); + } } -void atomic_write(const std::filesystem::path& path,std::string_view bytes) { - const auto parent=path.has_parent_path()?path.parent_path():std::filesystem::path("."); +void atomic_write(const std::filesystem::path& path, std::string_view bytes) { + const auto parent = path.has_parent_path() ? path.parent_path() : std::filesystem::path("."); std::filesystem::create_directories(parent); - const auto temporary=parent/(path.filename().string()+".tmp-"+new_id()); + const auto temporary = parent / (path.filename().string() + ".tmp-" + new_id()); try { #ifdef _WIN32 - HANDLE file=CreateFileW(temporary.c_str(),GENERIC_WRITE,0,nullptr,CREATE_NEW,FILE_ATTRIBUTE_NORMAL,nullptr); - require(file!=INVALID_HANDLE_VALUE,"io.create","Cannot create temporary file"); - bool ok=true;std::size_t offset=0; - while(offset(std::min(bytes.size()-offset,1u<<30)); if(!WriteFile(file,bytes.data()+offset,count,&written,nullptr)||written==0){ok=false;break;} offset+=written; } - ok=FlushFileBuffers(file)&&ok;CloseHandle(file); - require(ok,"io.write","Cannot flush temporary file"); - require(MoveFileExW(temporary.c_str(),path.c_str(),MOVEFILE_REPLACE_EXISTING|MOVEFILE_WRITE_THROUGH)!=0,"io.replace","Cannot publish file: "+path.string()); + HANDLE file = CreateFileW(temporary.c_str(), GENERIC_WRITE, 0, nullptr, CREATE_NEW, + FILE_ATTRIBUTE_NORMAL, nullptr); + require(file != INVALID_HANDLE_VALUE, "io.create", "Cannot create temporary file"); + bool ok = true; + std::size_t offset = 0; + while (offset < bytes.size()) { + DWORD written = 0; + const auto count = + static_cast(std::min(bytes.size() - offset, 1u << 30)); + if (!WriteFile(file, bytes.data() + offset, count, &written, nullptr) || written == 0) { + ok = false; + break; + } + offset += written; + } + ok = FlushFileBuffers(file) && ok; + CloseHandle(file); + require(ok, "io.write", "Cannot flush temporary file"); + require(MoveFileExW(temporary.c_str(), path.c_str(), + MOVEFILE_REPLACE_EXISTING | MOVEFILE_WRITE_THROUGH) != 0, + "io.replace", "Cannot publish file: " + path.string()); #else - const int fd=::open(temporary.c_str(),O_WRONLY|O_CREAT|O_EXCL,0644); - require(fd>=0,"io.create","Cannot create temporary file"); - bool ok=true;std::size_t offset=0; - while(offset(count); } - ok=(::fsync(fd)==0)&&ok;const auto closed=::close(fd);ok=ok&&(closed==0); - require(ok,"io.write","Cannot flush temporary file"); - std::filesystem::rename(temporary,path); - const int directory=::open(parent.c_str(),O_RDONLY|O_DIRECTORY); - if(directory>=0){::fsync(directory);::close(directory);} + const int fd = ::open(temporary.c_str(), O_WRONLY | O_CREAT | O_EXCL, 0644); + require(fd >= 0, "io.create", "Cannot create temporary file"); + bool ok = true; + std::size_t offset = 0; + while (offset < bytes.size()) { + const auto count = ::write(fd, bytes.data() + offset, bytes.size() - offset); + if (count < 0 && errno == EINTR) + continue; + if (count <= 0) { + ok = false; + break; + } + offset += static_cast(count); + } + ok = (::fsync(fd) == 0) && ok; + const auto closed = ::close(fd); + ok = ok && (closed == 0); + require(ok, "io.write", "Cannot flush temporary file"); + std::filesystem::rename(temporary, path); + const int directory = ::open(parent.c_str(), O_RDONLY | O_DIRECTORY); + if (directory >= 0) { + ::fsync(directory); + ::close(directory); + } #endif - } catch(...) { std::error_code ignored;std::filesystem::remove(temporary,ignored);throw; } + } catch (...) { + std::error_code ignored; + std::filesystem::remove(temporary, ignored); + throw; + } } -void atomic_write_json(const std::filesystem::path& path,const Json& value) { atomic_write(path,value.dump(2)+"\n"); } -std::filesystem::path project_path(const std::filesystem::path& root,const std::filesystem::path& relative) { - require(!relative.is_absolute(),"path.outside_project","Expected a path relative to the project"); - const auto canonical=std::filesystem::weakly_canonical(root); - const auto target=std::filesystem::weakly_canonical(canonical/relative); - auto a=canonical.begin(),b=target.begin(); - for(;a!=canonical.end();++a,++b) require(b!=target.end()&&*a==*b,"path.outside_project","Path escapes the project root"); +void atomic_write_json(const std::filesystem::path& path, const Json& value) { + atomic_write(path, value.dump(2) + "\n"); +} +std::filesystem::path project_path(const std::filesystem::path& root, + const std::filesystem::path& relative) { + require(!relative.is_absolute(), "path.outside_project", + "Expected a path relative to the project"); + const auto canonical = std::filesystem::weakly_canonical(root); + const auto target = std::filesystem::weakly_canonical(canonical / relative); + auto a = canonical.begin(), b = target.begin(); + for (; a != canonical.end(); ++a, ++b) + require(b != target.end() && *a == *b, "path.outside_project", + "Path escapes the project root"); return target; } -} +} // namespace faset diff --git a/src/core/process.cpp b/src/core/process.cpp new file mode 100644 index 0000000..a02cd0c --- /dev/null +++ b/src/core/process.cpp @@ -0,0 +1,427 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef _WIN32 +#define NOMINMAX +#include +#else +#include +#include +#include +#include +#include +#include +extern char** environ; +#endif + +namespace faset { +namespace { +#ifdef _WIN32 +std::wstring widen(const std::string& value) { + if (value.empty()) + return {}; + int length = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, value.data(), + static_cast(value.size()), nullptr, 0); + if (!length) + throw std::runtime_error("Invalid UTF-8 process argument"); + std::wstring result(length, 0); + MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, value.data(), static_cast(value.size()), + result.data(), length); + return result; +} +std::wstring quote(const std::wstring& value) { + std::wstring result = L"\""; + std::size_t slashes{}; + for (wchar_t c : value) { + if (c == L'\\') { + ++slashes; + continue; + } + if (c == L'\"') { + result.append(slashes * 2 + 1, L'\\'); + result += c; + } else { + result.append(slashes, L'\\'); + result += c; + } + slashes = 0; + } + result.append(slashes * 2, L'\\'); + result += L'\"'; + return result; +} +struct CaseInsensitive { + bool operator()(const std::wstring& a, const std::wstring& b) const { + return _wcsicmp(a.c_str(), b.c_str()) < 0; + } +}; +#else +std::filesystem::path resolve_program(const std::string& name, const std::string& path, + const std::filesystem::path& cwd) { + if (name.find('/') != std::string::npos) { + auto file = std::filesystem::path(name); + if (file.is_relative()) + file = cwd / file; + if (::access(file.c_str(), X_OK) == 0 && !std::filesystem::is_directory(file)) + return std::filesystem::absolute(file); + throw std::runtime_error("Executable is missing or not executable: " + name); + } + std::size_t from{}; + do { + auto end = path.find(':', from); + auto directory = path.substr(from, end == std::string::npos ? end : end - from); + auto file = (directory.empty() ? cwd : std::filesystem::path(directory)) / name; + if (file.is_relative()) + file = cwd / file; + if (::access(file.c_str(), X_OK) == 0 && !std::filesystem::is_directory(file)) + return std::filesystem::absolute(file); + if (end == std::string::npos) + break; + from = end + 1; + } while (true); + throw std::runtime_error("Executable not found on PATH: " + name); +} +#endif +} // namespace +std::filesystem::path find_executable(const std::string& name) { +#ifdef _WIN32 + auto wide = widen(name); + std::vector buffer(32768); + DWORD length = SearchPathW(nullptr, wide.c_str(), L".exe", static_cast(buffer.size()), + buffer.data(), nullptr); + if (length == 0 || length >= buffer.size()) + throw std::runtime_error("Executable not found on PATH: " + name); + return std::filesystem::path(std::wstring(buffer.data(), length)); +#else + const char* path = std::getenv("PATH"); + return resolve_program(name, path ? path : "", std::filesystem::current_path()); +#endif +} +struct Process::Impl { +#ifdef _WIN32 + HANDLE process{}, thread{}, job{}, output{}; +#else + pid_t pid{-1}; + int output{-1}; +#endif + bool running{}; + std::optional exit_code; + ~Impl() { + try { + cancel(); + } catch (...) { + } +#ifdef _WIN32 + if (output) + CloseHandle(output); + if (thread) + CloseHandle(thread); + if (process) + CloseHandle(process); + if (job) + CloseHandle(job); +#else + if (output >= 0) + ::close(output); +#endif + } + ProcessPoll poll() { + std::string text; + char buffer[8192]; +#ifdef _WIN32 + if (output) { + DWORD available{}; + while (PeekNamedPipe(output, nullptr, 0, nullptr, &available, nullptr) && available) { + DWORD read{}; + if (!ReadFile(output, buffer, std::min(available, sizeof(buffer)), &read, + nullptr) || + !read) + break; + text.append(buffer, read); + } + } + if (running && WaitForSingleObject(process, 0) == WAIT_OBJECT_0) { + DWORD code{}; + if (!GetExitCodeProcess(process, &code)) + throw std::runtime_error("Cannot read process exit status"); + running = false; + exit_code = static_cast(code); + } +#else + if (output >= 0) { + while (true) { + auto count = ::read(output, buffer, sizeof(buffer)); + if (count > 0) { + text.append(buffer, static_cast(count)); + continue; + } + if (count < 0 && errno == EINTR) + continue; + if (count == 0) { + ::close(output); + output = -1; + } else if (errno != EAGAIN && errno != EWOULDBLOCK) + throw std::runtime_error("Cannot read child output"); + break; + } + } + if (running) { + int status{}; + pid_t result; + do { + result = ::waitpid(pid, &status, WNOHANG); + } while (result < 0 && errno == EINTR); + if (result == pid) { + running = false; + exit_code = WIFEXITED(status) ? WEXITSTATUS(status) + : WIFSIGNALED(status) ? 128 + WTERMSIG(status) + : 1; + } else if (result < 0) + throw std::runtime_error("Cannot collect child process"); + } +#endif + if (!running) { +#ifdef _WIN32 + DWORD available{}; + while (output && PeekNamedPipe(output, nullptr, 0, nullptr, &available, nullptr) && + available) { + DWORD read{}; + if (!ReadFile(output, buffer, std::min(available, sizeof(buffer)), &read, + nullptr) || + !read) + break; + text.append(buffer, read); + } +#else + if (output >= 0) + while (true) { + auto count = ::read(output, buffer, sizeof(buffer)); + if (count > 0) { + text.append(buffer, static_cast(count)); + continue; + } + if (count < 0 && errno == EINTR) + continue; + if (count == 0) { + ::close(output); + output = -1; + } + break; + } +#endif + } + return {running, exit_code, std::move(text)}; + } + void cancel() { + if (!running) + return; +#ifdef _WIN32 + if (job) + TerminateJobObject(job, 130); + TerminateProcess(process, 130); + WaitForSingleObject(process, INFINITE); + DWORD code{}; + GetExitCodeProcess(process, &code); + exit_code = static_cast(code); + running = false; +#else + ::kill(-pid, SIGTERM); + const auto deadline = std::chrono::steady_clock::now() + std::chrono::milliseconds(200); + while (std::chrono::steady_clock::now() < deadline) { + int status{}; + auto result = ::waitpid(pid, &status, WNOHANG); + if (result == pid) { + running = false; + exit_code = WIFEXITED(status) ? WEXITSTATUS(status) : 128 + WTERMSIG(status); + ::kill(-pid, SIGKILL); + return; + } + if (result < 0 && errno != EINTR) { + running = false; + return; + } + std::this_thread::sleep_for(std::chrono::milliseconds(10)); + } + ::kill(-pid, SIGKILL); + int status{}; + while (::waitpid(pid, &status, 0) < 0 && errno == EINTR) { + } + running = false; + exit_code = 130; +#endif + } +}; +Process::Process(const ProcessOptions& options) : impl_(std::make_unique()) { + if (options.arguments.empty() || options.arguments[0].empty()) + throw std::invalid_argument("Process requires an executable"); + for (const auto& argument : options.arguments) + if (argument.find('\0') != std::string::npos) + throw std::invalid_argument("NUL in process argument"); + auto cwd = options.working_directory.empty() + ? std::filesystem::current_path() + : std::filesystem::absolute(options.working_directory); + if (!std::filesystem::is_directory(cwd)) + throw std::runtime_error("Process working directory does not exist"); +#ifdef _WIN32 + auto program = std::filesystem::path(widen(options.arguments[0])); + if (program.has_parent_path() && program.is_relative()) + program = cwd / program; + auto executable = program.has_parent_path() ? program : find_executable(options.arguments[0]); + std::wstring command; + for (const auto& argument : options.arguments) { + if (!command.empty()) + command += L' '; + command += quote(widen(argument)); + } + std::map environment; + auto block = GetEnvironmentStringsW(); + if (!block) + throw std::runtime_error("Cannot read process environment"); + for (auto entry = block; *entry; entry += wcslen(entry) + 1) { + std::wstring text(entry); + auto equals = text.find(L'=', text[0] == L'=' ? 1 : 0); + if (equals != std::wstring::npos) + environment[text.substr(0, equals)] = text.substr(equals + 1); + } + FreeEnvironmentStringsW(block); + for (auto& [key, value] : options.environment) { + if (key.empty() || key.find('=') != std::string::npos || + key.find('\0') != std::string::npos || value.find('\0') != std::string::npos) + throw std::invalid_argument("Invalid environment entry"); + environment[widen(key)] = widen(value); + } + std::vector env; + for (auto& [key, value] : environment) { + auto item = key + L"=" + value; + env.insert(env.end(), item.begin(), item.end()); + env.push_back(0); + } + env.push_back(0); + SECURITY_ATTRIBUTES security{sizeof(SECURITY_ATTRIBUTES), nullptr, TRUE}; + HANDLE output_write{}, input{}; + if (!CreatePipe(&impl_->output, &output_write, &security, 0)) + throw std::runtime_error("Cannot create process pipe"); + SetHandleInformation(impl_->output, HANDLE_FLAG_INHERIT, 0); + input = CreateFileW(L"NUL", GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, &security, + OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr); + SIZE_T bytes{}; + InitializeProcThreadAttributeList(nullptr, 1, 0, &bytes); + std::vector storage(bytes); + auto* attributes = reinterpret_cast(storage.data()); + bool initialized = InitializeProcThreadAttributeList(attributes, 1, 0, &bytes) != 0; + HANDLE handles[] = {output_write, input}; + bool updated = + initialized && UpdateProcThreadAttribute(attributes, 0, PROC_THREAD_ATTRIBUTE_HANDLE_LIST, + handles, sizeof(handles), nullptr, nullptr) != 0; + STARTUPINFOEXW startup{}; + startup.StartupInfo.cb = sizeof(startup); + startup.StartupInfo.dwFlags = STARTF_USESTDHANDLES; + startup.StartupInfo.hStdOutput = startup.StartupInfo.hStdError = output_write; + startup.StartupInfo.hStdInput = input; + startup.lpAttributeList = attributes; + PROCESS_INFORMATION process{}; + bool launched = + updated && CreateProcessW(executable.c_str(), command.data(), nullptr, nullptr, TRUE, + CREATE_UNICODE_ENVIRONMENT | CREATE_SUSPENDED | + CREATE_NEW_PROCESS_GROUP | EXTENDED_STARTUPINFO_PRESENT, + env.data(), cwd.c_str(), &startup.StartupInfo, &process) != 0; + if (initialized) + DeleteProcThreadAttributeList(attributes); + CloseHandle(output_write); + if (input != INVALID_HANDLE_VALUE) + CloseHandle(input); + if (!launched) + throw std::runtime_error("CreateProcess failed for " + options.arguments[0]); + impl_->process = process.hProcess; + impl_->thread = process.hThread; + impl_->running = true; + impl_->job = CreateJobObjectW(nullptr, nullptr); + if (!impl_->job) + throw std::runtime_error("Cannot create compiler job object"); + JOBOBJECT_EXTENDED_LIMIT_INFORMATION limits{}; + limits.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE; + if (!SetInformationJobObject(impl_->job, JobObjectExtendedLimitInformation, &limits, + sizeof(limits)) || + !AssignProcessToJobObject(impl_->job, impl_->process)) + throw std::runtime_error("Cannot isolate compiler process group"); + if (ResumeThread(impl_->thread) == DWORD(-1)) + throw std::runtime_error("Cannot start compiler process"); +#else + std::map environment; + for (char** item = environ; *item; ++item) { + std::string text(*item); + auto separator = text.find('='); + if (separator != std::string::npos) + environment[text.substr(0, separator)] = text.substr(separator + 1); + } + for (const auto& [key, value] : options.environment) { + if (key.empty() || key.find('=') != std::string::npos || + key.find('\0') != std::string::npos || value.find('\0') != std::string::npos) + throw std::invalid_argument("Invalid environment entry"); + environment[key] = value; + } + auto executable = resolve_program(options.arguments[0], environment["PATH"], cwd); + std::vector env_storage; + std::vector argv, envp; + for (const auto& argument : options.arguments) + argv.push_back(const_cast(argument.c_str())); + argv.push_back(nullptr); + for (const auto& [key, value] : environment) + env_storage.push_back(key + "=" + value); + for (auto& entry : env_storage) + envp.push_back(entry.data()); + envp.push_back(nullptr); + int pipes[2]; + if (::pipe2(pipes, O_CLOEXEC) < 0) + throw std::runtime_error("Cannot create process pipe"); + int input = ::open("/dev/null", O_RDONLY | O_CLOEXEC); + if (input < 0) { + ::close(pipes[0]); + ::close(pipes[1]); + throw std::runtime_error("Cannot open process input"); + } + auto pid = ::fork(); + if (pid == 0) { + ::setpgid(0, 0); + ::close(pipes[0]); + if (::dup2(input, STDIN_FILENO) < 0 || ::dup2(pipes[1], STDOUT_FILENO) < 0 || + ::dup2(pipes[1], STDERR_FILENO) < 0 || ::chdir(cwd.c_str()) < 0) + ::_exit(126); + ::close(input); + ::close(pipes[1]); + ::execve(executable.c_str(), argv.data(), envp.data()); + constexpr char message[] = "Cannot execute child process\n"; + ::write(STDERR_FILENO, message, sizeof(message) - 1); + ::_exit(127); + } + ::close(input); + ::close(pipes[1]); + if (pid < 0) { + ::close(pipes[0]); + throw std::runtime_error("Cannot fork process"); + } + ::setpgid(pid, pid); + impl_->pid = pid; + impl_->output = pipes[0]; + impl_->running = true; + int flags = ::fcntl(pipes[0], F_GETFL, 0); + if (flags < 0 || ::fcntl(pipes[0], F_SETFL, flags | O_NONBLOCK) < 0) + throw std::runtime_error("Cannot configure process output pipe"); +#endif +} +Process::~Process() = default; +Process::Process(Process&&) noexcept = default; +Process& Process::operator=(Process&&) noexcept = default; +ProcessPoll Process::poll() { + return impl_->poll(); +} +void Process::cancel() { + impl_->cancel(); +} +} // namespace faset diff --git a/src/editor/build_service.cpp b/src/editor/build_service.cpp new file mode 100644 index 0000000..8ec51d5 --- /dev/null +++ b/src/editor/build_service.cpp @@ -0,0 +1,747 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace faset::editor { +namespace fs = std::filesystem; +namespace { +struct Cancelled {}; +constexpr std::size_t max_log_bytes = 8 * 1024 * 1024; +void validate_scene(const Json& scene) { + if (!scene.is_object() || scene.value("format", "") != "faset.scene" || + scene.value("version", 0) != 1 || !scene.contains("entities") || + !scene["entities"].is_array()) + throw std::runtime_error("Cook requires a version 1 Faset scene"); + if (!scene.value("instances", Json::array()).empty()) + throw std::runtime_error("Resolve template instances before cooking"); + int dimension = scene.value("dimension", 0); + if (dimension != 2 && dimension != 3) + throw std::runtime_error("Scene dimension must be 2 or 3"); +} +void validate_component_types(const Json& scene, const Json& schema) { + std::map versions; + for (const auto* type : {"faset.transform", "faset.sprite", "faset.mesh", "faset.camera", + "faset.light", "faset.rigid_body_2d", "faset.rigid_body_3d"}) + versions[type] = 1; + for (const auto& type : schema.value("types", Json::array())) { + auto id = type.at("id").get(); + if (versions.contains(id)) + throw std::runtime_error("Gameplay schema duplicates a component type: " + id); + versions[id] = type.value("version", 1); + } + for (const auto& entity : scene.at("entities")) + for (const auto& component : entity.value("components", Json::array())) { + const auto id = component.at("type").get(); + auto found = versions.find(id); + if (found == versions.end()) + throw std::runtime_error("Cannot cook unresolved component type: " + id); + if (component.value("version", 1) != found->second) + throw std::runtime_error("Migrate component '" + id + + "' to the current gameplay schema before cooking"); + } +} +std::set asset_references(const Json& scene) { + std::set result; + for (const auto& entity : scene.at("entities")) + for (const auto& component : entity.value("components", Json::array())) { + const auto type = component.value("type", ""); + if (type != "faset.mesh" && type != "faset.sprite") + continue; + const auto fields = component.value("fields", Json::object()); + auto asset = fields.value(type == "faset.sprite" ? "texture" : "asset", ""); + if (asset.empty() || asset == "builtin:cube" || asset == "builtin:plane") + continue; + if (asset.starts_with("builtin:")) + throw std::runtime_error("Unknown builtin asset: " + asset); + result.insert(asset.substr(0, asset.find('#'))); + } + return result; +} +void copy_required_file(const fs::path& source, const fs::path& target) { + if (!fs::is_regular_file(source) || fs::is_symlink(source)) + throw std::runtime_error("Required package file missing or not a regular file: " + + source.string()); + fs::create_directories(target.parent_path()); + fs::copy_file(source, target, fs::copy_options::overwrite_existing); +} +std::string executable_suffix() { +#ifdef _WIN32 + return ".exe"; +#else + return ""; +#endif +} +fs::path build_executable(const fs::path& build, const std::string& configuration, + const std::string& target) { + for (const auto& root : + {build, build / configuration, build / "bin", build / "bin" / configuration}) { + auto file = root / (target + executable_suffix()); + if (fs::is_regular_file(file)) + return file; + } + throw std::runtime_error("Build did not produce " + target); +} +} // namespace +Json JobStatus::json() const { + return {{"id", id}, {"kind", kind}, {"state", state}, + {"stage", stage}, {"progress", progress}, {"log", log}, + {"error", error}, {"result", result}}; +} +void write_cooked_scene(const fs::path& path, const Json& scene) { + validate_scene(scene); + const auto payload = Json::to_cbor(scene); + std::string bytes = "FASETSCN"; + bytes.reserve(20 + payload.size()); + for (unsigned i = 0; i < 4; ++i) + bytes.push_back(static_cast((std::uint32_t(1) >> (i * 8)) & 255)); + for (unsigned i = 0; i < 8; ++i) + bytes.push_back(static_cast((std::uint64_t(payload.size()) >> (i * 8)) & 255)); + bytes.append(reinterpret_cast(payload.data()), payload.size()); + atomic_write(path, bytes); +} +struct BuildService::Impl { + struct Job { + mutable std::mutex mutex; + JobStatus status; + std::atomic cancelled{}; + std::condition_variable finished; + Json scene; + Json asset_manifests = Json::object(); + fs::path output; + }; + BuildConfig config; + mutable std::mutex mutex; + std::condition_variable condition; + std::map> jobs; + std::deque> queue; + bool stopping{}; + std::thread worker; + explicit Impl(BuildConfig c) : config(std::move(c)) { + if (config.project_root.empty() || config.engine_root.empty()) + throw std::invalid_argument("Build service requires project and engine directories"); + config.project_root = fs::absolute(config.project_root); + config.engine_root = fs::absolute(config.engine_root); + if (config.cache_root.empty()) + config.cache_root = config.project_root / ".faset" / "cache"; + else + config.cache_root = fs::absolute(config.cache_root); + if (config.build_directory.empty()) + config.build_directory = config.project_root / ".faset" / "build"; + else + config.build_directory = fs::absolute(config.build_directory); + if (config.configuration != "Debug" && config.configuration != "Release" && + config.configuration != "RelWithDebInfo") + throw std::invalid_argument("Unsupported build configuration"); + if (config.export_configuration != "Release" && + config.export_configuration != "RelWithDebInfo") + throw std::invalid_argument("Export configuration must be Release or RelWithDebInfo"); + fs::create_directories(config.project_root); + fs::create_directories(config.cache_root); + worker = std::thread([this] { work(); }); + } + ~Impl() { + { + std::lock_guard lock(mutex); + stopping = true; + for (auto& [_, job] : jobs) + job->cancelled = true; + } + condition.notify_all(); + if (worker.joinable()) + worker.join(); + } + std::shared_ptr lookup(const std::string& id) const { + std::lock_guard lock(mutex); + auto it = jobs.find(id); + if (it == jobs.end()) + throw std::out_of_range("Unknown build job: " + id); + return it->second; + } + std::string enqueue(std::string kind, Json scene = {}, fs::path output = {}) { + auto job = std::make_shared(); + job->status.id = new_id(); + job->status.kind = std::move(kind); + job->scene = std::move(scene); + job->output = std::move(output); + { + std::lock_guard lock(mutex); + if (stopping) + throw std::runtime_error("Build service is stopping"); + jobs.emplace(job->status.id, job); + queue.push_back(job); + } + condition.notify_all(); + return job->status.id; + } + void checkpoint(Job& job, std::string stage, double progress) { + if (job.cancelled) + throw Cancelled{}; + std::lock_guard lock(job.mutex); + job.status.stage = std::move(stage); + job.status.progress = progress; + } + void log(Job& job, std::string_view text) { + std::lock_guard lock(job.mutex); + job.status.log.append(text); + if (job.status.log.size() > max_log_bytes) + job.status.log.erase(0, job.status.log.size() - max_log_bytes); + } + std::string run(Job& job, std::vector arguments, const fs::path& cwd) { + if (job.cancelled) + throw Cancelled{}; + std::string description = "$"; + for (const auto& argument : arguments) + description += " " + Json(argument).dump(); + description += '\n'; + log(job, description); + Process process({std::move(arguments), cwd, {}}); + std::string output; + while (true) { + if (job.cancelled) { + process.cancel(); + auto final = process.poll(); + log(job, final.output); + throw Cancelled{}; + } + auto poll = process.poll(); + log(job, poll.output); + output += poll.output; + if (output.size() > max_log_bytes) + output.erase(0, output.size() - max_log_bytes); + if (!poll.running) { + if (poll.exit_code.value_or(1) != 0) + throw std::runtime_error("Process exited with code " + + std::to_string(poll.exit_code.value_or(1)) + + "; see job log"); + return output; + } + std::this_thread::sleep_for(std::chrono::milliseconds(15)); + } + } + void validate_assets(const Json& scene) { + assets::AssetStore pipeline(config.cache_root); + for (const auto& id : asset_references(scene)) + pipeline.load_asset(id); + } + Json build(Job& job, bool exporting = false) { + const auto& configuration = exporting ? config.export_configuration : config.configuration; + const auto native_directory = config.build_directory / configuration; + checkpoint(job, "Configuring C++ gameplay", .05); + if (!fs::is_regular_file(config.project_root / "Scripts" / "Gameplay.cpp") || + !fs::is_regular_file(config.project_root / "Scripts" / "Gameplay.hpp")) + throw std::runtime_error("Project Scripts/Gameplay.cpp and Gameplay.hpp are required; " + "create a project scaffold first"); + fs::create_directories(native_directory); + std::vector arguments = {config.cmake, + "-S", + config.engine_root.string(), + "-B", + native_directory.string(), + "-G", + config.generator, + "-DCMAKE_BUILD_TYPE=" + configuration, + "-DBUILD_TESTING=OFF", + "-DFASET_BUILD_EDITOR=OFF", + "-DFASET_BUILD_RENDERER=ON", + "-DFASET_BUILD_RUNTIME=ON", + "-DFASET_BUILD_ASSETS=ON", + "-DFASET_GAMEPLAY_SOURCE_DIR=" + + (config.project_root / "Scripts").string()}; + bool compiler_overridden = false; + for (const auto& arg : config.configure_arguments) + if (arg.starts_with("-DCMAKE_CXX_COMPILER=")) + compiler_overridden = true; + if (!compiler_overridden) { +#ifdef _WIN32 + auto compiler = find_executable("clang-cl"); + arguments.push_back("-DCMAKE_C_COMPILER=" + compiler.string()); + arguments.push_back("-DCMAKE_CXX_COMPILER=" + compiler.string()); +#else + arguments.push_back("-DCMAKE_C_COMPILER=" + find_executable("clang").string()); + arguments.push_back("-DCMAKE_CXX_COMPILER=" + find_executable("clang++").string()); +#endif + } + arguments.insert(arguments.end(), config.configure_arguments.begin(), + config.configure_arguments.end()); + arguments.push_back("-DCMAKE_BUILD_TYPE=" + configuration); + run(job, std::move(arguments), config.project_root); + checkpoint(job, "Compiling and linking Player", .25); + run(job, + {config.cmake, "--build", native_directory.string(), "--config", configuration, + "--parallel", "4", "--target", "faset_player", "faset_schema_exporter"}, + config.project_root); + checkpoint(job, "Exporting gameplay schema", .58); + auto player = build_executable(native_directory, configuration, "faset_player"); + auto exporter = build_executable(native_directory, configuration, "faset_schema_exporter"); + const auto staging = config.cache_root / "builds" / (".staging-" + job.status.id); + const auto generation = config.cache_root / "builds" / job.status.id; + fs::create_directories(staging); + try { + const auto schema_file = staging / "schema.json"; + run(job, {exporter.string(), "--output", schema_file.string()}, config.project_root); + auto schema = read_json(schema_file); + if (schema.value("format", "") != "faset.schema" || schema.value("version", 0) != 1 || + !schema.contains("types") || !schema.at("types").is_array()) + throw std::runtime_error("SchemaExporter returned an invalid manifest"); + std::string fingerprint = sha256_file(player) + sha256_file(exporter) + + read_text(native_directory / "CMakeCache.txt"); + for (const auto& file : {"Gameplay.cpp", "Gameplay.hpp"}) + fingerprint += read_text(config.project_root / "Scripts" / file); + fingerprint = sha256(fingerprint); + schema["build_fingerprint"] = fingerprint; + atomic_write_json(schema_file, schema); + copy_required_file(player, staging / ("faset_player" + executable_suffix())); + copy_required_file(exporter, staging / ("faset_schema_exporter" + executable_suffix())); + for (const auto* file : {"vertexMain.spv", "fragmentMain.spv", "shadowMain.spv"}) + copy_required_file(native_directory / "shaders" / file, staging / "shaders" / file); + copy_runtime_libraries(job, player, staging, native_directory, configuration); + Json manifest{{"format", "faset.build"}, + {"version", 1}, + {"id", job.status.id}, + {"fingerprint", fingerprint}, + {"configuration", configuration}, + {"player", "faset_player" + executable_suffix()}, + {"schema", "schema.json"}}; + atomic_write_json(staging / "manifest.json", manifest); + checkpoint(job, "Publishing build generation", .68); + fs::rename(staging, generation); + atomic_write_json(config.cache_root / "last_build.json", + {{"generation", job.status.id}, {"fingerprint", fingerprint}}); + return {{"generation", job.status.id}, + {"directory", generation.string()}, + {"build_directory", native_directory.string()}, + {"configuration", configuration}, + {"player", (generation / ("faset_player" + executable_suffix())).string()}, + {"schema", (generation / "schema.json").string()}, + {"fingerprint", fingerprint}}; + } catch (...) { + std::error_code error; + fs::remove_all(staging, error); + throw; + } + } + void copy_runtime_libraries(Job& job, const fs::path& executable, const fs::path& destination, + const fs::path& native_directory, + const std::string& configuration) { +#ifdef _WIN32 + // Libraries produced by the selected toolchain are copied beside the executable. + // System DLLs (including Vulkan) remain platform prerequisites. + for (const auto& root : + {executable.parent_path(), native_directory, native_directory / configuration}) + if (fs::is_directory(root)) + for (const auto& entry : fs::directory_iterator(root)) { + auto extension = entry.path().extension().string(); + for (auto& c : extension) + c = static_cast(std::tolower(static_cast(c))); + if (entry.is_regular_file() && extension == ".dll") + copy_required_file(entry.path(), destination / entry.path().filename()); + } + // The actual packaged executable is launched before publication to reject missing imports. + (void)job; +#else + const auto output = + run(job, {find_executable("ldd").string(), executable.string()}, config.project_root); + if (output.find("not found") != std::string::npos) + throw std::runtime_error("Player has unresolved shared library dependencies"); + // SDL/physics/gameplay are linked statically. glibc/libstdc++/Vulkan are the host baseline. + // Refuse an unexpected private DSO rather than silently publish a non-portable package. + std::size_t begin{}; + while (begin < output.size()) { + auto end = output.find('\n', begin); + auto line = output.substr(begin, end == std::string::npos ? end : end - begin); + auto arrow = line.find("=> "); + if (arrow != std::string::npos) { + auto name = line.substr(0, arrow); + name.erase(0, name.find_first_not_of(" \t")); + auto path_start = arrow + 3; + auto path_end = line.find(" (", path_start); + auto path = line.substr(path_start, path_end - path_start); + if (!path.empty() && path[0] == '/' && !path.starts_with("/lib/") && + !path.starts_with("/lib64/") && !path.starts_with("/usr/lib/") && + !path.starts_with("/usr/lib64/")) + throw std::runtime_error( + "Private shared library needs an explicit package rule: " + path); + } + if (end == std::string::npos) + break; + begin = end + 1; + } + (void)destination; + (void)native_directory; + (void)configuration; +#endif + } + Json cook(Job& job) { + checkpoint(job, "Validating scene and assets", .1); + validate_scene(job.scene); + validate_assets(job.scene); + Json schema = Json::object(); + if (fs::exists(config.cache_root / "last_build.json")) { + auto pointer = read_json(config.cache_root / "last_build.json"); + auto schema_path = project_path( + config.cache_root, + fs::path("builds") / pointer.at("generation").get() / "schema.json"); + schema = read_json(schema_path); + } + validate_component_types(job.scene, schema); + auto source_hash = sha256(job.scene.dump()); + auto schema_fingerprint = schema.value("build_fingerprint", std::string("builtin-v1")); + auto digest = sha256(source_hash + schema_fingerprint); + auto directory = config.cache_root / "cooked" / digest; + auto staging = config.cache_root / "cooked" / (".staging-" + job.status.id); + fs::create_directories(staging); + try { + checkpoint(job, "Writing cooked scene", .6); + write_cooked_scene(staging / "scene.fscene", job.scene); + Json manifest{{"format", "faset.cooked-scene"}, + {"version", 1}, + {"scene", job.scene.value("id", "")}, + {"source_hash", source_hash}, + {"schema_fingerprint", schema_fingerprint}, + {"sha256", sha256_file(staging / "scene.fscene")}}; + atomic_write_json(staging / "manifest.json", manifest); + checkpoint(job, "Publishing cooked scene", .9); + if (fs::exists(directory)) { + if (read_json(directory / "manifest.json") != manifest || + sha256_file(directory / "scene.fscene") != + manifest.at("sha256").get()) + throw std::runtime_error("Existing cooked generation is corrupt"); + fs::remove_all(staging); + } else + fs::rename(staging, directory); + atomic_write_json(config.cache_root / "last_cook.json", {{"generation", digest}}); + return {{"generation", digest}, + {"scene", (directory / "scene.fscene").string()}, + {"directory", directory.string()}}; + } catch (...) { + std::error_code error; + fs::remove_all(staging, error); + throw; + } + } + void package_notices(const fs::path& destination, const fs::path& native_directory) { + fs::create_directories(destination); + auto lock = read_json(config.engine_root / "dependencies.lock.json"); + const std::vector runtime_dependencies = {"sdl3", "entt", "box2d", + "box3d", "json", "stb"}; + Json used = Json::object(); + for (const auto& name : runtime_dependencies) { + std::vector roots = {native_directory / "_deps" / (name + "-src"), + config.engine_root / ".cache" / "deps-src" / name}; + bool copied{}; + for (const auto& source : roots) { + if (!fs::is_directory(source)) + continue; + for (const auto& entry : fs::directory_iterator(source)) { + if (!entry.is_regular_file()) + continue; + auto filename = entry.path().filename().string(); + std::string upper = filename; + for (auto& c : upper) + c = static_cast(std::toupper(static_cast(c))); + if (upper.starts_with("LICENSE") || upper.starts_with("COPYING") || + upper.starts_with("NOTICE")) { + copy_required_file(entry.path(), destination / name / filename); + copied = true; + } + } + if (copied) + break; + } + if (!copied) + throw std::runtime_error("Cannot package required license notices for " + name); + used[name] = lock.at("dependencies").at(name); + } + atomic_write_json(destination / "dependencies.json", used); + if (fs::is_regular_file(config.engine_root / "LICENSE")) + copy_required_file(config.engine_root / "LICENSE", destination / "Faset-LICENSE"); + atomic_write(destination / "Faset-NOTICE.txt", + "Faset Engine\nhttps://github.com/emil28092005/Faset_Engine\nSee the source " + "repository for the current license status of Faset's own code.\nThird-party " + "license texts are included in the adjacent directories.\n"); + } + void package_assets(Job& job, const fs::path& destination) { + assets::AssetStore packaged(destination); + for (const auto& id : asset_references(job.scene)) { + if (job.cancelled) + throw Cancelled{}; + auto manifest = job.asset_manifests.at(id); + auto generation = manifest.at("generation").get(); + auto source_directory = project_path(config.cache_root, fs::path("assets") / id / + "generations" / generation); + auto target = destination / "assets" / id / "generations" / generation; + for (const auto& file : manifest.at("files")) { + auto relative = fs::path(file.at("path").get()); + copy_required_file(project_path(source_directory, relative), + project_path(target, relative)); + } + manifest["source"] = ""; + if (manifest.contains("payload_source")) + manifest["payload_source"] = ""; + atomic_write_json(target / "manifest.json", manifest); + atomic_write_json( + destination / "assets" / id / "current.json", + {{"schema_version", 1}, {"generation", generation}, {"source", ""}}); + packaged.load_asset(id); + } + } + Json export_game(Job& job) { + validate_scene(job.scene); + validate_assets(job.scene); + assets::AssetStore source(config.cache_root); + for (const auto& id : asset_references(job.scene)) + job.asset_manifests[id] = source.current_manifest(id); + const auto built = build(job, true); + validate_component_types(job.scene, read_json(built.at("schema").get())); + auto output = fs::absolute(job.output); + if (output.empty()) + throw std::runtime_error("An export destination is required"); + fs::create_directories(output / "generations"); + auto staging = output / (".staging-" + job.status.id); + auto generation = output / "generations" / job.status.id; + fs::create_directories(staging); + try { + checkpoint(job, "Cooking export snapshot", .72); + write_cooked_scene(staging / "scene.fscene", job.scene); + auto build_directory = fs::path(built.at("directory").get()); + copy_required_file(build_directory / ("faset_player" + executable_suffix()), + staging / ("faset_player" + executable_suffix())); + for (const auto* shader : {"vertexMain.spv", "fragmentMain.spv", "shadowMain.spv"}) + copy_required_file(build_directory / "shaders" / shader, + staging / "shaders" / shader); + for (const auto& entry : fs::directory_iterator(build_directory)) { + auto extension = entry.path().extension().string(); + for (auto& c : extension) + c = static_cast(std::tolower(static_cast(c))); + if (entry.is_regular_file() && extension == ".dll") + copy_required_file(entry.path(), staging / entry.path().filename()); + } + checkpoint(job, "Packaging assets and notices", .80); + package_assets(job, staging); + package_notices(staging / "Notices", built.at("build_directory").get()); + atomic_write( + staging / "README.txt", + "Run faset_player" + executable_suffix() + + " to start this game.\nThe executable loads scene.fscene and assets beside " + "it.\nKeep shaders/, assets/, and Notices/ with the executable.\nA compatible " + "Vulkan 1.3 driver and the supported OS runtime are required.\n"); +#ifdef _WIN32 + atomic_write(staging / "Windows-Runtime.txt", + "Install the Microsoft Visual C++ x64 Redistributable if Windows reports " + "a missing MSVCP140 or VCRUNTIME140 DLL.\nOfficial installer: " + "https://aka.ms/vc14/vc_redist.x64.exe\nThe Vulkan loader and GPU driver " + "must also be installed.\n"); +#endif + checkpoint(job, "Validating packaged Player", .90); + auto validation_output = + run(job, + {(staging / ("faset_player" + executable_suffix())).string(), "--validate", + "--scene", (staging / "scene.fscene").string(), "--assets", staging.string()}, + staging); + Json files = Json::array(); + for (const auto& entry : fs::recursive_directory_iterator(staging)) { + if (entry.is_symlink()) + throw std::runtime_error("Export contains a symlink"); + if (entry.is_regular_file()) + files.push_back( + {{"path", entry.path().lexically_relative(staging).generic_string()}, + {"sha256", sha256_file(entry.path())}, + {"size", entry.file_size()}}); + } + Json manifest{{"format", "faset.export"}, + {"version", 1}, + {"generation", job.status.id}, + {"build_fingerprint", built.at("fingerprint")}, + {"scene_hash", sha256(job.scene.dump())}, + {"asset_generations", Json::object()}, + {"configuration", built.at("configuration")}, + {"executable", "faset_player" + executable_suffix()}, + {"files", files}}; + manifest["units"] = { + {"distance", "metre"}, {"angle", "radian"}, {"coordinates", "right-handed Y-up"}}; + manifest["simulation"] = {{"fixed_delta", 1.0 / 60.0}, + {"max_catch_up_ticks", 4}, + {"physics_substeps", 4}, + {"gravity", {0, -9.81, 0}}}; + if (job.scene.contains("simulation")) + manifest["simulation"].update(job.scene.at("simulation")); + manifest["renderer_profile"] = { + {"api", "Vulkan 1.3"}, + {"required_features", {"dynamicRendering", "synchronization2"}}, + {"materials", {"base-color factor and texture", "metallic and roughness factors"}}, + {"texture_sampling", "linear clamp, one mip level"}, + {"shadow_map", {{"resolution", 1024}, {"world_extent", 40}}}, + {"unsupported_material_features", + {"normal maps", "metallic-roughness maps", "emissive and occlusion maps", + "alpha mode selection", "unlit mode", "per-material face culling"}}}; + manifest["validation_log"] = validation_output; + for (const auto& [id, asset] : job.asset_manifests.items()) + manifest["asset_generations"][id] = asset.at("generation"); +#ifdef _WIN32 + manifest["platform"] = "windows"; + manifest["prerequisites"] = { + "Windows x64", "Vulkan 1.3 driver", + "Microsoft Visual C++ x64 Redistributable (Visual Studio 2022 or newer)"}; +#else + manifest["platform"] = "linux"; + manifest["prerequisites"] = {"Linux x86_64", "Vulkan 1.3 driver", + "Compatible glibc and libstdc++ runtime"}; +#endif + atomic_write_json(staging / "manifest.json", manifest); + checkpoint(job, "Publishing export generation", .98); + fs::rename(staging, generation); + atomic_write_json(output / "current.json", + {{"format", "faset.export-pointer"}, + {"version", 1}, + {"generation", job.status.id}, + {"directory", "generations/" + job.status.id}}); + return {{"directory", generation.string()}, + {"executable", (generation / ("faset_player" + executable_suffix())).string()}, + {"manifest", (generation / "manifest.json").string()}, + {"generation", job.status.id}, + {"build", built}, + {"schema", built.at("schema")}, + {"player", built.at("player")}, + {"build_directory", built.at("build_directory")}, + {"configuration", built.at("configuration")}}; + } catch (...) { + std::error_code error; + fs::remove_all(staging, error); + throw; + } + } + void work() { + while (true) { + std::shared_ptr job; + { + std::unique_lock lock(mutex); + condition.wait(lock, [&] { return stopping || !queue.empty(); }); + if (queue.empty()) { + if (stopping) + return; + continue; + } + job = queue.front(); + queue.pop_front(); + } + { + std::lock_guard lock(job->mutex); + job->status.state = "running"; + } + try { + if (job->cancelled) + throw Cancelled{}; + Json result; + if (job->status.kind == "build") + result = build(*job); + else if (job->status.kind == "cook") + result = cook(*job); + else + result = export_game(*job); + std::lock_guard lock(job->mutex); + job->status.state = "succeeded"; + job->status.stage = "Complete"; + job->status.progress = 1; + job->status.result = std::move(result); + } catch (const Cancelled&) { + std::lock_guard lock(job->mutex); + job->status.state = "cancelled"; + job->status.stage = "Cancelled"; + job->status.error = + "Job cancelled; previous published generations remain available"; + } catch (const std::exception& error) { + std::lock_guard lock(job->mutex); + job->status.state = "failed"; + job->status.stage = "Failed"; + job->status.error = error.what(); + } + job->finished.notify_all(); + condition.notify_all(); + } + } +}; +BuildService::BuildService(BuildConfig config) : impl_(std::make_unique(std::move(config))) {} +BuildService::~BuildService() = default; +const BuildConfig& BuildService::config() const { + return impl_->config; +} +void BuildService::scaffold(const std::string& name, int dimension) { + if (name.empty() || (dimension != 2 && dimension != 3)) + throw std::invalid_argument("Project name and dimension 2 or 3 required"); + const auto& c = impl_->config; + fs::create_directories(c.project_root / "Scripts"); + fs::create_directories(c.project_root / "Scenes"); + fs::create_directories(c.project_root / "Assets"); + for (const auto* file : {"Gameplay.cpp", "Gameplay.hpp"}) { + auto target = c.project_root / "Scripts" / file; + if (!fs::exists(target)) { + auto source = c.engine_root / "tools" / "project_templates" / file; + copy_required_file(source, target); + } + } + auto project = c.project_root / "project.faset.json"; + if (!fs::exists(project)) + atomic_write_json(project, {{"format", "faset.project"}, + {"version", 1}, + {"id", new_id()}, + {"name", name}, + {"dimension", dimension}, + {"start_scene", "Scenes/main.scene.json"}}); + if (!fs::exists(c.project_root / ".gitignore")) + atomic_write(c.project_root / ".gitignore", ".faset/\nExports/\n"); +} +std::string BuildService::start_build() { + return impl_->enqueue("build"); +} +std::string BuildService::start_cook(Json scene) { + return impl_->enqueue("cook", std::move(scene)); +} +std::string BuildService::start_export(Json scene, const fs::path& output) { + if (output.empty()) + throw std::invalid_argument("Export output directory is required"); + return impl_->enqueue("export", std::move(scene), output); +} +JobStatus BuildService::job(const std::string& id) const { + auto value = impl_->lookup(id); + std::lock_guard lock(value->mutex); + return value->status; +} +std::vector BuildService::jobs() const { + std::vector> values; + { + std::lock_guard lock(impl_->mutex); + for (auto& [_, value] : impl_->jobs) + values.push_back(value); + } + std::vector result; + for (auto& value : values) { + std::lock_guard lock(value->mutex); + result.push_back(value->status); + } + return result; +} +void BuildService::cancel(const std::string& id) { + impl_->lookup(id)->cancelled = true; + impl_->condition.notify_all(); +} +JobStatus BuildService::wait(const std::string& id) { + auto value = impl_->lookup(id); + std::unique_lock lock(value->mutex); + value->finished.wait(lock, [&] { return value->status.finished(); }); + return value->status; +} +} // namespace faset::editor diff --git a/src/editor/commands.cpp b/src/editor/commands.cpp new file mode 100644 index 0000000..8f6be50 --- /dev/null +++ b/src/editor/commands.cpp @@ -0,0 +1,157 @@ +#include +#include +#include +#include +#include + +namespace faset::editor { +Json Commands::object_schema(Json properties, Json required) { + return {{"type", "object"}, + {"properties", std::move(properties)}, + {"required", std::move(required)}, + {"additionalProperties", false}}; +} +void Commands::add(std::string name, std::string description, Json schema, Handler handler, + bool read_only) { + require(!commands_.contains(name), "command.duplicate", "Command already registered: " + name); + Json descriptor = {{"name", name}, + {"description", std::move(description)}, + {"inputSchema", std::move(schema)}, + {"annotations", {{"readOnlyHint", read_only}, {"openWorldHint", false}}}}; + commands_.emplace(std::move(name), Command{std::move(descriptor), std::move(handler)}); +} +void Commands::remove(const std::string& name) { + commands_.erase(name); +} +Json Commands::list() const { + Json result = Json::array(); + for (const auto& [name, command] : commands_) + result.push_back(command.descriptor); + return result; +} +Json Commands::call(const std::string& name, const Json& arguments) { + const auto found = commands_.find(name); + require(found != commands_.end(), "command.unknown", "Unknown editor command: " + name); + require(arguments.is_object(), "arguments.object", "Tool arguments must be an object"); + const auto& schema = found->second.descriptor["inputSchema"]; + for (const auto& key : schema.value("required", Json::array())) + require(arguments.contains(key.get()), "arguments.required", + "Missing argument: " + key.get()); + for (const auto& [key, value] : arguments.items()) { + require(schema["properties"].contains(key), "arguments.unknown", + "Unknown argument: " + key); + const auto& property = schema["properties"][key]; + const auto type = property.value("type", std::string()); + const bool valid = + type.empty() || (type == "string" && value.is_string()) || + (type == "boolean" && value.is_boolean()) || (type == "number" && value.is_number()) || + (type == "integer" && value.is_number_integer()) || + (type == "object" && value.is_object()) || (type == "array" && value.is_array()); + require(valid, "arguments.type", "Invalid type for argument: " + key); + if (property.contains("enum")) + require(std::find(property["enum"].begin(), property["enum"].end(), value) != + property["enum"].end(), + "arguments.enum", "Unsupported value for argument: " + key); + if (property.contains("maximum") && value.is_number()) + require(value.get() <= property["maximum"].get(), "arguments.maximum", + "Argument exceeds its maximum: " + key); + if (property.contains("minimum") && value.is_number()) + require(value.get() >= property["minimum"].get(), "arguments.minimum", + "Argument is below its minimum: " + key); + } + try { + return found->second.handler(arguments); + } catch (const Json::exception& error) { + throw Error("arguments.invalid", "Invalid command data", {{"reason", error.what()}}); + } +} +Json Commands::resolved_scene(const std::string& id) const { + const auto result = authoring::resolve_templates( + authoring_.query(id).at("scene"), authoring_.schemas(), + [&](const std::string& path) { return read_json(project_path(authoring_.root(), path)); }); + return {{"scene", result.scene}, {"conflicts", result.conflicts}}; +} +Commands::Commands(authoring::AuthoringService& authoring) : authoring_(authoring) { + const Json text = {{"type", "string"}}, integer = {{"type", "integer"}, {"minimum", 0}}, + boolean = {{"type", "boolean"}}; + add( + "faset_documents", + "List open authoring documents and their revisions. This does not inspect a running game.", + object_schema(Json::object()), + [&](const Json&) { return Json{{"documents", authoring_.documents()}}; }, true); + add("faset_document_create", + "Create an unsaved 2D or 3D scene. Returns its persistent document ID and revision.", + object_schema({{"name", text}, {"dimension", integer}}, {"name", "dimension"}), + [&](const Json& args) { return authoring_.create(args.at("name"), args.at("dimension")); }); + add("faset_document_open", + "Open a scene relative to the project. Set recover=true to load its saved recovery " + "journal.", + object_schema({{"path", text}, {"recover", boolean}}, {"path"}), [&](const Json& args) { + return authoring_.open(args.at("path").get(), + args.value("recover", false)); + }); + add( + "faset_document_query", + "Read an authoring scene, persistent IDs, dirty state and revision. No Player or runtime " + "state is exposed.", + object_schema({{"document", text}}, {"document"}), + [&](const Json& args) { return authoring_.query(args.at("document")); }, true); + add("faset_document_save", + "Atomically save an authoring document. Refuses to overwrite an externally modified file.", + object_schema({{"document", text}, {"path", text}}, {"document"}), [&](const Json& args) { + return authoring_.save(args.at("document"), args.value("path", std::string())); + }); + add( + "faset_schema", + "Inspect registered component TypeIds, stable FieldIds, defaults and constraints.", + object_schema(Json::object()), [&](const Json&) { return authoring_.schemas().manifest(); }, + true); + add("faset_scene_edit", + "Apply one atomic authoring batch with optimistic revision checking and one Undo step. " + "Operations: entity.create/rename/delete/duplicate/reparent; component.add/remove/set; " + "scene.rename; template.instance/override/revert/suppress/add/reparent. Use persistent IDs " + "from document_query and schema. An idempotency_key retries the same payload in this " + "session.", + object_schema({{"document", text}, + {"revision", integer}, + {"operations", {{"type", "array"}, {"items", {{"type", "object"}}}}}, + {"idempotency_key", text}}, + {"document", "revision", "operations"}), + [&](const Json& args) { + return authoring_.transact(args.at("document"), args.at("revision"), + args.at("operations"), + args.value("idempotency_key", std::string())); + }); + add("faset_undo", "Undo one authoring transaction. Requires the current document revision.", + object_schema({{"document", text}, {"revision", integer}}, {"document", "revision"}), + [&](const Json& args) { + return authoring_.undo(args.at("document"), args.at("revision")); + }); + add("faset_redo", "Redo one authoring transaction. Requires the current document revision.", + object_schema({{"document", text}, {"revision", integer}}, {"document", "revision"}), + [&](const Json& args) { + return authoring_.redo(args.at("document"), args.at("revision")); + }); + add( + "faset_template_preview", + "Resolve authoring templates and report conflicts without changing source documents. This " + "is not a live game query.", + object_schema({{"document", text}}, {"document"}), + [&](const Json& args) { return resolved_scene(args.at("document")); }, true); + add("faset_recovery_restore", + "Restore a recovery journal, including an unsaved new scene. If the document is already " + "open, pass its current revision. External file changes are never overwritten.", + object_schema({{"document", text}, {"revision", integer}}, {"document"}), + [&](const Json& args) { + return authoring_.recover( + args.at("document"), + args.contains("revision") + ? std::optional(args.at("revision").get()) + : std::nullopt); + }); + add( + "faset_recovery_list", "List document recovery records in this project.", + object_schema(Json::object()), + [&](const Json&) { return Json{{"recovery", authoring_.recovery_documents()}}; }, true); +} +} // namespace faset::editor diff --git a/src/editor/editor_ui.cpp b/src/editor/editor_ui.cpp new file mode 100644 index 0000000..d137272 --- /dev/null +++ b/src/editor/editor_ui.cpp @@ -0,0 +1,1553 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace faset::editor { +namespace { +using render::Mat4; +using render::Vec3; +using ui::Kind; +using ui::Widget; +float dot(Vec3 a, Vec3 b) { + return a[0] * b[0] + a[1] * b[1] + a[2] * b[2]; +} +Vec3 add(Vec3 a, Vec3 b) { + for (int i = 0; i < 3; ++i) + a[i] += b[i]; + return a; +} +Vec3 sub(Vec3 a, Vec3 b) { + for (int i = 0; i < 3; ++i) + a[i] -= b[i]; + return a; +} +Vec3 mul(Vec3 a, float s) { + for (auto& x : a) + x *= s; + return a; +} +Vec3 cross(Vec3 a, Vec3 b) { + return {a[1] * b[2] - a[2] * b[1], a[2] * b[0] - a[0] * b[2], a[0] * b[1] - a[1] * b[0]}; +} +Vec3 normalize(Vec3 a) { + return mul(a, 1 / std::max(.000001f, std::sqrt(dot(a, a)))); +} +Vec3 point(const Mat4& m, Vec3 p) { + return {m[0] * p[0] + m[4] * p[1] + m[8] * p[2] + m[12], + m[1] * p[0] + m[5] * p[1] + m[9] * p[2] + m[13], + m[2] * p[0] + m[6] * p[1] + m[10] * p[2] + m[14]}; +} +Vec3 vector(const Mat4& m, Vec3 p) { + return {m[0] * p[0] + m[4] * p[1] + m[8] * p[2], m[1] * p[0] + m[5] * p[1] + m[9] * p[2], + m[2] * p[0] + m[6] * p[1] + m[10] * p[2]}; +} +bool inverse(const Mat4& m, Mat4& out) { + double a[4][8]{}; + for (int r = 0; r < 4; ++r) { + for (int c = 0; c < 4; ++c) + a[r][c] = m[c * 4 + r]; + a[r][r + 4] = 1; + } + for (int c = 0; c < 4; ++c) { + int pivot = c; + for (int r = c + 1; r < 4; ++r) + if (std::abs(a[r][c]) > std::abs(a[pivot][c])) + pivot = r; + if (std::abs(a[pivot][c]) < 1e-10) + return false; + for (int j = 0; j < 8; ++j) + std::swap(a[c][j], a[pivot][j]); + const auto d = a[c][c]; + for (auto& v : a[c]) + v /= d; + for (int r = 0; r < 4; ++r) + if (r != c) { + const auto f = a[r][c]; + for (int j = 0; j < 8; ++j) + a[r][j] -= f * a[c][j]; + } + } + for (int r = 0; r < 4; ++r) + for (int c = 0; c < 4; ++c) + out[c * 4 + r] = float(a[r][c + 4]); + return true; +} +Vec3 homogeneous(const Mat4& m, float x, float y, float z) { + const auto w = m[3] * x + m[7] * y + m[11] * z + m[15]; + if (std::abs(w) < 1e-8f) + return {}; + return {(m[0] * x + m[4] * y + m[8] * z + m[12]) / w, + (m[1] * x + m[5] * y + m[9] * z + m[13]) / w, + (m[2] * x + m[6] * y + m[10] * z + m[14]) / w}; +} +const Json* entity(const Json& scene, const std::string& id) { + for (const auto& e : scene.at("entities")) + if (e.at("id") == id) + return &e; + return nullptr; +} +const Json* component(const Json& e, const std::string& type) { + for (const auto& c : e.at("components")) + if (c.at("type") == type) + return &c; + return nullptr; +} +Vec3 vec(const Json& j, Vec3 fallback = {}) { + if (!j.is_array() || j.size() < 3) + return fallback; + for (int i = 0; i < 3; ++i) + fallback[i] = j[i].get(); + return fallback; +} +Mat4 world(const Json& scene, const Json& e, int depth = 0) { + if (depth > 256) + return render::identity; + Mat4 local = render::identity; + if (auto* t = component(e, "faset.transform")) { + const auto& f = t->at("fields"); + local = + render::transform(vec(f.value("position", Json{})), vec(f.value("rotation", Json{})), + vec(f.value("scale", Json{}), {1, 1, 1})); + } + if (e.contains("parent") && e["parent"].is_string()) + if (auto* p = entity(scene, e["parent"].get())) + return render::multiply(world(scene, *p, depth + 1), local); + return local; +} +bool ray_triangle(Vec3 origin, Vec3 direction, Vec3 a, Vec3 b, Vec3 c, float& distance) { + const auto e1 = sub(b, a), e2 = sub(c, a), h = cross(direction, e2); + const auto d = dot(e1, h); + if (std::abs(d) < 1e-7f) + return false; + const auto s = sub(origin, a); + const auto u = dot(s, h) / d; + if (u < 0 || u > 1) + return false; + const auto q = cross(s, e1); + const auto v = dot(direction, q) / d; + if (v < 0 || u + v > 1) + return false; + const auto t = dot(e2, q) / d; + if (t < 0 || t >= distance) + return false; + distance = t; + return true; +} +void trim_children(Widget& w, const std::set& keep) { + std::erase_if(w.children, [&](const auto& child) { return !keep.contains(child->id); }); +} +void label(Widget& p, const std::string& id, const std::string& value, float width = -1) { + auto& w = p.add(Kind::Label, id, value); + w.layout.width = width; +} +} // namespace +struct EditorUI::Impl { + Session& session; + render::Renderer& renderer; + ui::Context ui; + ui::DockLayout dock; + player::SceneView view; + render::Snapshot rendered; + std::string picks_key; + std::string document, selected, source_file, asset_filter, + active_bottom = "assets", menu, command_name = "faset_documents", status = "Ready", + gizmo_mode = "Move"; + Json current, resolved, files = Json::array(), assets = Json::array(), schemas = Json::object(), + recovery = Json::array(); + std::uint64_t shown_revision = std::numeric_limits::max(); + std::map edit_revisions; + std::map preview_fields; + std::filesystem::path layout_path; + bool palette = false, component_menu = false, assets_dirty = true, paused = false; + float yaw = .65f, pitch = .42f, distance = 12, ortho = 12, mouse_x = 0, mouse_y = 0, last_x = 0, + last_y = 0; + Vec3 target{}; + int camera_drag = 0, gizmo_axis = -1; + float gizmo_down_x = 0, gizmo_down_y = 0; + Json gizmo_original; + std::uint64_t gizmo_revision = 0; + std::string gizmo_component; + ui::Rect viewport; + Vec3 gizmo_origin{}; + render::Vec2 gizmo_drag_start{}, gizmo_drag_end{}; + float gizmo_world_length = 1; + std::array gizmo_screen{}; + bool gizmo_valid = false; + struct Pick { + std::string id; + render::DrawItem item; + }; + std::vector picks; + std::chrono::steady_clock::time_point last_assets{}; + Impl(Session& s, render::Renderer& r, const std::filesystem::path& font, + const std::filesystem::path& styles) + : session(s), renderer(r), ui(font), view(s.config().project_root / ".faset/cache") { + ui.set_theme(ui::Theme::load(styles)); + ui.apply_layout(read_json(styles.parent_path() / "editor-layout.json")); + layout_path = session.config().project_root / ".faset/editor-layout.json"; + dock.move("assets", "bottom", 0); + dock.move("console", "bottom", 1); + dock.move("jobs", "bottom", 2); + if (std::filesystem::exists(layout_path)) + try { + dock.load(layout_path); + } catch (const std::exception& e) { + session.log(std::string("Layout reset: ") + e.what()); + } + ui.find("scene_panel")->layout.width = dock.size("scene", 224); + ui.find("inspector_panel")->layout.width = dock.size("inspector", 300); + ui.find("bottom_panel")->layout.height = dock.size("bottom", 184); + ui.set_clipboard([this] { return renderer.clipboard(); }, + [this](const std::string& text) { renderer.set_clipboard(text); }); + ui.set_ime([this](bool enabled) { renderer.set_text_input(enabled); }, + [this](ui::Rect rect) { + renderer.set_text_input_area(rect.x, rect.y, rect.width, rect.height); + }); + ui.set_docking(&dock, [this] { persist_layout(); }); + for (const auto* id : {"left_divider", "right_divider", "bottom_divider"}) + ui.find(id)->on_commit = [this](Widget&) { persist_layout(); }; + const auto recovered = call("faset_recovery_list"); + if (!recovered.is_null()) + for (const auto& item : recovered.at("recovery")) + if (item.value("dirty", false)) + recovery.push_back(item); + build_static(); + const auto docs = session.authoring().documents(); + if (!docs.empty()) + document = docs.front().at("id"); + else + document = session.authoring() + .create("Untitled", session.project().value("dimension", 3)) + .at("id"); + refresh(); + } + void persist_layout() { + dock.set_size("scene", ui.find("scene_panel")->rect.width); + dock.set_size("inspector", ui.find("inspector_panel")->rect.width); + dock.set_size("bottom", ui.find("bottom_panel")->rect.height); + try { + dock.save(layout_path); + } catch (const std::exception& e) { + report(e.what()); + } + } + void report(const std::string& message) { + status = message; + session.log(message); + } + Json call(const std::string& name, Json args = Json::object()) { + try { + auto result = session.commands().call(name, args); + if (result.contains("job")) + status = "Started " + name + " (see Jobs)"; + return result; + } catch (const std::exception& e) { + report(e.what()); + return nullptr; + } + } + bool transaction(Json operations, + std::uint64_t revision = std::numeric_limits::max()) { + if (document.empty()) + return false; + const auto result = call("faset_scene_edit", + {{"document", document}, + {"revision", revision == std::numeric_limits::max() + ? current.at("revision").get() + : revision}, + {"operations", operations}}); + if (result.is_null()) + return false; + current = result; + shown_revision = std::numeric_limits::max(); + status = "Edited " + current.at("name").get(); + return true; + } + void history(bool redo) { + if (document.empty()) + return; + auto result = call(redo ? "faset_redo" : "faset_undo", + {{"document", document}, {"revision", current.at("revision")}}); + if (!result.is_null()) { + current = result; + preview_fields.clear(); + shown_revision = std::numeric_limits::max(); + } + } + void save() { + ui.clear_focus(); + const auto path = current.value("path", std::string()); + if (path.empty()) { + menu = "File"; + ui.update_text("save-path", + "Scenes/" + current.at("name").get() + ".scene.json", true); + return; + } + auto result = call("faset_document_save", {{"document", document}}); + if (!result.is_null()) { + current = result; + status = "Saved " + path; + } + } + Widget& button(Widget& row, const std::string& id, const std::string& text, + std::function action, float width = -1) { + auto& b = row.add(Kind::Button, id, text); + b.layout.width = width; + b.on_click = [action = std::move(action)](Widget&) { action(); }; + return b; + } + void create_object(const std::string& type) { + const auto id = new_id(); + Json object = authoring::make_entity(session.authoring().schemas(), type); + object["id"] = id; + if (type == "Cube" || type == "Plane") + object["components"].push_back({{"id", new_id()}, + {"type", "faset.mesh"}, + {"version", 1}, + {"fields", + {{"asset", ""}, + {"color", {.65, .65, .68, 1.0}}, + {"primitive", type == "Plane" ? "plane" : "cube"}}}}); + else if (type == "Sprite") + object["components"].push_back( + {{"id", new_id()}, + {"type", "faset.sprite"}, + {"version", 1}, + {"fields", session.authoring().schemas().default_fields("faset.sprite")}}); + if (transaction(Json::array({{{"op", "entity.create"}, {"entity", object}}}))) + selected = id; + } + void build_static() { + auto& menurow = ui.find("menubar")->add(Kind::Row, "menuitems"); + menurow.layout.gap = 2; + for (const std::string name : {"Faset", "File", "Edit", "Scene", "View", "Help"}) + button( + menurow, "menu-" + name, name, [this, name] { menu = menu == name ? "" : name; }, + name == "Faset" ? 72 : 54); + auto& project = menurow.add(Kind::Label, "project-title", + session.project().value("name", std::string("Project"))); + project.layout.flex = 1; + auto& toolbar = ui.find("toolbar")->add(Kind::Row, "tools"); + toolbar.layout.gap = 5; + button(toolbar, "save", "Save", [this] { save(); }, 60); + button(toolbar, "undo", "Undo", [this] { history(false); }, 56); + button(toolbar, "redo", "Redo", [this] { history(true); }, 56); + button( + toolbar, "play", "Play", [this] { call("faset_play", {{"document", document}}); }, 58); + button( + toolbar, "stop", "Stop", + [this] { + call("faset_stop"); + paused = false; + }, + 56); + button( + toolbar, "pause", "Pause", + [this] { + if (!call("faset_play_control", {{"command", paused ? "resume" : "pause"}}) + .is_null()) + paused = !paused; + }, + 65); + button( + toolbar, "step", "Step", [this] { call("faset_play_control", {{"command", "step"}}); }, + 55); + button(toolbar, "build", "Build C++", [this] { call("faset_build"); }, 94); + button( + toolbar, "export", "Export", + [this] { call("faset_export", {{"document", document}, {"output", "Exports"}}); }, 64); + auto& space = toolbar.add(Kind::Label, "toolbar-space", ""); + space.layout.flex = 1; + button(toolbar, "command-palette", "Commands", [this] { palette = !palette; }, 104); + auto& scene = *ui.find("scene_panel"); + scene.add(Kind::Tab, "scene-tab", "Scene").selected = true; + auto& tools = scene.add(Kind::Row, "scene-tools"); + tools.layout.height = 28; + tools.layout.padding = 3; + tools.layout.gap = 3; + button(tools, "add-object", "+ Object", [this] { create_object("Object"); }, 80); + button(tools, "add-cube", "Cube", [this] { create_object("Cube"); }, 55); + button(tools, "add-sprite", "Sprite", [this] { create_object("Sprite"); }, 58); + auto& tree = scene.add(Kind::Column, "scene-tree"); + tree.layout.flex = 1; + tree.layout.scroll = true; + tree.layout.gap = 0; + tree.on_drop = [this](Widget&, const Json& payload) { + if (payload.value("kind", std::string()) == "entity") + transaction(Json::array({{{"op", "entity.reparent"}, + {"entity", payload.at("id")}, + {"parent", nullptr}, + {"keep_world", true}}})); + }; + auto& inspector = *ui.find("inspector_panel"); + inspector.add(Kind::Tab, "inspector-tab", "Inspector").selected = true; + auto& body = inspector.add(Kind::Column, "properties"); + body.layout.flex = 1; + body.layout.padding = 10; + body.layout.gap = 7; + body.layout.scroll = true; + auto& vp = *ui.find("viewport"); + auto& vptools = vp.add(Kind::Row, "viewport-tools"); + vptools.layout.absolute = true; + vptools.layout.x = 8; + vptools.layout.y = 8; + vptools.layout.height = 28; + vptools.layout.width = 300; + for (const std::string mode : {"Move", "Rotate", "Scale"}) + button(vptools, "gizmo-" + mode, mode, [this, mode] { gizmo_mode = mode; }, 64); + button(vptools, "frame-selection", "Frame", [this] { frame_selection(); }, 64); + vp.on_drop = [this](Widget&, const Json& data) { + if (data.value("kind", std::string()) == "asset") + instantiate_asset(data.at("id").get()); + }; + auto& bottom = *ui.find("bottom_panel"); + bottom.dock_area = "bottom"; + auto& tabs = bottom.add(Kind::Row, "bottom-tabs"); + tabs.layout.height = 29; + tabs.layout.gap = 0; + for (const std::string id : {"assets", "console", "jobs"}) { + auto& tab = tabs.add(Kind::Tab, "tab-" + id, + id == "assets" ? "Assets" + : id == "console" ? "Console" + : "Jobs"); + tab.layout.width = 94; + tab.dock_area = "bottom"; + tab.dock_panel = id; + tab.on_click = [this, id](Widget&) { active_bottom = id; }; + } + auto& assetbar = bottom.add(Kind::Row, "asset-toolbar"); + assetbar.layout.height = 30; + assetbar.layout.padding = 2; + assetbar.layout.gap = 5; + label(assetbar, "asset-path", "Project assets", 135); + auto& search = assetbar.add(Kind::TextField, "asset-search", ""); + search.layout.width = 220; + search.on_preview = [this](Widget& w) { + asset_filter = w.text; + assets_dirty = true; + }; + button( + assetbar, "asset-import", "Import / Reimport", + [this] { + if (!source_file.empty()) + call("faset_import", {{"path", source_file}}); + }, + 146); + button(assetbar, "asset-open", "Open Scene", [this] { open_source(); }, 104); + button( + assetbar, "asset-refresh", "Refresh", + [this] { + assets_dirty = true; + view.clearCache(); + picks_key.clear(); + }, + 75); + auto& items = bottom.add(Kind::Column, "asset-items"); + items.layout.flex = 1; + items.layout.scroll = true; + items.layout.gap = 0; + auto& console = bottom.add(Kind::Column, "console-items"); + console.layout.flex = 1; + console.layout.scroll = true; + console.layout.gap = 0; + auto& jobs = bottom.add(Kind::Column, "job-items"); + jobs.layout.flex = 1; + jobs.layout.scroll = true; + jobs.layout.gap = 1; + auto& statusrow = ui.find("statusbar")->add(Kind::Row, "status-row"); + auto& statuslabel = statusrow.add(Kind::Label, "status", "Ready"); + statuslabel.layout.flex = 1; + label(statusrow, "renderer-status", "Vulkan", 225); + build_overlays(); + } + void build_overlays() { + auto& pop = ui.root().add(Kind::Panel, "menu-popup"); + pop.layout.absolute = true; + pop.layout.x = 72; + pop.layout.y = 35; + pop.layout.width = 350; + pop.layout.height = 355; + pop.layout.padding = 8; + pop.layout.gap = 5; + pop.visible = false; + label(pop, "menu-title", "File"); + button(pop, "new-3d", "New 3D scene", [this] { new_scene(3); }); + button(pop, "new-2d", "New 2D scene", [this] { new_scene(2); }); + pop.add(Kind::TextField, "open-path", "Scenes/Main.scene.json"); + button(pop, "open-path-button", "Open project-relative scene", [this] { + auto result = call("faset_document_open", {{"path", ui.find("open-path")->text}}); + if (!result.is_null()) { + choose_document(result.at("id")); + menu.clear(); + } + }); + pop.add(Kind::TextField, "save-path", "Scenes/Untitled.scene.json"); + button(pop, "save-as-button", "Save scene as", [this] { + auto result = call("faset_document_save", + {{"document", document}, {"path", ui.find("save-path")->text}}); + if (!result.is_null()) { + current = result; + menu.clear(); + assets_dirty = true; + } + }); + button(pop, "menu-duplicate", "Duplicate selection", [this] { + if (!selected.empty()) + transaction(Json::array({{{"op", "entity.duplicate"}, {"entity", selected}}})); + menu.clear(); + }); + button(pop, "menu-delete", "Delete selection", [this] { + delete_selected(); + menu.clear(); + }); + label(pop, "help-one", "Orbit: right drag. Pan: middle drag. Wheel: zoom."); + label(pop, "help-two", "W / E / R: gizmos. F: frame. Ctrl+P: commands."); + label(pop, "help-three", "Ctrl+S save. Ctrl+Z / Shift+Z undo / redo."); + auto& command = ui.root().add(Kind::Panel, "palette"); + command.layout.absolute = true; + command.layout.width = 570; + command.layout.height = 470; + command.layout.padding = 12; + command.layout.gap = 6; + command.visible = false; + label(command, "palette-title", "Editor commands · authoring only"); + auto& filter = command.add(Kind::TextField, "palette-filter", ""); + filter.on_preview = [](Widget&) {}; + auto& list = command.add(Kind::Column, "palette-list"); + list.layout.flex = 1; + list.layout.scroll = true; + list.layout.gap = 1; + command.add(Kind::TextField, "palette-arguments", "{}"); + button(command, "palette-run", "Run selected command", [this] { + try { + const auto result = + call(command_name, Json::parse(ui.find("palette-arguments")->text)); + if (!result.is_null()) { + session.log(result.dump(2)); + status = "Completed " + command_name; + assets_dirty = true; + } + } catch (const std::exception& e) { + report(e.what()); + } + }); + button(command, "palette-close", "Close", [this] { palette = false; }); + auto& recover = ui.root().add(Kind::Panel, "recovery-panel"); + recover.layout.absolute = true; + recover.layout.width = 470; + recover.layout.height = 260; + recover.layout.padding = 12; + recover.layout.gap = 5; + recover.visible = false; + } + void new_scene(int dimension) { + auto result = + call("faset_document_create", {{"name", "Untitled"}, {"dimension", dimension}}); + if (!result.is_null()) + choose_document(result.at("id")); + menu.clear(); + } + void choose_document(const std::string& id) { + ui.clear_focus(false); + document = id; + selected.clear(); + current = session.authoring().query(id); + shown_revision = std::numeric_limits::max(); + preview_fields.clear(); + edit_revisions.clear(); + gizmo_axis = -1; + } + void delete_selected() { + if (selected.empty()) + return; + if (transaction(Json::array({{{"op", "entity.delete"}, {"entity", selected}}}))) + selected.clear(); + } + void select(const std::string& id) { + if (selected == id) + return; + ui.clear_focus(); + selected = id; + preview_fields.clear(); + edit_revisions.clear(); + component_menu = false; + } + void open_source() { + if (source_file.empty()) + return; + auto result = call("faset_document_open", {{"path", source_file}}); + if (!result.is_null()) + choose_document(result.at("id")); + } + void instantiate_asset(const std::string& id) { + Json manifest; + for (const auto& entry : assets) + if (entry.at("id") == id && entry.contains("manifest")) + manifest = entry.at("manifest"); + const bool image = manifest.is_object() && manifest.value("kind", std::string()) == "image"; + const auto name = + manifest.is_object() + ? std::filesystem::path(manifest.value("source", std::string("Imported asset"))) + .stem() + .string() + : "Imported asset"; + auto object = authoring::make_entity(session.authoring().schemas(), name); + const auto entity_id = object.at("id").get(); + if (image) { + auto fields = session.authoring().schemas().default_fields("faset.sprite"); + fields["texture"] = id; + fields["color"] = {1, 1, 1, 1}; + if (manifest.contains("image")) { + const auto& info = manifest.at("image"); + const auto ppu = info.value("pixels_per_unit", 100.0); + fields["size"] = {info.at("width").get() / ppu, + info.at("height").get() / ppu}; + } + object["components"].push_back( + {{"id", new_id()}, {"type", "faset.sprite"}, {"version", 1}, {"fields", fields}}); + } else + object["components"].push_back( + {{"id", new_id()}, + {"type", "faset.mesh"}, + {"version", 1}, + {"fields", {{"asset", id}, {"primitive", "asset"}, {"color", {1, 1, 1, 1}}}}}); + if (transaction(Json::array({{{"op", "entity.create"}, {"entity", object}}}))) + selected = entity_id; + } + void refresh() { + if (document.empty()) + return; + current = session.authoring().query(document); + schemas = session.authoring().schemas().manifest(); + if (shown_revision != current.at("revision").get()) { + auto result = call("faset_template_preview", {{"document", document}}); + resolved = result.is_null() ? current.at("scene") : result.at("scene"); + if (!result.is_null() && !result.at("conflicts").empty()) + status = "Template conflicts: " + std::to_string(result.at("conflicts").size()); + shown_revision = current.at("revision"); + } + if (!selected.empty() && !entity(current.at("scene"), selected)) + selected.clear(); + refresh_tree(); + refresh_inspector(); + refresh_assets(); + refresh_bottom(); + refresh_overlays(); + ui.find("undo")->enabled = current.value("can_undo", false); + ui.find("redo")->enabled = current.value("can_redo", false); + ui.find("pause")->enabled = session.playing(); + ui.find("step")->enabled = session.playing(); + ui.find("pause")->text = paused ? "Resume" : "Pause"; + ui.find("project-title")->text = session.project().value("name", std::string("Project")) + + " / " + current.at("name").get() + + (current.value("dirty", false) ? " *" : ""); + ui.find("status")->text = status; + ui.find("renderer-status")->text = + "Vulkan 1.3 | " + std::to_string(current.at("scene").at("entities").size()) + + " objects"; + } + void refresh_tree() { + auto& tree = *ui.find("scene-tree"); + std::set keep; + const auto& scene = current.at("scene"); + auto& root = tree.add(Kind::TreeRow, "scene-root", scene.at("name")); + root.selected = selected.empty(); + root.on_click = [this](Widget&) { select(""); }; + keep.insert(root.id); + std::function append = [&](std::string parent, int depth) { + for (const auto& e : scene.at("entities")) { + const auto p = e.at("parent").is_string() ? e.at("parent").get() : ""; + if (p != parent) + continue; + const auto id = e.at("id").get(); + auto& row = tree.add(Kind::TreeRow, "entity-" + id, e.at("name")); + keep.insert(row.id); + row.indent = depth; + row.selected = selected == id; + row.drag_payload = {{"kind", "entity"}, {"id", id}, {"label", e.at("name")}}; + row.on_click = [this, id](Widget&) { select(id); }; + row.on_drop = [this, id](Widget&, const Json& payload) { + if (payload.value("kind", std::string()) == "entity") + transaction(Json::array({{{"op", "entity.reparent"}, + {"entity", payload.at("id")}, + {"parent", id}, + {"keep_world", true}}})); + }; + append(id, depth + 1); + } + }; + append("", 1); + trim_children(tree, keep); + // Match retained children to hierarchy order after a reparent without + // changing widget IDs. + std::map order; + std::size_t n = 0; + std::function visit = [&](std::string p) { + for (const auto& e : scene.at("entities")) + if ((e.at("parent").is_string() ? e.at("parent").get() : "") == p) { + const auto id = e.at("id").get(); + order["entity-" + id] = ++n; + visit(id); + } + }; + order["scene-root"] = 0; + visit(""); + std::stable_sort(tree.children.begin(), tree.children.end(), + [&](const auto& a, const auto& b) { return order[a->id] < order[b->id]; }); + } + void set_field(const std::string& component_id, const std::string& field, Json value, + const std::string& widget) { + const auto found = edit_revisions.find(widget); + const auto revision = found == edit_revisions.end() + ? current.at("revision").get() + : found->second; + transaction(Json::array({{{"op", "component.set"}, + {"entity", selected}, + {"component", component_id}, + {"field", field}, + {"value", std::move(value)}}}), + revision); + edit_revisions.erase(widget); + preview_fields.erase(component_id + "/" + field); + } + void bind_field(Widget& w, const std::string& cid, const std::string& field, Json original, + int index = -1) { + const auto id = w.id; + w.on_preview = [this, id, cid, field, original, index](Widget& widget) { + edit_revisions.try_emplace(id, current.at("revision").get()); + if (widget.kind == Kind::NumberField) { + try { + auto value = std::stod(widget.text); + if (!std::isfinite(value)) + return; + Json changed = original; + if (index >= 0) + changed[index] = value; + else if (original.is_number_integer()) + changed = std::int64_t(std::llround(value)); + else + changed = value; + preview_fields[cid + "/" + field] = changed; + } catch (...) { + } + } + }; + w.on_commit = [this, cid, field, original, index, id](Widget& widget) { + Json changed = original; + if (widget.kind == Kind::Checkbox) + changed = widget.checked; + else if (widget.kind == Kind::NumberField) { + if (index >= 0) + changed[index] = widget.value; + else if (original.is_number_integer()) + changed = std::int64_t(std::llround(widget.value)); + else + changed = widget.value; + } else if (original.is_string()) + changed = widget.text; + else + try { + changed = Json::parse(widget.text); + } catch (const std::exception& e) { + report(e.what()); + return; + } + set_field(cid, field, changed, id); + }; + w.on_cancel = [this, cid, field, id](Widget&) { + preview_fields.erase(cid + "/" + field); + edit_revisions.erase(id); + }; + w.on_drop = [this, cid, field, id](Widget&, const Json& payload) { + if (payload.value("kind", std::string()) == "asset") + set_field(cid, field, payload.at("id"), id); + }; + } + void refresh_inspector() { + auto& body = *ui.find("properties"); + std::set keep; + const auto* e = entity(current.at("scene"), selected); + if (!e) { + label(body, "inspector-empty", "Select an object to edit its components"); + keep.insert("inspector-empty"); + trim_children(body, keep); + return; + } + auto& name = body.add(Kind::TextField, "object-name"); + ui.update_text(name.id, e->at("name")); + keep.insert(name.id); + name.on_preview = [this](Widget&) { + edit_revisions.try_emplace("object-name", current.at("revision").get()); + }; + name.on_cancel = [this](Widget& w) { edit_revisions.erase(w.id); }; + name.on_commit = [this](Widget& w) { + transaction( + Json::array({{{"op", "entity.rename"}, {"entity", selected}, {"name", w.text}}}), + edit_revisions.contains(w.id) ? edit_revisions[w.id] + : current.at("revision").get()); + edit_revisions.erase(w.id); + }; + for (const auto& c : e->at("components")) { + const auto cid = c.at("id").get(), type = c.at("type").get(); + const bool known = session.authoring().schemas().contains(type); + const auto metadata = + known ? session.authoring().schemas().schema(type) + : Json{{"name", type + " (schema missing)"}, {"fields", Json::object()}}; + auto& header = body.add(Kind::Row, "component-header-" + cid); + keep.insert(header.id); + header.layout.height = 28; + auto& title = + header.add(Kind::Label, "component-title-" + cid, metadata.value("name", type)); + title.layout.flex = 1; + button( + header, "component-remove-" + cid, "x", + [this, cid] { + transaction(Json::array( + {{{"op", "component.remove"}, {"entity", selected}, {"component", cid}}})); + }, + 25); + for (const auto& [fid, value] : c.at("fields").items()) { + const auto descriptor = metadata.at("fields").value(fid, Json::object()); + const auto key = "field-" + cid + "-" + fid; + auto& row = body.add(Kind::Column, key); + keep.insert(key); + row.layout.gap = 2; + label(row, key + "-label", + descriptor.value("name", fid) + + (descriptor.value("unit", std::string()) == "radians" ? " (rad)" : "")); + const auto& options = descriptor.value("enum", Json::array()); + const bool vector_value = value.is_array() && value.size() >= 2 && + value.size() <= 4 && + std::all_of(value.begin(), value.end(), + [](const Json& v) { return v.is_number(); }); + const auto input_id = key + (vector_value ? "-vector" : "-value"); + const auto input_kind = !options.empty() ? Kind::Button + : vector_value ? Kind::Row + : value.is_boolean() ? Kind::Checkbox + : value.is_number() ? Kind::NumberField + : Kind::TextField; + if (auto* old = row.find(input_id); old && old->kind != input_kind) { + if (old->find(ui.focused_id())) + ui.clear_focus(false); + row.remove(input_id); + } + trim_children(row, {key + "-label", input_id}); + if (!options.empty()) { + auto& input = + button(row, key + "-value", + value.is_string() ? value.get() : value.dump(), + [this, cid, fid, value, options, key] { + auto found = std::find(options.begin(), options.end(), value); + auto index = found == options.end() + ? 0 + : (std::size_t(found - options.begin()) + 1) % + options.size(); + set_field(cid, fid, options[index], key + "-value"); + }); + input.layout.height = 27; + } else if (value.is_boolean()) { + auto& input = row.add(Kind::Checkbox, key + "-value", "Enabled"); + input.checked = value; + bind_field(input, cid, fid, value); + } else if (vector_value) { + auto& vectorrow = row.add(Kind::Row, key + "-vector"); + vectorrow.layout.gap = 3; + for (std::size_t axis = 0; axis < value.size(); ++axis) { + auto& input = + vectorrow.add(Kind::NumberField, key + "-" + std::to_string(axis)); + input.layout.flex = 1; + input.layout.min_width = 35; + ui.update_number(input.id, value[axis].get()); + input.step = .02; + bind_field(input, cid, fid, value, int(axis)); + } + } else if (value.is_number()) { + auto& input = row.add(Kind::NumberField, key + "-value"); + input.step = value.is_number_integer() ? 1 : .05; + input.precision = value.is_number_integer() ? 0 : 3; + ui.update_number(input.id, value.get()); + bind_field(input, cid, fid, value); + } else { + auto& input = row.add(Kind::TextField, key + "-value"); + ui.update_text(input.id, + value.is_string() ? value.get() : value.dump()); + bind_field(input, cid, fid, value); + } + } + } + auto& add = button(body, "add-component", "+ Add Component", + [this] { component_menu = !component_menu; }); + keep.insert(add.id); + if (component_menu) + for (const auto& schema : schemas.at("types")) { + const auto type = schema.at("id").get(); + auto& choice = button( + body, "component-choice-" + type, schema.value("name", type), [this, type] { + if (transaction(Json::array( + {{{"op", "component.add"}, {"entity", selected}, {"type", type}}}))) + component_menu = false; + }); + keep.insert(choice.id); + } + trim_children(body, keep); + } + void refresh_assets() { + const auto now = std::chrono::steady_clock::now(); + if (!assets_dirty && now - last_assets < std::chrono::seconds(1)) + return; + assets_dirty = false; + last_assets = now; + files = Json::array(); + try { + for (const std::string folder : {"Assets", "Scenes"}) { + const auto directory = session.config().project_root / folder; + if (!std::filesystem::exists(directory)) + continue; + std::size_t count = 0; + for (const auto& entry : std::filesystem::recursive_directory_iterator( + directory, std::filesystem::directory_options::skip_permission_denied)) { + if (++count > 4000) + break; + if (!entry.is_regular_file()) + continue; + auto relative = + std::filesystem::relative(entry.path(), session.config().project_root) + .generic_string(); + if (relative.find(".faset-") != std::string::npos) + continue; + if (!asset_filter.empty() && relative.find(asset_filter) == std::string::npos) + continue; + files.push_back(relative); + } + } + } catch (const std::exception& e) { + report(std::string("Asset scan: ") + e.what()); + } + auto result = call("faset_assets"); + if (!result.is_null()) { + if (assets != result.at("assets")) { + view.clearCache(); + picks_key.clear(); + } + assets = result.at("assets"); + } + auto& list = *ui.find("asset-items"); + std::set keep; + for (const auto& file : files) { + const auto path = file.get(); + auto& row = list.add(Kind::TreeRow, "file-" + path, path); + row.layout.height = 25; + row.indent = 1; + row.selected = source_file == path; + row.on_click = [this, path](Widget&) { + source_file = path; + assets_dirty = true; + }; + keep.insert(row.id); + } + for (const auto& asset : assets) { + const auto id = asset.at("id").get(); + const auto name = asset.contains("manifest") + ? std::filesystem::path(asset["manifest"].value("source", id)) + .filename() + .string() + : id; + auto& row = list.add(Kind::TreeRow, "asset-" + id, "Imported / " + name); + row.layout.height = 25; + row.indent = 1; + row.drag_payload = {{"kind", "asset"}, {"id", id}, {"label", name}}; + row.on_click = [this, id](Widget&) { + renderer.set_clipboard(id); + status = "Asset ID copied; drag to viewport or an asset field"; + }; + keep.insert(row.id); + } + if (keep.empty()) { + label(list, "assets-empty", "Place GLB, glTF, PNG or JPEG in Assets, then Import."); + keep.insert("assets-empty"); + } + trim_children(list, keep); + } + void refresh_bottom() { + for (const auto& panel : session.plugin_panels()) { + const auto panel_id = panel.at("id").get(); + const auto dock_id = "plugin-" + panel_id; + auto order = dock.panels("bottom"); + if (std::find(order.begin(), order.end(), dock_id) == order.end()) + dock.move(dock_id, "bottom", order.size()); + auto& tab = ui.find("bottom-tabs")->add(Kind::Tab, "tab-" + dock_id, panel.at("title")); + tab.layout.width = 150; + tab.dock_area = "bottom"; + tab.dock_panel = dock_id; + tab.selected = active_bottom == dock_id; + tab.on_click = [this, dock_id](Widget&) { active_bottom = dock_id; }; + auto& body = ui.find("bottom_panel")->add(Kind::Column, "plugin-panel-" + panel_id); + body.layout.flex = 1; + body.layout.padding = 10; + body.layout.gap = 6; + body.visible = active_bottom == dock_id; + label(body, "plugin-title-" + panel_id, panel.at("title")); + button(body, "plugin-action-" + panel_id, panel.value("action", std::string("Run")), + [this, panel] { + Json arguments = panel.value("arguments", Json::object()); + std::function resolve = [&](Json& value) { + if (value.is_string() && value == "$document") + value = document; + else if (value.is_structured()) + for (auto& item : value) + resolve(item); + }; + resolve(arguments); + auto result = call(panel.at("command"), arguments); + if (!result.is_null()) { + status = "Completed " + panel.at("title").get(); + shown_revision = std::numeric_limits::max(); + } + }); + } + const auto order = dock.panels("bottom"); + auto& tabs = *ui.find("bottom-tabs"); + std::stable_sort(tabs.children.begin(), tabs.children.end(), + [&](const auto& a, const auto& b) { + return std::find(order.begin(), order.end(), a->dock_panel) < + std::find(order.begin(), order.end(), b->dock_panel); + }); + for (const std::string id : {"assets", "console", "jobs"}) + ui.find("tab-" + id)->selected = active_bottom == id; + ui.find("asset-toolbar")->visible = active_bottom == "assets"; + ui.find("asset-items")->visible = active_bottom == "assets"; + ui.find("console-items")->visible = active_bottom == "console"; + ui.find("job-items")->visible = active_bottom == "jobs"; + auto& console = *ui.find("console-items"); + std::set keep; + const auto& logs = session.logs(); + for (std::size_t i = logs.size() > 150 ? logs.size() - 150 : 0; i < logs.size(); ++i) { + std::string line = logs[i]; + std::replace(line.begin(), line.end(), '\n', ' '); + const auto id = "log-" + std::to_string(i); + label(console, id, line); + console.children.back()->layout.height = 24; + keep.insert(id); + } + if (keep.empty()) { + label(console, "log-empty", "No editor messages."); + keep.insert("log-empty"); + } + trim_children(console, keep); + auto result = call("faset_jobs"); + auto& jobs = *ui.find("job-items"); + keep.clear(); + if (!result.is_null()) + for (const auto& job : result.at("jobs")) { + const auto id = job.at("id").get(); + auto& row = jobs.add(Kind::Row, "job-" + id); + row.layout.height = 28; + keep.insert(row.id); + const auto state = job.value("state", std::string()); + auto& text = + row.add(Kind::Label, "job-text-" + id, + job.value("kind", std::string("Job")) + " · " + state + " · " + + job.value("stage", std::string()) + " " + + std::to_string(int(job.value("progress", 0.0) * 100)) + "%"); + text.layout.flex = 1; + auto& cancel = button( + row, "job-cancel-" + id, "Cancel", + [this, id] { call("faset_job_cancel", {{"id", id}}); }, 72); + cancel.enabled = state == "queued" || state == "running"; + } + if (keep.empty()) { + label(jobs, "jobs-empty", "No active import, build or export jobs."); + keep.insert("jobs-empty"); + } + trim_children(jobs, keep); + } + void refresh_overlays() { + auto& popup = *ui.find("menu-popup"); + popup.visible = !menu.empty(); + ui.find("menu-title")->text = menu; + refresh_recovery(); + const bool file = menu == "File" || menu == "Faset", + edit = menu == "Edit" || menu == "Scene", + help = menu == "Help" || menu == "View"; + for (const auto* id : + {"new-3d", "new-2d", "open-path", "open-path-button", "save-path", "save-as-button"}) + ui.find(id)->visible = file; + for (const auto* id : {"menu-duplicate", "menu-delete"}) + ui.find(id)->visible = edit; + for (const auto* id : {"help-one", "help-two", "help-three"}) + ui.find(id)->visible = help; + popup.layout.height = file ? 260 : edit ? 112 : 150; + popup.layout.x = menu == "File" ? 70 + : menu == "Edit" ? 126 + : menu == "Scene" ? 182 + : menu == "View" ? 238 + : menu == "Help" ? 294 + : 5; + auto& command = *ui.find("palette"); + command.visible = palette; + command.layout.x = std::max(0.f, (float(renderer.width()) - 570) / 2); + command.layout.y = 90; + auto& list = *ui.find("palette-list"); + std::set keep; + const auto filter = ui.find("palette-filter")->text; + for (const auto& descriptor : session.commands().list()) { + const auto name = descriptor.at("name").get(); + if (!filter.empty() && name.find(filter) == std::string::npos) + continue; + auto& row = list.add(Kind::TreeRow, "command-" + name, name); + row.selected = command_name == name; + row.on_click = [this, name](Widget&) { command_name = name; }; + keep.insert(row.id); + } + trim_children(list, keep); + } + void refresh_recovery() { + auto& panel = *ui.find("recovery-panel"); + panel.visible = !recovery.empty(); + panel.layout.x = std::max(0.f, (float(renderer.width()) - 470) / 2); + panel.layout.y = 100; + std::set keep; + label(panel, "recovery-title", "Unsaved authoring recovery"); + keep.insert("recovery-title"); + for (const auto& item : recovery) { + const auto id = item.at("id").get(); + auto& restore = + button(panel, "recover-" + id, "Restore " + item.value("name", id), [this, id] { + Json args = {{"document", id}}; + for (const auto& doc : session.authoring().documents()) + if (doc.at("id") == id) + args["revision"] = doc.at("revision"); + auto result = call("faset_recovery_restore", args); + if (!result.is_null()) { + choose_document(result.at("id")); + recovery.erase( + std::remove_if(recovery.begin(), recovery.end(), + [&](const Json& entry) { return entry.at("id") == id; }), + recovery.end()); + } + }); + keep.insert(restore.id); + } + button(panel, "recovery-dismiss", "Continue without restoring", + [this] { recovery.clear(); }); + keep.insert("recovery-dismiss"); + trim_children(panel, keep); + panel.layout.height = 80 + float(recovery.size()) * 33; + } + player::CameraSettings camera() const { + player::CameraSettings c; + c.overrideSceneCamera = true; + c.target = target; + c.eye = add(target, {distance * std::cos(pitch) * std::sin(yaw), distance * std::sin(pitch), + distance * std::cos(pitch) * std::cos(yaw)}); + c.orthographicHeight = ortho; + if (current.at("scene").value("dimension", 3) == 2) + c.eye = add(target, {0, 0, distance}); + return c; + } + void frame_selection() { + if (auto* e = entity(resolved, selected)) + target = point(world(resolved, *e), {}); + else + target = {}; + distance = 8; + ortho = 8; + } + bool project(Vec3 p, render::Vec2& output) const { + const auto& m = rendered.view_projection; + const auto w = m[3] * p[0] + m[7] * p[1] + m[11] * p[2] + m[15]; + if (w <= .0001f) + return false; + const auto x = (m[0] * p[0] + m[4] * p[1] + m[8] * p[2] + m[12]) / w, + y = (m[1] * p[0] + m[5] * p[1] + m[9] * p[2] + m[13]) / w; + output = {viewport.x + (x + 1) * viewport.width * .5f, + viewport.y + (y + 1) * viewport.height * .5f}; + return true; + } + void line(render::Vec2 a, render::Vec2 b, render::Color color, float thickness = 1) { + const auto length = std::hypot(b[0] - a[0], b[1] - a[1]); + const auto count = std::min(700, std::max(1, int(length / thickness))); + for (int i = 0; i <= count; ++i) { + const auto t = float(i) / count; + ui::Rect q{a[0] + (b[0] - a[0]) * t - thickness * .5f, + a[1] + (b[1] - a[1]) * t - thickness * .5f, thickness + 1, thickness + 1}; + q = q.intersection(viewport); + if (q.width > 0 && q.height > 0) + rendered.ui_quads.push_back({q.x, q.y, q.width, q.height, color, {}, {0, 0, 1, 1}}); + } + } + void build_snapshot() { + auto scene = resolved; + for (auto& e : scene["entities"]) + for (auto& c : e["components"]) + for (auto& [field, value] : c["fields"].items()) { + const auto key = c.at("id").get() + "/" + field; + if (preview_fields.contains(key)) + value = preview_fields[key]; + } + viewport = ui.find("viewport")->rect; + rendered = view.build(scene, viewport.width / std::max(1.f, viewport.height), camera()); + rendered.scene_rect = {viewport.x, viewport.y, viewport.width, viewport.height}; + rendered.clear_color = ui.theme().background; + const auto key = scene.dump() + assets.dump(); + if (key != picks_key) { + picks_key = key; + picks.clear(); + // Picking uses the same cooked meshes and transforms as the visible + // snapshot. + for (const auto& e : scene.at("entities")) { + if (!component(e, "faset.mesh") && !component(e, "faset.sprite")) + continue; + const auto id = e.at("id").get(); + auto isolated = scene; + for (auto& other : isolated["entities"]) + if (other.at("id") != id) { + auto& cs = other["components"]; + cs.erase(std::remove_if(cs.begin(), cs.end(), + [](const Json& c) { + return c.at("type") == "faset.mesh" || + c.at("type") == "faset.sprite"; + }), + cs.end()); + } + auto object = view.build(isolated, 1, camera()); + for (auto& item : object.draws) + picks.push_back({id, std::move(item)}); + for (const auto& sprite : object.sprites) { + auto mesh = std::make_shared(); + mesh->vertices = { + {{-.5f, -.5f, 0}}, {{.5f, -.5f, 0}}, {{.5f, .5f, 0}}, {{-.5f, .5f, 0}}}; + mesh->indices = {0, 1, 2, 0, 2, 3}; + render::DrawItem item; + item.mesh = mesh; + item.model = render::transform(sprite.position, {0, 0, sprite.rotation}, + {sprite.size[0], sprite.size[1], 1}); + picks.push_back({id, item}); + } + } + } + // Grid geometry participates in scene depth, so it never draws through + // objects. It is presentation only and is absent from authoring, picking + // and export. + const bool is2d = scene.value("dimension", 3) == 2; + for (int i = -10; i <= 10; ++i) { + if (is2d) { + rendered.sprites.push_back( + {{float(i), 0, -.02f}, {.012f, 20}, {.18f, .18f, .19f, 1}, 0, {}}); + rendered.sprites.push_back( + {{0, float(i), -.02f}, {20, .012f}, {.18f, .18f, .19f, 1}, 0, {}}); + } else { + render::DrawItem grid; + grid.mesh = render::cube_mesh(); + grid.cast_shadow = false; + grid.color = {.12f, .12f, .13f, 1}; + grid.model = render::transform({float(i), 0, 0}, {}, {.012f, .002f, 20}); + rendered.draws.push_back(grid); + grid.model = render::transform({0, 0, float(i)}, {}, {20, .002f, .012f}); + rendered.draws.push_back(grid); + } + } + gizmo_valid = false; + if (auto* e = entity(scene, selected)) { + gizmo_origin = point(world(scene, *e), {}); + gizmo_valid = project(gizmo_origin, gizmo_screen[0]); + const auto length = is2d ? ortho * .12f : distance * .12f; + for (int axis = 0; axis < 3; ++axis) { + Vec3 p = gizmo_origin; + p[axis] += length; + gizmo_valid = project(p, gizmo_screen[axis + 1]) && gizmo_valid; + } + if (gizmo_valid) { + const render::Color colors[3] = { + {.88f, .35f, .34f, 1}, {.38f, .75f, .49f, 1}, {.4f, .58f, .92f, 1}}; + for (int axis = 0; axis < (is2d ? 2 : 3); ++axis) { + line(gizmo_screen[0], gizmo_screen[axis + 1], colors[axis], 2); + const auto end = gizmo_screen[axis + 1]; + if (viewport.contains(end[0], end[1])) + rendered.ui_quads.push_back( + {end[0] - 4, end[1] - 4, 8, 8, colors[axis], {}, {0, 0, 1, 1}}); + } + } + } + ui.draw(rendered); + } + void pick(float x, float y) { + Mat4 inv; + if (!inverse(rendered.view_projection, inv)) + return; + const auto nx = 2 * (x - viewport.x) / viewport.width - 1, + ny = 2 * (y - viewport.y) / viewport.height - 1; + const auto origin = homogeneous(inv, nx, ny, 0), end = homogeneous(inv, nx, ny, 1), + direction = normalize(sub(end, origin)); + float distance_hit = std::numeric_limits::infinity(); + std::string hit; + for (const auto& candidate : picks) { + const auto& mesh = *candidate.item.mesh; + for (std::size_t i = 0; i + 2 < mesh.indices.size(); i += 3) { + const auto a = point(candidate.item.model, + mesh.vertices.at(mesh.indices[i]).position), + b = point(candidate.item.model, + mesh.vertices.at(mesh.indices[i + 1]).position), + c = point(candidate.item.model, + mesh.vertices.at(mesh.indices[i + 2]).position); + if (ray_triangle(origin, direction, a, b, c, distance_hit)) + hit = candidate.id; + } + } + select(hit); + } + bool start_gizmo(float x, float y) { + if (!gizmo_valid) + return false; + const auto* e = entity(current.at("scene"), selected); + if (!e) + return false; + const auto* c = component(*e, "faset.transform"); + if (!c) + return false; + float best = 8; + int axis = -1; + for (int i = 0; i < (current.at("scene").value("dimension", 3) == 2 ? 2 : 3); ++i) { + auto a = gizmo_screen[0], b = gizmo_screen[i + 1]; + const auto dx = b[0] - a[0], dy = b[1] - a[1], l = dx * dx + dy * dy; + if (l < 16) + continue; + const auto t = std::clamp(((x - a[0]) * dx + (y - a[1]) * dy) / l, 0.f, 1.f); + const auto d = std::hypot(x - a[0] - t * dx, y - a[1] - t * dy); + if (d < best) { + best = d; + axis = i; + } + } + if (axis < 0) + return false; + gizmo_axis = + current.at("scene").value("dimension", 3) == 2 && gizmo_mode == "Rotate" ? 2 : axis; + gizmo_drag_start = gizmo_screen[0]; + gizmo_drag_end = gizmo_screen[axis + 1]; + gizmo_world_length = + (current.at("scene").value("dimension", 3) == 2 ? ortho : distance) * .12f; + gizmo_down_x = x; + gizmo_down_y = y; + gizmo_original = c->at("fields"); + gizmo_component = c->at("id"); + gizmo_revision = current.at("revision"); + return true; + } + void update_gizmo(float x, float y, bool snap) { + if (gizmo_axis < 0) + return; + const auto a = gizmo_drag_start, b = gizmo_drag_end; + const auto dx = b[0] - a[0], dy = b[1] - a[1], l = dx * dx + dy * dy; + const auto amount = l > 1 ? ((x - gizmo_down_x) * dx + (y - gizmo_down_y) * dy) / l : 0; + if (gizmo_mode == "Move") { + Vec3 delta{}; + delta[gizmo_axis] = amount * gizmo_world_length; + if (snap) + delta[gizmo_axis] = std::round(delta[gizmo_axis] * 4) / 4; + const auto* e = entity(current.at("scene"), selected); + if (e && e->at("parent").is_string()) + if (auto* parent = + entity(current.at("scene"), e->at("parent").get())) { + Mat4 inv; + if (inverse(world(current.at("scene"), *parent), inv)) + delta = vector(inv, delta); + } + auto position = vec(gizmo_original.at("position")); + position = add(position, delta); + preview_fields[gizmo_component + "/position"] = position; + } else if (gizmo_mode == "Rotate") { + auto rotation = vec(gizmo_original.at("rotation")); + rotation[gizmo_axis] += snap ? std::round(amount * 12) * .261799f : amount * 3.141593f; + preview_fields[gizmo_component + "/rotation"] = rotation; + } else { + auto scale = vec(gizmo_original.at("scale")); + scale[gizmo_axis] *= std::max(.01f, 1 + amount); + if (snap) + scale[gizmo_axis] = std::max(.05f, std::round(scale[gizmo_axis] * 4) / 4); + preview_fields[gizmo_component + "/scale"] = scale; + } + } + bool viewport_event(const render::Event& event) { + using Type = render::Event::Type; + if (event.type == Type::FocusLost) { + camera_drag = 0; + gizmo_axis = -1; + preview_fields.clear(); + return false; + } + if (event.type == Type::MouseMove) { + const auto dx = event.x - last_x, dy = event.y - last_y; + last_x = event.x; + last_y = event.y; + mouse_x = event.x; + mouse_y = event.y; + if (gizmo_axis >= 0) { + update_gizmo(event.x, event.y, event.control); + return true; + } + if (camera_drag) { + const bool is2d = current.at("scene").value("dimension", 3) == 2; + if (camera_drag == 3 && !is2d) { + yaw -= dx * .008f; + pitch = std::clamp(pitch + dy * .008f, -1.5f, 1.5f); + } else { + const auto right = Vec3{std::cos(yaw), 0, -std::sin(yaw)}; + const auto up = + is2d ? Vec3{0, 1, 0} : normalize(cross(right, sub(camera().eye, target))); + const auto scale = (is2d ? ortho : distance) / std::max(1.f, viewport.height); + target = add(target, add(mul(is2d ? Vec3{1, 0, 0} : right, -dx * scale), + mul(up, dy * scale))); + } + return true; + } + } + if (event.type == Type::MouseDown && viewport.contains(event.x, event.y)) { + last_x = event.x; + last_y = event.y; + if (event.button == 2 || event.button == 3) { + camera_drag = event.button; + return true; + } + if (event.button == 1) { + if (!start_gizmo(event.x, event.y)) + pick(event.x, event.y); + return true; + } + } + if (event.type == Type::MouseUp) { + if (event.button == camera_drag) { + camera_drag = 0; + return true; + } + if (event.button == 1 && gizmo_axis >= 0) { + const auto field = gizmo_mode == "Move" ? "position" + : gizmo_mode == "Rotate" ? "rotation" + : "scale"; + const auto key = gizmo_component + "/" + field; + if (preview_fields.contains(key)) + transaction(Json::array({{{"op", "component.set"}, + {"entity", selected}, + {"component", gizmo_component}, + {"field", field}, + {"value", preview_fields[key]}}}), + gizmo_revision); + preview_fields.erase(key); + gizmo_axis = -1; + return true; + } + } + if (event.type == Type::Wheel && viewport.contains(mouse_x, mouse_y)) { + distance = std::clamp(distance * std::exp(-event.y * .12f), .25f, 500.f); + ortho = std::clamp(ortho * std::exp(-event.y * .12f), .1f, 1000.f); + return true; + } + return false; + } + void events(const std::vector& input) { + using Type = render::Event::Type; + for (const auto& event : input) { + if (event.type == Type::KeyDown && event.key == "Escape") { + if (gizmo_axis >= 0) { + gizmo_axis = -1; + preview_fields.clear(); + continue; + } + if (palette || !menu.empty()) { + palette = false; + menu.clear(); + ui.clear_focus(false); + continue; + } + } + if (event.type == Type::MouseDown && !menu.empty() && + !ui.find("menu-popup")->rect.contains(event.x, event.y) && event.y > 36) + menu.clear(); + if (event.type == Type::MouseMove || event.type == Type::MouseDown) { + mouse_x = event.x; + mouse_y = event.y; + } + if ((palette || !recovery.empty()) && event.type == Type::MouseDown) { + auto* modal = ui.find(!recovery.empty() ? "recovery-panel" : "palette"); + if (!modal->rect.contains(event.x, event.y)) + continue; + } + if (camera_drag || gizmo_axis >= 0) { + if (viewport_event(event)) + continue; + } + if (ui.handle(event)) + continue; + if (event.type == Type::KeyDown) { + if (event.control && (event.key == "S" || event.key == "s")) { + save(); + continue; + } + if (event.control && (event.key == "Z" || event.key == "z")) { + history(event.shift); + continue; + } + if (event.control && (event.key == "P" || event.key == "p")) { + palette = !palette; + continue; + } + if (!ui.editing()) { + if (event.key == "Delete") + delete_selected(); + if (event.key == "F" || event.key == "f") + frame_selection(); + if (event.key == "W" || event.key == "w") + gizmo_mode = "Move"; + if (event.key == "E" || event.key == "e") + gizmo_mode = "Rotate"; + if (event.key == "R" || event.key == "r") + gizmo_mode = "Scale"; + } + } + viewport_event(event); + } + } + void frame(const std::vector& events_) { + session.poll(); + refresh(); + ui.layout(float(renderer.width()), float(renderer.height())); + if (rendered.scene_rect[2] == 0) + build_snapshot(); + events(events_); + refresh(); + ui.layout(float(renderer.width()), float(renderer.height())); + build_snapshot(); + } +}; +EditorUI::EditorUI(Session& s, render::Renderer& r, const std::filesystem::path& font, + const std::filesystem::path& styles) + : impl_(std::make_unique(s, r, font, styles)) {} +EditorUI::~EditorUI() = default; +void EditorUI::frame(const std::vector& input) { + impl_->frame(input); +} +const render::Snapshot& EditorUI::snapshot() const { + return impl_->rendered; +} +ui::Context& EditorUI::widgets() { + return impl_->ui; +} +const std::string& EditorUI::current_document() const { + return impl_->document; +} +void EditorUI::select_document(const std::string& id) { + impl_->choose_document(id); +} +const std::string& EditorUI::selected_entity() const { + return impl_->selected; +} +void EditorUI::select_entity(const std::string& id) { + impl_->select(id); +} +} // namespace faset::editor diff --git a/src/editor/mcp.cpp b/src/editor/mcp.cpp new file mode 100644 index 0000000..7f0e475 --- /dev/null +++ b/src/editor/mcp.cpp @@ -0,0 +1,175 @@ +#include +#include +#ifdef _WIN32 +#define NOMINMAX +#include +#else +#include +#include +#include +#endif + +namespace faset::editor { +namespace { +Json rpc_error(Json id, int code, std::string message, Json data = Json::object()) { + return { + {"jsonrpc", "2.0"}, + {"id", id}, + {"error", {{"code", code}, {"message", std::move(message)}, {"data", std::move(data)}}}}; +} +} // namespace +Json McpServer::parse_error() const { + return rpc_error(nullptr, -32700, "Parse error"); +} +std::optional McpServer::handle(const Json& message) { + if (!message.is_object() || !message.contains("jsonrpc") || message["jsonrpc"] != "2.0" || + !message.contains("method") || !message["method"].is_string()) + return rpc_error(nullptr, -32600, "Invalid Request"); + const auto method = message.at("method").get(); + if (!message.contains("id")) { + if (method == "notifications/initialized" && initialized_) + ready_ = true; + return std::nullopt; + } + const Json id = message.at("id"); + if (!(id.is_string() || id.is_number_integer())) + return rpc_error(nullptr, -32600, "Request ID must be a string or integer"); + const auto params = message.value("params", Json::object()); + if (!params.is_object()) + return rpc_error(id, -32602, "Invalid params"); + auto result = [&](Json value) { + return Json{{"jsonrpc", "2.0"}, {"id", id}, {"result", std::move(value)}}; + }; + if (method == "ping") + return result(Json::object()); + if (method == "initialize") { + if (initialized_) + return rpc_error(id, -32600, "Session already initialized"); + if (!params.contains("protocolVersion") || !params["protocolVersion"].is_string()) + return rpc_error(id, -32602, "protocolVersion is required"); + initialized_ = true; + return result( + {{"protocolVersion", "2025-06-18"}, + {"serverInfo", {{"name", "faset-editor"}, {"version", FASET_VERSION}}}, + {"capabilities", {{"tools", Json::object()}, {"resources", Json::object()}}}, + {"instructions", + "Faset tools edit project documents and manage editor jobs. Query revisions before " + "writes. Player/runtime world access is intentionally unavailable."}}); + } + if (!ready_) + return rpc_error(id, -32002, "Initialize the session before using editor tools"); + if (method == "tools/list") + return result({{"tools", commands_.list()}}); + if (method == "tools/call") { + if (!params.contains("name") || !params["name"].is_string()) + return rpc_error(id, -32602, "Tool name is required"); + try { + auto value = + commands_.call(params.at("name"), params.value("arguments", Json::object())); + Json content = Json::array(); + if (value.is_object() && value.contains("image_base64")) { + content.push_back( + {{"type", "image"}, + {"data", value.at("image_base64")}, + {"mimeType", value.value("mimeType", std::string("image/png"))}}); + value.erase("image_base64"); + } + content.push_back({{"type", "text"}, {"text", value.dump()}}); + return result({{"content", content}, {"structuredContent", value}, {"isError", false}}); + } catch (const Error& error) { + const auto value = Json{{"error", error.json()}}; + return result({{"content", Json::array({{{"type", "text"}, {"text", value.dump()}}})}, + {"structuredContent", value}, + {"isError", true}}); + } catch (const std::exception& error) { + const auto value = + Json{{"error", {{"code", "editor.failure"}, {"message", error.what()}}}}; + return result({{"content", Json::array({{{"type", "text"}, {"text", value.dump()}}})}, + {"structuredContent", value}, + {"isError", true}}); + } + } + if (method == "resources/list") + return result({{"resources", Json::array({{{"uri", "faset://schema"}, + {"name", "Component schema"}, + {"mimeType", "application/json"}}, + {{"uri", "faset://documents"}, + {"name", "Open authoring documents"}, + {"mimeType", "application/json"}}})}}); + if (method == "resources/read") { + if (!params.contains("uri") || !params["uri"].is_string()) + return rpc_error(id, -32602, "Resource URI must be a string"); + const auto uri = params.at("uri").get(); + Json value; + if (uri == "faset://schema") + value = commands_.authoring().schemas().manifest(); + else if (uri == "faset://documents") + value = commands_.authoring().documents(); + else + return rpc_error(id, -32602, "Unknown resource URI"); + return result({{"contents", Json::array({{{"uri", uri}, + {"mimeType", "application/json"}, + {"text", value.dump()}}})}}); + } + return rpc_error(id, -32601, "Method not found"); +} +std::vector StdioTransport::poll() { + std::vector lines; + if (closed_) + return lines; + char bytes[65536]; + std::size_t count = 0; +#ifdef _WIN32 + const auto input = GetStdHandle(STD_INPUT_HANDLE); + const auto type = GetFileType(input); + DWORD available = 0; + if (type == FILE_TYPE_PIPE) { + if (!PeekNamedPipe(input, nullptr, 0, nullptr, &available, nullptr)) { + closed_ = true; + return lines; + } + } else if (type == FILE_TYPE_DISK) + available = sizeof(bytes); + else + return lines; + if (available) { + DWORD read = 0; + if (!ReadFile(input, bytes, std::min(available, sizeof(bytes)), &read, nullptr) || + read == 0) + closed_ = true; + count = read; + } +#else + pollfd input{STDIN_FILENO, POLLIN, 0}; + if (::poll(&input, 1, 0) > 0 && (input.revents & (POLLIN | POLLHUP))) { + const auto read = ::read(STDIN_FILENO, bytes, sizeof(bytes)); + if (read > 0) + count = static_cast(read); + else if (read == 0) + closed_ = true; + else if (errno != EINTR && errno != EAGAIN) + closed_ = true; + } +#endif + buffer_.append(bytes, count); + require(buffer_.size() <= 8 * 1024 * 1024, "mcp.message_size", "MCP input exceeds 8 MiB"); + std::size_t newline = 0; + while ((newline = buffer_.find('\n')) != std::string::npos) { + auto line = buffer_.substr(0, newline); + if (!line.empty() && line.back() == '\r') + line.pop_back(); + if (!line.empty()) + lines.push_back(std::move(line)); + buffer_.erase(0, newline + 1); + } + if (closed_ && !buffer_.empty()) { + lines.push_back(std::move(buffer_)); + buffer_.clear(); + } + return lines; +} +void StdioTransport::send(const Json& value) { + std::cout << value.dump() << '\n'; + std::cout.flush(); +} +} // namespace faset::editor diff --git a/src/editor/plugins.cpp b/src/editor/plugins.cpp new file mode 100644 index 0000000..63e97f9 --- /dev/null +++ b/src/editor/plugins.cpp @@ -0,0 +1,358 @@ +#include +#include +#include +#include +#include +#include +#include +#ifdef _WIN32 +#define NOMINMAX +#include +#else +#include +#endif + +namespace faset::editor { +namespace { +void append(void* context, const char* bytes, std::uint64_t size) { + auto& output = *static_cast(context); + require(size <= 8 * 1024 * 1024 && output.size() + size <= 8 * 1024 * 1024, + "plugin.output_limit", "Plugin response exceeds 8 MiB"); + output.append(bytes, static_cast(size)); +} +Json response(const std::string& bytes) { + auto value = Json::parse(bytes); + require(value.is_object(), "plugin.response", "Plugin response must be a JSON object"); + return value; +} +bool identifier(const std::string& value) { + return !value.empty() && value.size() <= 128 && + std::all_of(value.begin(), value.end(), [](unsigned char c) { + return c < 128 && (std::isalnum(c) || c == '.' || c == '_' || c == '-'); + }); +} +std::string prefix(std::string id) { + for (auto& c : id) + if (c == '.' || c == '-') + c = '_'; + return "plugin_" + id + "_"; +} +} // namespace +struct PluginManager::Impl { + struct Registration { + Json descriptor; + FasetCommand callback = nullptr; + void* user = nullptr; + }; + struct Module { + Impl* owner = nullptr; + Json manifest; + std::filesystem::path directory; + std::vector commands; + Json panels = Json::array(); + std::vector installed; + FasetEditorHost host{}; + FasetEditorPlugin plugin{}; + void* library = nullptr; + bool ready = false; + std::string failure; + ~Module() { + ready = false; + for (const auto& name : installed) + owner->commands.remove(name); + if (plugin.shutdown) + try { + plugin.shutdown(plugin.user); + } catch (...) { /* Plugin contract forbids exceptions. */ + } +#ifdef _WIN32 + if (library) + FreeLibrary(static_cast(library)); +#else + if (library) + dlclose(library); +#endif + } + std::string id() const { + return manifest.at("id"); + } + void check_thread() const { + require(std::this_thread::get_id() == owner->thread, "plugin.thread", + "Editor SDK calls must run on the Editor thread"); + } + }; + Commands& commands; + Logger logger; + std::thread::id thread = std::this_thread::get_id(); + std::vector> modules; + Json records = Json::array(); + bool attempted = false; + unsigned call_depth = 0; + Impl(Commands& value, Logger output) : commands(value), logger(std::move(output)) {} + ~Impl() { + while (!modules.empty()) + modules.pop_back(); + } + static int command(void* context, const char* descriptor, FasetCommand callback, void* user) { + auto& module = *static_cast(context); + try { + module.check_thread(); + require(!module.ready, "plugin.registration_closed", "Registrations are startup-only"); + require(callback, "plugin.callback", "Command callback is missing"); + const auto value = Json::parse(descriptor); + const auto name = value.at("name").get(); + require(name.starts_with(prefix(module.id())) && identifier(name), + "plugin.command_owner", "Plugin command must use its module prefix"); + require(value.at("description").is_string() && + value.at("inputSchema").at("type") == "object" && + value.at("inputSchema").at("properties").is_object(), + "plugin.command_schema", "Command requires an object input schema"); + for (const auto& prior : module.commands) + require(prior.descriptor.at("name") != name, "plugin.command_duplicate", + "Duplicate plugin command"); + module.commands.push_back({value, callback, user}); + return 0; + } catch (const std::exception& error) { + module.failure = error.what(); + return 1; + } + } + static int panel(void* context, const char* descriptor) { + auto& module = *static_cast(context); + try { + module.check_thread(); + require(!module.ready, "plugin.registration_closed", "Registrations are startup-only"); + auto value = Json::parse(descriptor); + require(value.at("id").get().starts_with(module.id() + "."), + "plugin.panel_owner", "Panel ID must belong to its module"); + require(value.at("title").is_string() && value.at("command").is_string(), + "plugin.panel", "Panel needs a title and command"); + if (!value.contains("arguments")) + value["arguments"] = Json::object(); + require(value["arguments"].is_object(), "plugin.panel", + "Panel arguments must be an object"); + for (const auto& previous : module.panels) + require(previous["id"] != value["id"], "plugin.panel_duplicate", + "Duplicate panel ID"); + value["owner"] = module.id(); + module.panels.push_back(std::move(value)); + return 0; + } catch (const std::exception& error) { + module.failure = error.what(); + return 1; + } + } + static int invoke(void* context, const char* name, const char* arguments, FasetWrite write, + void* receiver) { + auto& module = *static_cast(context); + bool entered = false; + try { + module.check_thread(); + require(module.ready, "plugin.not_ready", + "Editor commands become available after plugin startup"); + require(module.owner->call_depth < 32, "plugin.recursion", + "Plugin command recursion limit exceeded"); + ++module.owner->call_depth; + entered = true; + const auto output = module.owner->commands.call(name, Json::parse(arguments)).dump(); + --module.owner->call_depth; + entered = false; + write(receiver, output.data(), output.size()); + return 0; + } catch (const std::exception& error) { + if (entered) + --module.owner->call_depth; + const auto* known = dynamic_cast(&error); + const auto output = + (known ? known->json() + : Json{{"code", "plugin.command"}, {"message", error.what()}}) + .dump(); + if (write) + try { + write(receiver, output.data(), output.size()); + } catch (...) { + } + return 1; + } + } + static void log(void* context, const char* text) { + auto& module = *static_cast(context); + try { + module.check_thread(); + module.owner->logger(module.id() + ": " + text); + } catch (...) { + } + } + void activate(const Json& manifest, const std::filesystem::path& directory) { + auto module = std::make_unique(); + module->owner = this; + module->manifest = manifest; + module->directory = directory; + const auto path = project_path(directory, manifest.at("library").get()); + require(std::filesystem::is_regular_file(path), "plugin.library", + "Plugin library is missing"); +#ifdef _WIN32 + module->library = + LoadLibraryExW(path.c_str(), nullptr, + LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR | LOAD_LIBRARY_SEARCH_DEFAULT_DIRS); + auto entry = module->library + ? reinterpret_cast(GetProcAddress( + static_cast(module->library), "faset_editor_plugin")) + : nullptr; +#else + module->library = dlopen(path.c_str(), RTLD_NOW | RTLD_LOCAL); + const auto error = module->library ? nullptr : dlerror(); + require(module->library, "plugin.load", error ? error : "Cannot load plugin library"); + auto entry = + reinterpret_cast(dlsym(module->library, "faset_editor_plugin")); +#endif + require(module->library && entry, "plugin.entry", + "Library does not export faset_editor_plugin"); + module->host = {FASET_EDITOR_API_VERSION, + sizeof(FasetEditorHost), + FASET_EDITOR_SDK_FINGERPRINT, + module.get(), + command, + panel, + invoke, + log}; + require(entry(&module->host, &module->plugin) == 0, "plugin.startup", + "Plugin startup failed"); + require(module->failure.empty(), "plugin.registration", module->failure); + require(module->plugin.api_version == FASET_EDITOR_API_VERSION && + module->plugin.struct_size == sizeof(FasetEditorPlugin), + "plugin.api", "Plugin returned an incompatible API"); + require(module->plugin.build_fingerprint && + std::string(module->plugin.build_fingerprint) == FASET_EDITOR_SDK_FINGERPRINT, + "plugin.build", "Plugin binary does not match this Editor SDK build"); + for (const auto& value : module->panels) { + const auto name = value.at("command").get(); + require(std::any_of(module->commands.begin(), module->commands.end(), + [&](const auto& reg) { return reg.descriptor.at("name") == name; }), + "plugin.panel_command", "Panel command must be registered by its owner"); + } + for (const auto& registration : module->commands) { + const auto& descriptor = registration.descriptor; + const auto name = descriptor.at("name").get(); + commands.add( + name, descriptor.at("description"), descriptor.at("inputSchema"), + [registration](const Json& arguments) { + std::string output; + const auto input = arguments.dump(); + const int result = + registration.callback(registration.user, input.c_str(), append, &output); + const auto value = response(output); + if (result != 0) + throw Error(value.value("code", std::string("plugin.failed")), + value.value("message", std::string("Plugin command failed")), + value); + return value; + }, + descriptor.value("read_only", false)); + module->installed.push_back(name); + } + module->ready = true; + logger("Loaded editor plugin: " + module->id()); + modules.push_back(std::move(module)); + } +}; +PluginManager::PluginManager(Commands& commands, Logger logger) + : impl_(std::make_unique(commands, std::move(logger))) {} +PluginManager::~PluginManager() = default; +std::string PluginManager::fingerprint() { + return FASET_EDITOR_SDK_FINGERPRINT; +} +Json PluginManager::status() const { + return impl_->records; +} +Json PluginManager::panels() const { + Json result = Json::array(); + for (const auto& module : impl_->modules) + for (const auto& panel : module->panels) + result.push_back(panel); + return result; +} +void PluginManager::load(const std::filesystem::path& directory) { + require(!impl_->attempted, "plugin.restart_required", + "Plugin discovery runs once; restart the Editor after changing packages"); + impl_->attempted = true; + if (!std::filesystem::exists(directory)) + return; + struct Source { + Json manifest; + std::filesystem::path directory; + }; + std::map sources; + std::set invalid; + auto failure = [&](const std::string& id, const std::string& message) { + invalid.insert(id); + impl_->records.push_back({{"id", id}, {"state", "failed"}, {"message", message}}); + impl_->logger("Plugin " + id + ": " + message); + }; + for (const auto& entry : std::filesystem::recursive_directory_iterator(directory)) + if (entry.is_regular_file() && + entry.path().filename().string().ends_with(".faset-plugin.json")) { + std::string id = entry.path().filename().string(); + try { + const auto manifest = read_json(entry.path()); + id = manifest.at("id"); + require(identifier(id), "plugin.id", "Invalid module ID"); + require(!sources.contains(id), "plugin.duplicate", "Duplicate module ID"); + require(manifest.at("format") == "faset.editor_plugin" && + manifest.at("version") == 1 && manifest.at("kind") == "editor", + "plugin.manifest", "Unsupported editor plugin manifest"); + require(manifest.at("module_version").is_string() && + manifest.at("dependencies").is_array(), + "plugin.manifest", "Plugin needs version and dependency list"); + require(manifest.at("api_version") == FASET_EDITOR_API_VERSION && + manifest.at("build_fingerprint") == fingerprint(), + "plugin.compatibility", + "Plugin manifest does not match this Editor SDK; rebuild it"); + project_path(entry.path().parent_path(), manifest.at("library").get()); + sources.emplace(id, Source{manifest, entry.path().parent_path()}); + } catch (const std::exception& error) { + failure(id, error.what()); + } + } + std::map colors; + std::vector order; + std::function visit = [&](const std::string& id) { + require(sources.contains(id) && !invalid.contains(id), "plugin.dependency", + "Missing or invalid dependency: " + id); + require(colors[id] != 1, "plugin.cycle", "Plugin dependency cycle at " + id); + if (colors[id] == 2) + return; + colors[id] = 1; + for (const auto& dependency : sources.at(id).manifest.at("dependencies")) { + const std::string required = dependency.at("id"); + visit(required); + require(sources.at(required).manifest.at("module_version") == dependency.at("version"), + "plugin.dependency_version", "Dependency version mismatch: " + required); + } + colors[id] = 2; + order.push_back(id); + }; + for (const auto& [id, source] : sources) + try { + visit(id); + } catch (const std::exception& error) { + failure(id, error.what()); + } + std::set loaded; + for (const auto& id : order) + if (!invalid.contains(id)) + try { + const auto& source = sources.at(id); + for (const auto& dependency : source.manifest.at("dependencies")) + require(loaded.contains(dependency.at("id").get()), + "plugin.dependency_failed", "A required plugin failed to load"); + impl_->activate(source.manifest, source.directory); + loaded.insert(id); + impl_->records.push_back({{"id", id}, + {"version", source.manifest.at("module_version")}, + {"state", "loaded"}}); + } catch (const std::exception& error) { + failure(id, error.what()); + } +} +} // namespace faset::editor diff --git a/src/editor/session.cpp b/src/editor/session.cpp new file mode 100644 index 0000000..5cf1710 --- /dev/null +++ b/src/editor/session.cpp @@ -0,0 +1,358 @@ +#include +#include +#include +#include +#include + +namespace faset::editor { +namespace { +std::string executable_name(const std::string& name) { +#ifdef _WIN32 + return name + ".exe"; +#else + return name; +#endif +} +BuildConfig build_config(const SessionConfig& config) { + BuildConfig result; + result.project_root = config.project_root; + result.engine_root = config.engine_root; + result.build_directory = config.project_root / ".faset/build"; + result.cache_root = config.project_root / ".faset/cache"; + return result; +} +Json resolved_or_throw(Commands& commands, const std::string& id) { + const auto resolved = commands.resolved_scene(id); + if (!resolved.at("conflicts").empty()) + throw Error("template.conflicts", "Resolve template conflicts before Play or export", + {{"conflicts", resolved.at("conflicts")}}); + return resolved.at("scene"); +} +} // namespace +struct Session::ImportTask { + std::string id; + std::shared_ptr job = std::make_shared(); + mutable std::mutex mutex; + std::string state = "queued", error; + Json result = Json::object(); + Json json() const { + std::lock_guard lock(mutex); + const auto progress = job->progress(); + return {{"id", id}, + {"kind", "import"}, + {"state", state}, + {"stage", progress.stage}, + {"progress", progress.fraction}, + {"error", error}, + {"result", result}}; + } +}; +Session::Session(SessionConfig config) + : config_(std::move(config)), authoring_(config_.project_root), commands_(authoring_), + assets_(config_.project_root / ".faset/cache"), builds_(build_config(config_)) { + register_commands(); + plugins_ = std::make_unique( + commands_, [this](std::string message) { log(std::move(message)); }); + plugins_->load(config_.project_root / "Plugins"); + const auto schema = config_.project_root / ".faset/schema.json"; + if (std::filesystem::exists(schema)) + try { + load_schema(schema); + } catch (const std::exception& error) { + log(std::string("Schema load failed: ") + error.what()); + } +} +Session::~Session() { + for (const auto& [id, task] : imports_) + task->job->cancel(); + workers_.clear(); + stop_player(); +} +void Session::log(std::string value) { + if (value.empty()) + return; + logs_.push_back(std::move(value)); + if (logs_.size() > 1000) + logs_.erase(logs_.begin(), logs_.begin() + 100); +} +Json Session::project() const { + const auto path = config_.project_root / "project.faset.json"; + if (std::filesystem::exists(path)) + return read_json(path); + return {{"format", "faset.project"}, + {"version", 1}, + {"name", config_.project_root.filename().string()}, + {"dimension", 3}}; +} +void Session::scaffold(const std::string& name, int dimension) { + builds_.scaffold(name, dimension); + log("Created project: " + name); +} +Json Session::assets_list() const { + Json list = Json::array(); + const auto directory = assets_.cache_root() / "assets"; + if (std::filesystem::exists(directory)) + for (const auto& entry : std::filesystem::directory_iterator(directory)) + if (entry.is_directory()) { + try { + const auto id = entry.path().filename().string(); + const auto manifest = assets_.current_manifest(id); + list.push_back({{"id", id}, {"manifest", manifest}}); + } catch (const std::exception& error) { + list.push_back( + {{"id", entry.path().filename().string()}, {"error", error.what()}}); + } + } + return {{"assets", list}}; +} +Json Session::jobs() const { + Json list = Json::array(); + for (const auto& item : builds_.jobs()) + list.push_back(item.json()); + for (const auto& [id, task] : imports_) + list.push_back(task->json()); + return {{"jobs", list}}; +} +Json Session::job(const std::string& id) const { + if (imports_.contains(id)) + return imports_.at(id)->json(); + return builds_.job(id).json(); +} +void Session::load_schema(const std::filesystem::path& path) { + const auto value = read_json(path); + authoring_.replace_external_schemas(value); + const auto output = config_.project_root / ".faset/schema.json"; + if (std::filesystem::weakly_canonical(path) != std::filesystem::weakly_canonical(output)) + atomic_write_json(output, value); + log("Gameplay schema loaded"); +} +void Session::launch_player(Json scene, const std::filesystem::path& executable) { + require(std::filesystem::is_regular_file(executable), "play.missing_player", + "Build the Player before starting Play"); + const auto directory = config_.project_root / ".faset/play" / new_id(); + std::filesystem::create_directories(directory); + const auto snapshot = directory / "scene.fscene"; + write_cooked_scene(snapshot, scene); + control_path_ = directory / "control.json"; + control_sequence_ = 0; + ProcessOptions options; + options.arguments = { + executable.string(), "--scene", snapshot.string(), "--assets", + assets_.cache_root().string(), "--control", control_path_.string()}; + options.working_directory = config_.project_root; + player_ = std::make_unique(options); + log("Play started in a separate Player process"); +} +void Session::stop_player() { + if (!pending_play_job_.empty()) { + builds_.cancel(pending_play_job_); + pending_play_job_.clear(); + pending_play_scene_ = nullptr; + } + if (player_) { + player_->cancel(); + const auto result = player_->poll(); + log(result.output); + player_.reset(); + log("Play stopped; authoring scene unchanged"); + } +} +void Session::poll() { + if (player_) { + const auto result = player_->poll(); + log(result.output); + if (!result.running) { + log("Player exited with code " + std::to_string(result.exit_code.value_or(-1))); + player_.reset(); + } + } + for (const auto& value : builds_.jobs()) { + if (observed_jobs_[value.id] == value.state) + continue; + observed_jobs_[value.id] = value.state; + if (value.state == "failed") + log(value.kind + " failed: " + value.error); + if (value.state == "succeeded") { + log(value.kind + " completed"); + if (value.result.contains("schema")) + try { + load_schema(value.result.at("schema").get()); + } catch (const std::exception& error) { + log(std::string("Schema update failed: ") + error.what()); + } + } + if (value.id == pending_play_job_ && value.finished()) { + pending_play_job_.clear(); + if (value.state == "succeeded") + try { + const auto executable = + value.result.value("player", (builds_.config().build_directory / + executable_name("faset_player")) + .string()); + launch_player(pending_play_scene_, executable); + } catch (const std::exception& error) { + log(std::string("Play failed: ") + error.what()); + } + pending_play_scene_ = nullptr; + } + } + for (const auto& [id, task] : imports_) { + const auto value = task->json(); + const auto status = value.at("state").get(); + if (observed_jobs_[id] == status) + continue; + observed_jobs_[id] = status; + if (status == "succeeded") + log("Asset import completed: " + value["result"].value("asset_id", std::string())); + if (status == "failed" || status == "conflict") + log("Asset import " + status + ": " + value.value("error", std::string())); + } +} +void Session::register_commands() { + const Json text = {{"type", "string"}}, boolean = {{"type", "boolean"}}; + auto schema = [](Json properties, Json required = Json::array()) { + return Commands::object_schema(std::move(properties), std::move(required)); + }; + commands_.add( + "faset_capabilities", "Inspect available Editor services and rendering capabilities.", + schema(Json::object()), + [&](const Json&) { + bool screenshot = false; + for (const auto& command : commands_.list()) + if (command.at("name") == "faset_editor_capture") + screenshot = true; + return Json{{"authoring", true}, + {"build", true}, + {"import", true}, + {"plugins", true}, + {"viewport_capture", screenshot}, + {"runtime_entity_access", false}, + {"protocol", "2025-06-18"}}; + }, + true); + commands_.add( + "faset_plugins", "Inspect startup-loaded Editor plugins and exact SDK compatibility.", + schema(Json::object()), + [&](const Json&) { + return Json{{"sdk_fingerprint", PluginManager::fingerprint()}, + {"plugins", plugins_->status()}, + {"panels", plugins_->panels()}}; + }, + true); + commands_.add( + "faset_project", "Read the authoring project's settings.", schema(Json::object()), + [&](const Json&) { return project(); }, true); + commands_.add( + "faset_assets", "List imported asset manifests and resource identities.", + schema(Json::object()), [&](const Json&) { return assets_list(); }, true); + commands_.add("faset_import", + "Import GLB/glTF or a Blender export manifest relative to this project. Returns " + "a cancellable job ID; failure retains the last successful generation.", + schema({{"path", text}, + {"settings", {{"type", "object"}}}, + {"allow_removed_outputs", boolean}}, + {"path"}), + [&](const Json& args) { + assets::ImportRequest request; + request.source = + project_path(config_.project_root, args.at("path").get()); + request.settings = args.value("settings", Json(nullptr)); + request.allow_removed_outputs = args.value("allow_removed_outputs", false); + auto task = std::make_shared(); + task->id = "import-" + new_id(); + imports_[task->id] = task; + workers_.emplace_back([this, task, request] { + { + std::lock_guard lock(task->mutex); + task->state = "running"; + } + try { + const auto result = assets_.import_asset(request, *task->job); + std::lock_guard lock(task->mutex); + task->state = + result.status == assets::ImportStatus::succeeded ? "succeeded" + : result.status == assets::ImportStatus::cancelled ? "cancelled" + : result.status == assets::ImportStatus::conflict ? "conflict" + : "failed"; + task->result = {{"asset_id", result.asset_id}, + {"generation", result.generation}, + {"diagnostics", result.diagnostics}, + {"cache_hit", result.cache_hit}, + {"manifest", result.manifest}}; + for (const auto& message : result.diagnostics) + task->error += message + "\n"; + } catch (const std::exception& error) { + std::lock_guard lock(task->mutex); + task->state = "failed"; + task->error = error.what(); + } + }); + return Json{{"job", task->id}}; + }); + commands_.add("faset_build", + "Incrementally compile C++ gameplay and export its metadata in separate native " + "processes. Returns a job ID.", + schema(Json::object()), + [&](const Json&) { return Json{{"job", builds_.start_build()}}; }); + commands_.add("faset_export", + "Build, validate and export a resolved authoring snapshot to a project-relative " + "output directory. Returns a job ID.", + schema({{"document", text}, {"output", text}}, {"document", "output"}), + [&](const Json& args) { + return Json{{"job", builds_.start_export( + resolved_or_throw(commands_, args.at("document")), + project_path(config_.project_root, + args.at("output").get()))}}; + }); + commands_.add( + "faset_jobs", "List editor import/build/export jobs and their progress.", + schema(Json::object()), [&](const Json&) { return jobs(); }, true); + commands_.add( + "faset_job", "Read an editor job's progress, result and diagnostics.", + schema({{"id", text}}, {"id"}), [&](const Json& args) { return job(args.at("id")); }, true); + commands_.add("faset_job_cancel", + "Cancel an editor job. Cancellation is separate from authoring Undo.", + schema({{"id", text}}, {"id"}), [&](const Json& args) { + const auto id = args.at("id").get(); + if (imports_.contains(id)) + imports_.at(id)->job->cancel(); + else + builds_.cancel(id); + return Json{{"cancel_requested", true}}; + }); + commands_.add("faset_play", + "Build gameplay, then start a separate Player from an immutable snapshot of the " + "current authoring document. Returns the build job ID.", + schema({{"document", text}}, {"document"}), [&](const Json& args) { + stop_player(); + pending_play_scene_ = resolved_or_throw(commands_, args.at("document")); + pending_play_job_ = builds_.start_build(); + return Json{{"job", pending_play_job_}, {"play_pending", true}}; + }); + commands_.add( + "faset_stop", + "Stop editor Play or cancel its pending build. Does not modify the authoring scene.", + schema(Json::object()), [&](const Json&) { + stop_player(); + return Json{{"stopped", true}}; + }); + commands_.add("faset_play_control", + "Pause, resume, or single-step the Editor's Player session. No game entities or " + "state are exposed.", + schema({{"command", {{"type", "string"}, {"enum", {"pause", "resume", "step"}}}}}, + {"command"}), + [&](const Json& args) { + require(bool(player_), "play.not_running", "Player is not running"); + const auto command = args.at("command").get(); + require(command == "pause" || command == "resume" || command == "step", + "play.command", "Unknown Play control"); + atomic_write_json(control_path_, + {{"sequence", ++control_sequence_}, {"command", command}}); + return Json{{"queued", true}}; + }); + commands_.add( + "faset_editor_logs", + "Read compiler, importer and process diagnostics collected by this Editor session.", + schema(Json::object()), [&](const Json&) { return Json{{"logs", logs_}}; }, true); +} +} // namespace faset::editor diff --git a/src/player/SceneView.cpp b/src/player/SceneView.cpp new file mode 100644 index 0000000..5f7d6a1 --- /dev/null +++ b/src/player/SceneView.cpp @@ -0,0 +1,378 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#if defined(FASET_HAS_STB) +#define STB_IMAGE_IMPLEMENTATION +#define STBI_NO_STDIO +#include +#endif + +namespace faset::player { +namespace { +using Json = nlohmann::json; +Json properties(const Json& entity, const std::string& name) { + if (entity.contains(name)) + return entity.at(name); + if (entity.contains("components")) + for (const auto& c : entity["components"]) + if (c.at("type") == "faset." + name) + return c.at("fields"); + return Json{}; +} +template +std::array vec(const Json& value, const char* name, std::array fallback) { + if (value.is_null() || !value.contains(name)) + return fallback; + auto result = value.at(name).get>(); + for (float v : result) + if (!std::isfinite(v)) + throw std::runtime_error("nonfinite scene vector"); + return result; +} +render::Vec3 point(const render::Mat4& m, render::Vec3 p) { + return {m[0] * p[0] + m[4] * p[1] + m[8] * p[2] + m[12], + m[1] * p[0] + m[5] * p[1] + m[9] * p[2] + m[13], + m[2] * p[0] + m[6] * p[1] + m[10] * p[2] + m[14]}; +} +render::Vec3 direction(const render::Mat4& m, render::Vec3 p) { + return {m[0] * p[0] + m[4] * p[1] + m[8] * p[2], m[1] * p[0] + m[5] * p[1] + m[9] * p[2], + m[2] * p[0] + m[6] * p[1] + m[10] * p[2]}; +} +std::pair reference(const std::string& ref) { + const auto hash = ref.find('#'); + return {ref.substr(0, hash), hash == std::string::npos ? std::string{} : ref.substr(hash + 1)}; +} +std::shared_ptr plane() { + static const auto mesh = []() { + auto out = std::make_shared(); + out->vertices = {{{-.5f, 0, -.5f}, {0, 1, 0}, {1, 1, 1, 1}, {0, 0}}, + {{.5f, 0, -.5f}, {0, 1, 0}, {1, 1, 1, 1}, {1, 0}}, + {{.5f, 0, .5f}, {0, 1, 0}, {1, 1, 1, 1}, {1, 1}}, + {{-.5f, 0, .5f}, {0, 1, 0}, {1, 1, 1, 1}, {0, 1}}}; + out->indices = {0, 2, 1, 0, 3, 2}; + return out; + }(); + return mesh; +} +} // namespace +struct SceneView::Impl { + struct Bundle { + assets::CookedAsset data; + std::vector>> meshes; + std::vector> textures; + }; + assets::AssetStore pipeline; + std::unordered_map bundles; + std::vector messages; + explicit Impl(std::filesystem::path path) : pipeline(std::move(path)) {} + Bundle& bundle(const std::string& id) { + if (auto it = bundles.find(id); it != bundles.end()) + return it->second; + Bundle result; + result.data = pipeline.load_asset(id); + for (const auto& mesh : result.data.meshes) { + auto& primitives = result.meshes.emplace_back(); + for (const auto& primitive : mesh.primitives) { + auto converted = std::make_shared(); + converted->indices = primitive.indices; + converted->vertices.reserve(primitive.vertices.size()); + for (const auto& vertex : primitive.vertices) + converted->vertices.push_back( + {vertex.position, vertex.normal, {1, 1, 1, 1}, vertex.uv}); + primitives.push_back(std::move(converted)); + } + } + for (const auto& texture : result.data.textures) { + std::shared_ptr converted; +#if defined(FASET_HAS_STB) + if (texture.bytes.size() > std::size_t(std::numeric_limits::max())) + throw std::runtime_error("Encoded texture exceeds decoder limit"); + int width = 0, height = 0, channels = 0; + if (!stbi_info_from_memory(reinterpret_cast(texture.bytes.data()), + static_cast(texture.bytes.size()), &width, &height, + &channels)) + throw std::runtime_error("Cannot read texture dimensions: " + texture.id); + if (width <= 0 || height <= 0 || width > 16384 || height > 16384 || + std::uint64_t(width) * std::uint64_t(height) > 64 * 1024 * 1024) + throw std::runtime_error("Texture exceeds decoder image limits"); + auto pixels = stbi_load_from_memory( + reinterpret_cast(texture.bytes.data()), + static_cast(texture.bytes.size()), &width, &height, &channels, 4); + if (!pixels) + throw std::runtime_error("Cannot decode texture " + texture.id + ": " + + std::string(stbi_failure_reason() ? stbi_failure_reason() + : "unsupported image")); + std::unique_ptr guard(pixels, + &stbi_image_free); + if (width <= 0 || height <= 0 || width > 16384 || height > 16384) + throw std::runtime_error("Texture exceeds 16384 dimension limit"); + converted = std::make_shared(); + converted->width = width; + converted->height = height; + converted->srgb = true; + converted->rgba.assign(pixels, pixels + std::size_t(width) * std::size_t(height) * 4); +#else + throw std::runtime_error("Image decoding was not enabled for this Player build"); +#endif + result.textures.push_back(std::move(converted)); + } + return bundles.emplace(id, std::move(result)).first->second; + } + std::shared_ptr texture(const std::string& ref) { + auto [id, selector] = reference(ref); + auto& asset = bundle(id); + if (asset.textures.empty()) + throw std::runtime_error("Asset has no texture: " + ref); + if (selector.empty()) + return asset.textures.front(); + for (std::size_t i = 0; i < asset.data.textures.size(); ++i) + if (asset.data.textures[i].id == selector) + return asset.textures[i]; + throw std::runtime_error("Texture subasset does not exist: " + ref); + } + void imported(render::Snapshot& out, const std::string& ref, const render::Mat4& model, + render::Color tint) { + const auto [id, selector] = reference(ref); + auto& asset = bundle(id); + auto emit = [&](std::size_t meshIndex, const render::Mat4& local) { + if (meshIndex >= asset.meshes.size()) + throw std::runtime_error("Invalid cooked mesh index"); + for (std::size_t p = 0; p < asset.meshes[meshIndex].size(); ++p) { + render::DrawItem draw; + draw.mesh = asset.meshes[meshIndex][p]; + draw.model = render::multiply(model, local); + draw.color = tint; + const auto material = asset.data.meshes[meshIndex].primitives[p].material; + if (material >= 0) { + if (std::size_t(material) >= asset.data.materials.size()) + throw std::runtime_error("Invalid cooked material index"); + const auto& m = asset.data.materials[material]; + for (int i = 0; i < 4; ++i) + draw.color[i] *= m.base_color[i]; + draw.roughness = m.roughness; + draw.metallic = m.metallic; + if (m.base_color_texture >= 0) { + if (std::size_t(m.base_color_texture) >= asset.textures.size()) + throw std::runtime_error("Invalid base-color texture index"); + draw.texture = asset.textures[m.base_color_texture]; + } + if (m.normal_texture >= 0 || m.metallic_roughness_texture >= 0 || + m.alpha_mode != "OPAQUE" || m.unlit || m.double_sided) + messages.push_back( + "warning: material " + m.id + + " has features beyond the initial base-color/PBR renderer"); + } + out.draws.push_back(std::move(draw)); + } + }; + if (!selector.empty()) + for (std::size_t i = 0; i < asset.data.meshes.size(); ++i) + if (asset.data.meshes[i].id == selector) { + emit(i, render::identity); + return; + } + std::unordered_map nodes; + for (const auto& node : asset.data.nodes) + nodes.emplace(node.id, &node); + if (!selector.empty() && !nodes.contains(selector)) + throw std::runtime_error("Node/mesh subasset does not exist: " + ref); + std::unordered_map matrices; + std::set active; + auto world = [&](auto&& self, const assets::Node& node) -> render::Mat4 { + if (auto it = matrices.find(node.id); it != matrices.end()) + return it->second; + if (!active.insert(node.id).second) + throw std::runtime_error("Cyclic cooked node hierarchy"); + auto matrix = node.local_transform; + if (!node.parent_id.empty()) { + auto parent = nodes.find(node.parent_id); + if (parent == nodes.end()) + throw std::runtime_error("Missing cooked parent node"); + matrix = render::multiply(self(self, *parent->second), matrix); + } + active.erase(node.id); + return matrices.emplace(node.id, matrix).first->second; + }; + if (asset.data.nodes.empty()) + for (std::size_t i = 0; i < asset.meshes.size(); ++i) + emit(i, render::identity); + for (const auto& node : asset.data.nodes) + if (node.mesh >= 0) { + bool selected = selector.empty(); + auto current = &node; + std::set seen; + while (!selected && current && seen.insert(current->id).second) { + selected = current->id == selector; + auto parent = nodes.find(current->parent_id); + current = parent == nodes.end() ? nullptr : parent->second; + } + if (selected) + emit(static_cast(node.mesh), world(world, node)); + } + } +}; +SceneView::SceneView(std::filesystem::path cacheRoot) + : impl_(std::make_unique(std::move(cacheRoot))) {} +SceneView::~SceneView() = default; +void SceneView::clearCache() { + impl_->bundles.clear(); +} +const std::vector& SceneView::diagnostics() const { + return impl_->messages; +} +render::Snapshot SceneView::build(const Json& scene, float aspect, CameraSettings camera) { + if (!std::isfinite(aspect) || aspect <= 0) + throw std::invalid_argument("Viewport aspect must be positive"); + impl_->messages.clear(); + render::Snapshot out; + const auto& entities = scene.at("entities"); + if (!entities.is_array()) + throw std::invalid_argument("Scene entities must be an array"); + std::unordered_map byId; + for (const auto& entity : entities) + if (!byId.emplace(entity.at("id").get(), &entity).second) + throw std::invalid_argument("Duplicate scene ID"); + std::unordered_map matrices; + std::set active; + auto world = [&](auto&& self, const Json& entity) -> render::Mat4 { + auto id = entity.at("id").get(); + if (auto it = matrices.find(id); it != matrices.end()) + return it->second; + if (!active.insert(id).second) + throw std::invalid_argument("Cyclic scene hierarchy"); + const auto fields = properties(entity, "transform"); + auto matrix = render::transform(vec<3>(fields, "position", {0, 0, 0}), + vec<3>(fields, "rotation", {0, 0, 0}), + vec<3>(fields, "scale", {1, 1, 1})); + if (entity.contains("parent") && !entity["parent"].is_null()) { + auto parent = byId.find(entity["parent"].get()); + if (parent == byId.end()) + throw std::invalid_argument("Missing scene parent"); + matrix = render::multiply(self(self, *parent->second), matrix); + } + active.erase(id); + return matrices.emplace(id, matrix).first->second; + }; + const int dimension = scene.value("dimension", 3); + if (dimension != 2 && dimension != 3) + throw std::invalid_argument("Scene dimension must be 2 or 3"); + render::Vec3 cameraUp{0, 1, 0}; + bool foundCamera = false; + std::vector> sprites; + for (const auto& entity : entities) { + const auto model = world(world, entity); + if (auto fields = properties(entity, "camera"); + !fields.is_null() && !camera.overrideSceneCamera && !foundCamera) { + camera.eye = point(model, {0, 0, 0}); + camera.target = point(model, {0, 0, -1}); + cameraUp = direction(model, {0, 1, 0}); + camera.verticalFovDegrees = fields.value("fov", 60.0f); + camera.nearPlane = fields.value("near", 0.1f); + camera.farPlane = fields.value("far", 1000.0f); + foundCamera = true; + } + if (auto fields = properties(entity, "light"); !fields.is_null()) + out.light_direction = direction(model, {-0.5f, -1, -0.3f}); + if (auto fields = properties(entity, "sprite"); !fields.is_null()) { + render::Sprite sprite; + sprite.position = point(model, {0, 0, 0}); + auto size = vec<2>(fields, "size", {1, 1}); + float sx = std::hypot(model[0], model[1]), sy = std::hypot(model[4], model[5]); + sprite.size = {size[0] * sx, size[1] * sy}; + sprite.rotation = std::atan2(model[1], model[0]); + sprite.color = vec<4>(fields, "color", {1, 1, 1, 1}); + if (model[0] * model[5] - model[1] * model[4] < 0) + sprite.size[1] = -sprite.size[1]; + if (sx > 0 && sy > 0 && + std::abs((model[0] * model[4] + model[1] * model[5]) / (sx * sy)) > 0.0001f) + impl_->messages.push_back("warning: sprite hierarchy shear is approximated"); + auto texture = fields.value("texture", std::string{}); + if (!texture.empty()) + try { + sprite.texture = impl_->texture(texture); + } catch (const std::exception& e) { + impl_->messages.push_back("error: " + std::string(e.what())); + sprite.color = {1, 0, 1, 1}; + } + sprites.emplace_back(fields.value("layer", 0), std::move(sprite)); + } + if (auto fields = properties(entity, "mesh"); !fields.is_null()) { + const auto tint = vec<4>(fields, "color", {1, 1, 1, 1}); + const auto asset = fields.value("asset", std::string{}); + if (asset.empty() || asset.starts_with("builtin:")) { + const auto primitive = asset.empty() + ? fields.value("primitive", std::string("cube")) + : asset.substr(8); + if (primitive != "plane" && primitive != "cube") + throw std::invalid_argument("Unsupported builtin mesh: " + primitive); + out.draws.push_back({primitive == "plane" ? plane() : render::cube_mesh(), + model, + tint, + 0.65f, + 0.0f, + true, + {}}); + } else + try { + impl_->imported(out, asset, model, tint); + } catch (const std::exception& e) { + impl_->messages.push_back("error: " + std::string(e.what())); + out.draws.push_back( + {render::cube_mesh(), model, {1, 0, 1, 1}, 0.65f, 0.0f, true, {}}); + } + } + } + std::stable_sort(sprites.begin(), sprites.end(), + [](const auto& a, const auto& b) { return a.first < b.first; }); + for (auto& pair : sprites) + out.sprites.push_back(std::move(pair.second)); + if (dimension == 2) { + const float height = camera.orthographicHeight; + if (!std::isfinite(height) || height <= 0) + throw std::invalid_argument("Orthographic height must be positive"); + const auto center = foundCamera ? camera.eye : camera.target; + out.view_projection = + render::multiply(render::orthographic(-height * aspect / 2, height * aspect / 2, + -height / 2, height / 2, -100, 100), + render::transform({-center[0], -center[1], 0})); + out.eye = {center[0], center[1], 10}; + } else { + if (!std::isfinite(camera.verticalFovDegrees) || camera.verticalFovDegrees <= 0 || + camera.verticalFovDegrees >= 179) + throw std::invalid_argument("Camera FOV out of range"); + if (!std::isfinite(camera.nearPlane) || !std::isfinite(camera.farPlane) || + camera.nearPlane <= 0 || camera.farPlane <= camera.nearPlane) + throw std::invalid_argument("Camera depth range is invalid"); + float distance = 0; + render::Vec3 delta{}; + for (int i = 0; i < 3; ++i) { + if (!std::isfinite(camera.eye[i]) || !std::isfinite(camera.target[i]) || + !std::isfinite(cameraUp[i])) + throw std::invalid_argument("Camera basis must be finite"); + delta[i] = camera.target[i] - camera.eye[i]; + distance += delta[i] * delta[i]; + } + const render::Vec3 cross{delta[1] * cameraUp[2] - delta[2] * cameraUp[1], + delta[2] * cameraUp[0] - delta[0] * cameraUp[2], + delta[0] * cameraUp[1] - delta[1] * cameraUp[0]}; + if (distance < 1e-10f || + cross[0] * cross[0] + cross[1] * cross[1] + cross[2] * cross[2] < 1e-10f) + throw std::invalid_argument("Camera basis is degenerate"); + out.eye = camera.eye; + out.view_projection = render::multiply( + render::perspective(camera.verticalFovDegrees * std::numbers::pi_v / 180, aspect, + camera.nearPlane, camera.farPlane), + render::look_at(camera.eye, camera.target, cameraUp)); + } + std::sort(impl_->messages.begin(), impl_->messages.end()); + impl_->messages.erase(std::unique(impl_->messages.begin(), impl_->messages.end()), + impl_->messages.end()); + return out; +} +} // namespace faset::player diff --git a/src/player/scene_io.cpp b/src/player/scene_io.cpp new file mode 100644 index 0000000..0e1caaa --- /dev/null +++ b/src/player/scene_io.cpp @@ -0,0 +1,32 @@ +#include +#include +#include +#include + +namespace faset::player { +nlohmann::json readScene(const std::filesystem::path& path) { + if (!std::filesystem::is_regular_file(path)) + throw std::runtime_error("Scene file does not exist: " + path.string()); + if (std::filesystem::file_size(path) > 256 * 1024 * 1024) + throw std::runtime_error("Scene exceeds the 256 MiB reader limit"); + const auto bytes = faset::read_text(path); + if (bytes.size() >= 8 && std::memcmp(bytes.data(), "FASETSCN", 8) == 0) { + if (bytes.size() < 20) + throw std::runtime_error("Truncated cooked scene header"); + std::uint32_t version = 0; + std::uint64_t size = 0; + for (int i = 0; i < 4; ++i) + version |= std::uint32_t(static_cast(bytes[8 + i])) << (8 * i); + for (int i = 0; i < 8; ++i) + size |= std::uint64_t(static_cast(bytes[12 + i])) << (8 * i); + if (version != 1) + throw std::runtime_error("Unsupported cooked scene version"); + if (size != bytes.size() - 20) + throw std::runtime_error("Cooked scene payload size mismatch"); + return nlohmann::json::from_cbor(bytes.begin() + 20, bytes.end(), true, true); + } + if (path.extension() == ".fscene") + throw std::runtime_error("Cooked scene magic is invalid"); + return nlohmann::json::parse(bytes); +} +} // namespace faset::player diff --git a/src/render/math.cpp b/src/render/math.cpp index f444301..8eef458 100644 --- a/src/render/math.cpp +++ b/src/render/math.cpp @@ -1,26 +1,87 @@ -#include #include +#include #include namespace faset::render { namespace { -Vec3 sub(Vec3 a, Vec3 b) { return {a[0]-b[0],a[1]-b[1],a[2]-b[2]}; } -float dot(Vec3 a,Vec3 b){return a[0]*b[0]+a[1]*b[1]+a[2]*b[2];} -Vec3 cross(Vec3 a,Vec3 b){return {a[1]*b[2]-a[2]*b[1],a[2]*b[0]-a[0]*b[2],a[0]*b[1]-a[1]*b[0]};} -Vec3 unit(Vec3 a){float l=std::sqrt(dot(a,a)); if(l<1e-6f) throw std::invalid_argument("Degenerate camera axis"); return {a[0]/l,a[1]/l,a[2]/l};} +Vec3 sub(Vec3 a, Vec3 b) { + return {a[0] - b[0], a[1] - b[1], a[2] - b[2]}; } -Mat4 multiply(const Mat4& a,const Mat4& b){Mat4 r{};for(int c=0;c<4;++c)for(int y=0;y<4;++y)for(int k=0;k<4;++k)r[c*4+y]+=a[k*4+y]*b[c*4+k];return r;} -Mat4 transform(Vec3 p,Vec3 r,Vec3 s){ - const float cx=std::cos(r[0]),sx=std::sin(r[0]),cy=std::cos(r[1]),sy=std::sin(r[1]),cz=std::cos(r[2]),sz=std::sin(r[2]); - Mat4 x{1,0,0,0,0,cx,sx,0,0,-sx,cx,0,0,0,0,1}; - Mat4 y{cy,0,-sy,0,0,1,0,0,sy,0,cy,0,0,0,0,1}; - Mat4 z{cz,sz,0,0,-sz,cz,0,0,0,0,1,0,0,0,0,1}; - auto m=multiply(z,multiply(y,x));for(int c=0;c<3;++c)for(int i=0;i<3;++i)m[c*4+i]*=s[c];m[12]=p[0];m[13]=p[1];m[14]=p[2];return m; +float dot(Vec3 a, Vec3 b) { + return a[0] * b[0] + a[1] * b[1] + a[2] * b[2]; } -Mat4 perspective(float fov,float aspect,float n,float f){if(aspect<=0||n<=0||f<=n)throw std::invalid_argument("Invalid perspective volume");float q=1/std::tan(fov*.5f);return {q/aspect,0,0,0,0,-q,0,0,0,0,f/(n-f),-1,0,0,n*f/(n-f),0};} -Mat4 orthographic(float l,float r,float b,float t,float n,float f){if(r==l||t==b||f==n)throw std::invalid_argument("Invalid orthographic volume");return {2/(r-l),0,0,0,0,-2/(t-b),0,0,0,0,1/(n-f),0,-(r+l)/(r-l),(t+b)/(t-b),n/(n-f),1};} -Mat4 look_at(Vec3 e,Vec3 t,Vec3 up){auto f=unit(sub(t,e));auto s=unit(cross(f,up));auto u=cross(s,f);return {s[0],u[0],-f[0],0,s[1],u[1],-f[1],0,s[2],u[2],-f[2],0,-dot(s,e),-dot(u,e),dot(f,e),1};} -std::shared_ptr cube_mesh(){static auto mesh=[](){auto m=std::make_shared(); - const Vec3 normals[]={{0,0,1},{0,0,-1},{1,0,0},{-1,0,0},{0,1,0},{0,-1,0}}; - const Vec3 points[][4]={{{-.5f,-.5f,.5f},{.5f,-.5f,.5f},{.5f,.5f,.5f},{-.5f,.5f,.5f}},{{.5f,-.5f,-.5f},{-.5f,-.5f,-.5f},{-.5f,.5f,-.5f},{.5f,.5f,-.5f}},{{.5f,-.5f,.5f},{.5f,-.5f,-.5f},{.5f,.5f,-.5f},{.5f,.5f,.5f}},{{-.5f,-.5f,-.5f},{-.5f,-.5f,.5f},{-.5f,.5f,.5f},{-.5f,.5f,-.5f}},{{-.5f,.5f,.5f},{.5f,.5f,.5f},{.5f,.5f,-.5f},{-.5f,.5f,-.5f}},{{-.5f,-.5f,-.5f},{.5f,-.5f,-.5f},{.5f,-.5f,.5f},{-.5f,-.5f,.5f}}}; - for(int face=0;face<6;++face){for(auto p:points[face])m->vertices.push_back({p,normals[face],{1,1,1,1}});for(auto i:{0u,1u,2u,0u,2u,3u})m->indices.push_back(face*4+i);}return m;}();return mesh;} +Vec3 cross(Vec3 a, Vec3 b) { + return {a[1] * b[2] - a[2] * b[1], a[2] * b[0] - a[0] * b[2], a[0] * b[1] - a[1] * b[0]}; } +Vec3 unit(Vec3 a) { + float l = std::sqrt(dot(a, a)); + if (l < 1e-6f) + throw std::invalid_argument("Degenerate camera axis"); + return {a[0] / l, a[1] / l, a[2] / l}; +} +} // namespace +Mat4 multiply(const Mat4& a, const Mat4& b) { + Mat4 r{}; + for (int c = 0; c < 4; ++c) + for (int y = 0; y < 4; ++y) + for (int k = 0; k < 4; ++k) + r[c * 4 + y] += a[k * 4 + y] * b[c * 4 + k]; + return r; +} +Mat4 transform(Vec3 p, Vec3 r, Vec3 s) { + const float cx = std::cos(r[0]), sx = std::sin(r[0]), cy = std::cos(r[1]), sy = std::sin(r[1]), + cz = std::cos(r[2]), sz = std::sin(r[2]); + Mat4 x{1, 0, 0, 0, 0, cx, sx, 0, 0, -sx, cx, 0, 0, 0, 0, 1}; + Mat4 y{cy, 0, -sy, 0, 0, 1, 0, 0, sy, 0, cy, 0, 0, 0, 0, 1}; + Mat4 z{cz, sz, 0, 0, -sz, cz, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1}; + auto m = multiply(z, multiply(y, x)); + for (int c = 0; c < 3; ++c) + for (int i = 0; i < 3; ++i) + m[c * 4 + i] *= s[c]; + m[12] = p[0]; + m[13] = p[1]; + m[14] = p[2]; + return m; +} +Mat4 perspective(float fov, float aspect, float n, float f) { + if (aspect <= 0 || n <= 0 || f <= n) + throw std::invalid_argument("Invalid perspective volume"); + float q = 1 / std::tan(fov * .5f); + return {q / aspect, 0, 0, 0, 0, -q, 0, 0, 0, 0, f / (n - f), -1, 0, 0, n * f / (n - f), 0}; +} +Mat4 orthographic(float l, float r, float b, float t, float n, float f) { + if (r == l || t == b || f == n) + throw std::invalid_argument("Invalid orthographic volume"); + return {2 / (r - l), 0, 0, 0, 0, -2 / (t - b), 0, + 0, 0, 0, 1 / (n - f), 0, -(r + l) / (r - l), (t + b) / (t - b), + n / (n - f), 1}; +} +Mat4 look_at(Vec3 e, Vec3 t, Vec3 up) { + auto f = unit(sub(t, e)); + auto s = unit(cross(f, up)); + auto u = cross(s, f); + return {s[0], u[0], -f[0], 0, s[1], u[1], -f[1], 0, + s[2], u[2], -f[2], 0, -dot(s, e), -dot(u, e), dot(f, e), 1}; +} +std::shared_ptr cube_mesh() { + static auto mesh = []() { + auto m = std::make_shared(); + const Vec3 normals[] = {{0, 0, 1}, {0, 0, -1}, {1, 0, 0}, + {-1, 0, 0}, {0, 1, 0}, {0, -1, 0}}; + const Vec3 points[][4] = { + {{-.5f, -.5f, .5f}, {.5f, -.5f, .5f}, {.5f, .5f, .5f}, {-.5f, .5f, .5f}}, + {{.5f, -.5f, -.5f}, {-.5f, -.5f, -.5f}, {-.5f, .5f, -.5f}, {.5f, .5f, -.5f}}, + {{.5f, -.5f, .5f}, {.5f, -.5f, -.5f}, {.5f, .5f, -.5f}, {.5f, .5f, .5f}}, + {{-.5f, -.5f, -.5f}, {-.5f, -.5f, .5f}, {-.5f, .5f, .5f}, {-.5f, .5f, -.5f}}, + {{-.5f, .5f, .5f}, {.5f, .5f, .5f}, {.5f, .5f, -.5f}, {-.5f, .5f, -.5f}}, + {{-.5f, -.5f, -.5f}, {.5f, -.5f, -.5f}, {.5f, -.5f, .5f}, {-.5f, -.5f, .5f}}}; + for (int face = 0; face < 6; ++face) { + for (auto p : points[face]) + m->vertices.push_back({p, normals[face], {1, 1, 1, 1}}); + for (auto i : {0u, 1u, 2u, 0u, 2u, 3u}) + m->indices.push_back(face * 4 + i); + } + return m; + }(); + return mesh; +} +} // namespace faset::render diff --git a/src/render/render_graph.cpp b/src/render/render_graph.cpp index 0ff8538..2c55c8e 100644 --- a/src/render/render_graph.cpp +++ b/src/render/render_graph.cpp @@ -3,25 +3,36 @@ #include #include namespace faset::render { -void RenderGraph::import(std::string resource) { imports_.push_back(std::move(resource)); } -void RenderGraph::add(std::string name, std::vector reads, std::vector writes, Callback execute) { - if (name.empty() || !execute) throw std::invalid_argument("RenderGraph pass requires a name and callback"); - for (const auto& pass : passes_) if (pass.name == name) throw std::invalid_argument("Duplicate RenderGraph pass: " + name); - passes_.push_back({std::move(name),std::move(reads),std::move(writes),std::move(execute)}); +void RenderGraph::import(std::string resource) { + imports_.push_back(std::move(resource)); +} +void RenderGraph::add(std::string name, std::vector reads, + std::vector writes, Callback execute) { + if (name.empty() || !execute) + throw std::invalid_argument("RenderGraph pass requires a name and callback"); + for (const auto& pass : passes_) + if (pass.name == name) + throw std::invalid_argument("Duplicate RenderGraph pass: " + name); + passes_.push_back({std::move(name), std::move(reads), std::move(writes), std::move(execute)}); } void RenderGraph::execute() const { std::unordered_set available(imports_.begin(), imports_.end()); // Validate the whole graph before recording any GPU work. for (const auto& pass : passes_) { for (const auto& resource : pass.reads) - if (!available.contains(resource)) throw std::runtime_error("RenderGraph pass '" + pass.name + "' reads uninitialized resource '" + resource + "'"); - for (const auto& resource : pass.writes) available.insert(resource); + if (!available.contains(resource)) + throw std::runtime_error("RenderGraph pass '" + pass.name + + "' reads uninitialized resource '" + resource + "'"); + for (const auto& resource : pass.writes) + available.insert(resource); } - for (const auto& pass : passes_) pass.callback(); + for (const auto& pass : passes_) + pass.callback(); } std::vector RenderGraph::pass_names() const { std::vector result; - for (const auto& pass : passes_) result.push_back(pass.name); + for (const auto& pass : passes_) + result.push_back(pass.name); return result; } -} +} // namespace faset::render diff --git a/src/render/renderer.cpp b/src/render/renderer.cpp index 5868238..afb6e76 100644 --- a/src/render/renderer.cpp +++ b/src/render/renderer.cpp @@ -1,13 +1,12 @@ -#include -#include #include #include -#include #include #include #include #include #include +#include +#include #include #include #include @@ -15,24 +14,52 @@ #include #include #include +#include namespace faset::render { namespace { -void check(VkResult result,const char* action){if(result!=VK_SUCCESS)throw std::runtime_error(std::string(action)+" failed (Vulkan "+std::to_string(result)+")");} -struct GpuVertex {float clip[4], world[3], normal[3], color[4], material[2], uv[2];}; -struct Push {Mat4 light_view_projection; std::array light_direction,eye;}; -static_assert(sizeof(Push)==96, "Slang FrameParameters layout"); -std::array point(const Mat4& m,std::array p){std::array o{};for(int r=0;r<4;++r)for(int c=0;c<4;++c)o[r]+=m[c*4+r]*p[c];return o;} -struct Buffer { VkBuffer handle{}; VkDeviceMemory memory{}; VkDeviceSize size{}; }; -struct Image {VkImage handle{}; VkDeviceMemory memory{}; VkImageView view{}; VkImageLayout layout{VK_IMAGE_LAYOUT_UNDEFINED};}; -struct Batch {std::uint32_t first{},count{}; const Texture* texture{};}; -constexpr std::uint32_t shadow_size=1024; +void check(VkResult result, const char* action) { + if (result != VK_SUCCESS) + throw std::runtime_error(std::string(action) + " failed (Vulkan " + std::to_string(result) + + ")"); } +struct GpuVertex { + float clip[4], world[3], normal[3], color[4], material[2], uv[2]; +}; +struct Push { + Mat4 light_view_projection; + std::array light_direction, eye; +}; +static_assert(sizeof(Push) == 96, "Slang FrameParameters layout"); +std::array point(const Mat4& m, std::array p) { + std::array o{}; + for (int r = 0; r < 4; ++r) + for (int c = 0; c < 4; ++c) + o[r] += m[c * 4 + r] * p[c]; + return o; +} +struct Buffer { + VkBuffer handle{}; + VkDeviceMemory memory{}; + VkDeviceSize size{}; +}; +struct Image { + VkImage handle{}; + VkDeviceMemory memory{}; + VkImageView view{}; + VkImageLayout layout{VK_IMAGE_LAYOUT_UNDEFINED}; +}; +struct Batch { + std::uint32_t first{}, count{}; + const Texture* texture{}; +}; +constexpr std::uint32_t shadow_size = 1024; +} // namespace struct Renderer::Impl { RendererConfig config; SDL_Window* window{}; - bool sdl{},close{},dirty_swapchain{}; - std::uint32_t width{},height{}; + bool sdl{}, close{}, dirty_swapchain{}; + std::uint32_t width{}, height{}; VkInstance instance{}; VkDebugUtilsMessengerEXT messenger{}; VkSurfaceKHR surface{}; @@ -46,256 +73,1403 @@ struct Renderer::Impl { VkQueryPool timestamp_pool{}; float timestamp_period{}; std::uint32_t timestamp_bits{}; - VkSemaphore acquired{},present_ready{}; + VkSemaphore acquired{}, present_ready{}; VkSwapchainKHR swapchain{}; VkFormat swap_format{}; VkExtent2D swap_extent{}; std::vector swap_images; std::vector swap_layouts; - Image color,depth,shadow; - Buffer vertices,readback; + Image color, depth, shadow; + Buffer vertices, readback; VkDescriptorSetLayout descriptor_layout{}; VkDescriptorPool descriptor_pool{}; - VkSampler shadow_sampler{},color_sampler{}; + VkSampler shadow_sampler{}, color_sampler{}; VkPipelineLayout pipeline_layout{}; - VkPipeline pipeline{},ui_pipeline{},shadow_pipeline{}; - struct GpuTexture {Image image; VkDescriptorSet descriptor{}; std::shared_ptr source; std::uint64_t revision{};}; - std::unordered_map textures; + VkPipeline pipeline{}, ui_pipeline{}, shadow_pipeline{}; + struct GpuTexture { + Image image; + VkDescriptorSet descriptor{}; + std::shared_ptr source; + std::uint64_t revision{}; + }; + std::unordered_map textures; std::shared_ptr white; std::vector last_pixels; FrameStats statistics; std::atomic validation_errors{}; - ~Impl(){cleanup();} - static VKAPI_ATTR VkBool32 VKAPI_CALL debug(VkDebugUtilsMessageSeverityFlagBitsEXT severity,VkDebugUtilsMessageTypeFlagsEXT,const VkDebugUtilsMessengerCallbackDataEXT* data,void* user){ - if(severity>=VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT)static_cast(user)->validation_errors.fetch_add(1); - if(severity>=VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT)std::cerr<<"[Vulkan] "<pMessage<<'\n';return VK_FALSE; + ~Impl() { + cleanup(); } - void destroy(Buffer& b){if(device){if(b.handle)vkDestroyBuffer(device,b.handle,nullptr);if(b.memory)vkFreeMemory(device,b.memory,nullptr);}b={};} - void destroy(Image& i){if(device){if(i.view)vkDestroyImageView(device,i.view,nullptr);if(i.handle)vkDestroyImage(device,i.handle,nullptr);if(i.memory)vkFreeMemory(device,i.memory,nullptr);}i={};} - void cleanup(){ - if(device)vkDeviceWaitIdle(device); - for(auto& [_,texture]:textures)destroy(texture.image); - destroy(vertices);destroy(readback);destroy(color);destroy(depth);destroy(shadow); - if(device){ - if(pipeline)vkDestroyPipeline(device,pipeline,nullptr);if(ui_pipeline)vkDestroyPipeline(device,ui_pipeline,nullptr);if(shadow_pipeline)vkDestroyPipeline(device,shadow_pipeline,nullptr); - if(pipeline_layout)vkDestroyPipelineLayout(device,pipeline_layout,nullptr);if(descriptor_pool)vkDestroyDescriptorPool(device,descriptor_pool,nullptr);if(descriptor_layout)vkDestroyDescriptorSetLayout(device,descriptor_layout,nullptr); - if(shadow_sampler)vkDestroySampler(device,shadow_sampler,nullptr);if(color_sampler)vkDestroySampler(device,color_sampler,nullptr); - if(swapchain)vkDestroySwapchainKHR(device,swapchain,nullptr); - if(timestamp_pool)vkDestroyQueryPool(device,timestamp_pool,nullptr); - if(acquired)vkDestroySemaphore(device,acquired,nullptr);if(present_ready)vkDestroySemaphore(device,present_ready,nullptr);if(fence)vkDestroyFence(device,fence,nullptr);if(pool)vkDestroyCommandPool(device,pool,nullptr); - vkDestroyDevice(device,nullptr); + static VKAPI_ATTR VkBool32 VKAPI_CALL debug(VkDebugUtilsMessageSeverityFlagBitsEXT severity, + VkDebugUtilsMessageTypeFlagsEXT, + const VkDebugUtilsMessengerCallbackDataEXT* data, + void* user) { + if (severity >= VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT) + static_cast(user)->validation_errors.fetch_add(1); + if (severity >= VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT) + std::cerr << "[Vulkan] " << data->pMessage << '\n'; + return VK_FALSE; + } + void destroy(Buffer& b) { + if (device) { + if (b.handle) + vkDestroyBuffer(device, b.handle, nullptr); + if (b.memory) + vkFreeMemory(device, b.memory, nullptr); } - if(surface)vkDestroySurfaceKHR(instance,surface,nullptr); - if(messenger){auto fn=reinterpret_cast(vkGetInstanceProcAddr(instance,"vkDestroyDebugUtilsMessengerEXT"));if(fn)fn(instance,messenger,nullptr);} - if(instance)vkDestroyInstance(instance,nullptr); - if(window)SDL_DestroyWindow(window);if(sdl)SDL_QuitSubSystem(SDL_INIT_VIDEO); + b = {}; } - std::uint32_t memory_type(std::uint32_t bits,VkMemoryPropertyFlags properties){VkPhysicalDeviceMemoryProperties p{};vkGetPhysicalDeviceMemoryProperties(physical,&p);for(std::uint32_t i=0;i( + vkGetInstanceProcAddr(instance, "vkDestroyDebugUtilsMessengerEXT")); + if (fn) + fn(instance, messenger, nullptr); + } + if (instance) + vkDestroyInstance(instance, nullptr); + if (window) + SDL_DestroyWindow(window); + if (sdl) + SDL_QuitSubSystem(SDL_INIT_VIDEO); } - void transition(VkCommandBuffer cmd,VkImage image,VkImageLayout& before,VkImageLayout after,VkImageAspectFlags aspect){ + std::uint32_t memory_type(std::uint32_t bits, VkMemoryPropertyFlags properties) { + VkPhysicalDeviceMemoryProperties p{}; + vkGetPhysicalDeviceMemoryProperties(physical, &p); + for (std::uint32_t i = 0; i < p.memoryTypeCount; ++i) + if ((bits & (1u << i)) && (p.memoryTypes[i].propertyFlags & properties) == properties) + return i; + throw std::runtime_error("Required Vulkan memory type is unavailable"); + } + Buffer make_buffer(VkDeviceSize bytes, VkBufferUsageFlags usage, + VkMemoryPropertyFlags properties) { + Buffer b{}; + b.size = bytes; + VkBufferCreateInfo info{VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO}; + info.size = bytes; + info.usage = usage; + info.sharingMode = VK_SHARING_MODE_EXCLUSIVE; + check(vkCreateBuffer(device, &info, nullptr, &b.handle), "Create buffer"); + try { + VkMemoryRequirements req{}; + vkGetBufferMemoryRequirements(device, b.handle, &req); + VkMemoryAllocateInfo alloc{VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO}; + alloc.allocationSize = req.size; + alloc.memoryTypeIndex = memory_type(req.memoryTypeBits, properties); + check(vkAllocateMemory(device, &alloc, nullptr, &b.memory), "Allocate buffer memory"); + check(vkBindBufferMemory(device, b.handle, b.memory, 0), "Bind buffer memory"); + } catch (...) { + destroy(b); + throw; + } + return b; + } + Image make_image(std::uint32_t w, std::uint32_t h, VkFormat format, VkImageUsageFlags usage, + VkImageAspectFlags aspect) { + Image image{}; + VkImageCreateInfo info{VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO}; + info.imageType = VK_IMAGE_TYPE_2D; + info.format = format; + info.extent = {w, h, 1}; + info.mipLevels = 1; + info.arrayLayers = 1; + info.samples = VK_SAMPLE_COUNT_1_BIT; + info.tiling = VK_IMAGE_TILING_OPTIMAL; + info.usage = usage; + info.sharingMode = VK_SHARING_MODE_EXCLUSIVE; + check(vkCreateImage(device, &info, nullptr, &image.handle), "Create image"); + try { + VkMemoryRequirements req{}; + vkGetImageMemoryRequirements(device, image.handle, &req); + VkMemoryAllocateInfo alloc{VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO}; + alloc.allocationSize = req.size; + alloc.memoryTypeIndex = + memory_type(req.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); + check(vkAllocateMemory(device, &alloc, nullptr, &image.memory), + "Allocate image memory"); + check(vkBindImageMemory(device, image.handle, image.memory, 0), "Bind image memory"); + VkImageViewCreateInfo view{VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO}; + view.image = image.handle; + view.viewType = VK_IMAGE_VIEW_TYPE_2D; + view.format = format; + view.subresourceRange = {aspect, 0, 1, 0, 1}; + check(vkCreateImageView(device, &view, nullptr, &image.view), "Create image view"); + } catch (...) { + destroy(image); + throw; + } + return image; + } + void transition(VkCommandBuffer cmd, VkImage image, VkImageLayout& before, VkImageLayout after, + VkImageAspectFlags aspect) { // Conservative dependencies make the first single-queue backend auditable. - VkImageMemoryBarrier2 barrier{VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2};barrier.srcStageMask=before==VK_IMAGE_LAYOUT_UNDEFINED?VK_PIPELINE_STAGE_2_NONE:VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT;barrier.srcAccessMask=before==VK_IMAGE_LAYOUT_UNDEFINED?0:VK_ACCESS_2_MEMORY_WRITE_BIT;barrier.dstStageMask=VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT;barrier.dstAccessMask=VK_ACCESS_2_MEMORY_READ_BIT|VK_ACCESS_2_MEMORY_WRITE_BIT;barrier.oldLayout=before;barrier.newLayout=after;barrier.srcQueueFamilyIndex=barrier.dstQueueFamilyIndex=VK_QUEUE_FAMILY_IGNORED;barrier.image=image;barrier.subresourceRange={aspect,0,1,0,1};VkDependencyInfo dependency{VK_STRUCTURE_TYPE_DEPENDENCY_INFO};dependency.imageMemoryBarrierCount=1;dependency.pImageMemoryBarriers=&barrier;vkCmdPipelineBarrier2(cmd,&dependency);before=after; + VkImageMemoryBarrier2 barrier{VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2}; + barrier.srcStageMask = before == VK_IMAGE_LAYOUT_UNDEFINED + ? VK_PIPELINE_STAGE_2_NONE + : VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT; + barrier.srcAccessMask = + before == VK_IMAGE_LAYOUT_UNDEFINED ? 0 : VK_ACCESS_2_MEMORY_WRITE_BIT; + barrier.dstStageMask = VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT; + barrier.dstAccessMask = VK_ACCESS_2_MEMORY_READ_BIT | VK_ACCESS_2_MEMORY_WRITE_BIT; + barrier.oldLayout = before; + barrier.newLayout = after; + barrier.srcQueueFamilyIndex = barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + barrier.image = image; + barrier.subresourceRange = {aspect, 0, 1, 0, 1}; + VkDependencyInfo dependency{VK_STRUCTURE_TYPE_DEPENDENCY_INFO}; + dependency.imageMemoryBarrierCount = 1; + dependency.pImageMemoryBarriers = &barrier; + vkCmdPipelineBarrier2(cmd, &dependency); + before = after; } - void transition(VkCommandBuffer cmd,Image& image,VkImageLayout after,VkImageAspectFlags aspect){transition(cmd,image.handle,image.layout,after,aspect);} - void begin(){check(vkResetCommandBuffer(command,0),"Reset command buffer");VkCommandBufferBeginInfo info{VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO};info.flags=VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;check(vkBeginCommandBuffer(command,&info),"Begin command buffer");} - void submit(bool present=false){ - check(vkEndCommandBuffer(command),"End command buffer");check(vkResetFences(device,1,&fence),"Reset fence");VkCommandBufferSubmitInfo cmd{VK_STRUCTURE_TYPE_COMMAND_BUFFER_SUBMIT_INFO};cmd.commandBuffer=command;VkSubmitInfo2 info{VK_STRUCTURE_TYPE_SUBMIT_INFO_2};info.commandBufferInfoCount=1;info.pCommandBufferInfos=&cmd;VkSemaphoreSubmitInfo wait{VK_STRUCTURE_TYPE_SEMAPHORE_SUBMIT_INFO},signal{VK_STRUCTURE_TYPE_SEMAPHORE_SUBMIT_INFO};if(present){wait.semaphore=acquired;wait.stageMask=VK_PIPELINE_STAGE_2_TRANSFER_BIT;signal.semaphore=present_ready;signal.stageMask=VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT;info.waitSemaphoreInfoCount=1;info.pWaitSemaphoreInfos=&wait;info.signalSemaphoreInfoCount=1;info.pSignalSemaphoreInfos=&signal;}check(vkQueueSubmit2(queue,1,&info,fence),"Submit frame");check(vkWaitForFences(device,1,&fence,VK_TRUE,UINT64_MAX),"Wait frame fence"); + void transition(VkCommandBuffer cmd, Image& image, VkImageLayout after, + VkImageAspectFlags aspect) { + transition(cmd, image.handle, image.layout, after, aspect); } - void initialize(const RendererConfig& c){ - config=c;width=c.width;height=c.height;if(!width||!height)throw std::invalid_argument("Renderer dimensions must be nonzero"); - std::vector extensions; - if(!c.headless){if(!SDL_InitSubSystem(SDL_INIT_VIDEO))throw std::runtime_error(SDL_GetError());sdl=true;window=SDL_CreateWindow(c.title.c_str(),static_cast(width),static_cast(height),SDL_WINDOW_VULKAN|SDL_WINDOW_RESIZABLE|SDL_WINDOW_HIGH_PIXEL_DENSITY);if(!window)throw std::runtime_error(SDL_GetError());Uint32 count{};auto names=SDL_Vulkan_GetInstanceExtensions(&count);if(!names)throw std::runtime_error(SDL_GetError());extensions.assign(names,names+count);SDL_StartTextInput(window);} - std::uint32_t count{};check(vkEnumerateInstanceLayerProperties(&count,nullptr),"Enumerate layers");std::vector layers(count);check(vkEnumerateInstanceLayerProperties(&count,layers.data()),"Enumerate layers");bool validation=c.validation&&std::any_of(layers.begin(),layers.end(),[](auto& p){return std::strcmp(p.layerName,"VK_LAYER_KHRONOS_validation")==0;}); - if(c.validation&&!validation)std::cerr<<"[Faset] Vulkan validation layer not installed; diagnostics disabled.\n"; - if(validation)extensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME); - VkApplicationInfo app{VK_STRUCTURE_TYPE_APPLICATION_INFO};app.pApplicationName="Faset Engine";app.apiVersion=VK_API_VERSION_1_3; - VkDebugUtilsMessengerCreateInfoEXT debug_info{VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT};debug_info.messageSeverity=VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT|VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT;debug_info.messageType=VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT|VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT|VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT;debug_info.pfnUserCallback=debug;debug_info.pUserData=this; - const char* validation_name="VK_LAYER_KHRONOS_validation";VkInstanceCreateInfo info{VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO};info.pApplicationInfo=&app;info.enabledExtensionCount=static_cast(extensions.size());info.ppEnabledExtensionNames=extensions.data();if(validation){info.enabledLayerCount=1;info.ppEnabledLayerNames=&validation_name;info.pNext=&debug_info;}check(vkCreateInstance(&info,nullptr,&instance),"Create Vulkan instance"); - if(validation){auto fn=reinterpret_cast(vkGetInstanceProcAddr(instance,"vkCreateDebugUtilsMessengerEXT"));if(fn)check(fn(instance,&debug_info,nullptr,&messenger),"Create validation messenger");} - if(window&&!SDL_Vulkan_CreateSurface(window,instance,nullptr,&surface))throw std::runtime_error(SDL_GetError()); - check(vkEnumeratePhysicalDevices(instance,&count,nullptr),"Enumerate GPUs");std::vector devices(count);check(vkEnumeratePhysicalDevices(instance,&count,devices.data()),"Enumerate GPUs"); - int best=-1; - for(auto gpu:devices){VkPhysicalDeviceProperties properties{};vkGetPhysicalDeviceProperties(gpu,&properties);if(properties.apiVersion queues(n);vkGetPhysicalDeviceQueueFamilyProperties(gpu,&n,queues.data());for(std::uint32_t i=0;ibest){best=score;physical=gpu;queue_family=i;statistics.device=properties.deviceName;timestamp_period=properties.limits.timestampPeriod;timestamp_bits=queues[i].timestampValidBits;}} + void begin() { + check(vkResetCommandBuffer(command, 0), "Reset command buffer"); + VkCommandBufferBeginInfo info{VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO}; + info.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; + check(vkBeginCommandBuffer(command, &info), "Begin command buffer"); + } + void submit(bool present = false) { + check(vkEndCommandBuffer(command), "End command buffer"); + check(vkResetFences(device, 1, &fence), "Reset fence"); + VkCommandBufferSubmitInfo cmd{VK_STRUCTURE_TYPE_COMMAND_BUFFER_SUBMIT_INFO}; + cmd.commandBuffer = command; + VkSubmitInfo2 info{VK_STRUCTURE_TYPE_SUBMIT_INFO_2}; + info.commandBufferInfoCount = 1; + info.pCommandBufferInfos = &cmd; + VkSemaphoreSubmitInfo wait{VK_STRUCTURE_TYPE_SEMAPHORE_SUBMIT_INFO}, + signal{VK_STRUCTURE_TYPE_SEMAPHORE_SUBMIT_INFO}; + if (present) { + wait.semaphore = acquired; + wait.stageMask = VK_PIPELINE_STAGE_2_TRANSFER_BIT; + signal.semaphore = present_ready; + signal.stageMask = VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT; + info.waitSemaphoreInfoCount = 1; + info.pWaitSemaphoreInfos = &wait; + info.signalSemaphoreInfoCount = 1; + info.pSignalSemaphoreInfos = &signal; } - if(!physical)throw std::runtime_error("No Vulkan 1.3 device supports dynamic rendering, synchronization2 and required color/depth formats"); - float priority=1;VkDeviceQueueCreateInfo qi{VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO};qi.queueFamilyIndex=queue_family;qi.queueCount=1;qi.pQueuePriorities=&priority;VkPhysicalDeviceVulkan13Features f13{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_3_FEATURES};f13.synchronization2=VK_TRUE;f13.dynamicRendering=VK_TRUE;VkDeviceCreateInfo di{VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO};di.pNext=&f13;di.queueCreateInfoCount=1;di.pQueueCreateInfos=&qi;const char* swap_extension=VK_KHR_SWAPCHAIN_EXTENSION_NAME;if(surface){di.enabledExtensionCount=1;di.ppEnabledExtensionNames=&swap_extension;}check(vkCreateDevice(physical,&di,nullptr,&device),"Create Vulkan device");vkGetDeviceQueue(device,queue_family,0,&queue); - VkCommandPoolCreateInfo pi{VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO};pi.queueFamilyIndex=queue_family;pi.flags=VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;check(vkCreateCommandPool(device,&pi,nullptr,&pool),"Create command pool");VkCommandBufferAllocateInfo ai{VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO};ai.commandPool=pool;ai.level=VK_COMMAND_BUFFER_LEVEL_PRIMARY;ai.commandBufferCount=1;check(vkAllocateCommandBuffers(device,&ai,&command),"Allocate command buffer");VkFenceCreateInfo fi{VK_STRUCTURE_TYPE_FENCE_CREATE_INFO};fi.flags=VK_FENCE_CREATE_SIGNALED_BIT;check(vkCreateFence(device,&fi,nullptr,&fence),"Create frame fence");VkSemaphoreCreateInfo si{VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO};check(vkCreateSemaphore(device,&si,nullptr,&acquired),"Create acquire semaphore");check(vkCreateSemaphore(device,&si,nullptr,&present_ready),"Create present semaphore"); - if(timestamp_bits){VkQueryPoolCreateInfo query{VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO};query.queryType=VK_QUERY_TYPE_TIMESTAMP;query.queryCount=2;check(vkCreateQueryPool(device,&query,nullptr,×tamp_pool),"Create GPU timestamp queries");} - shadow=make_image(shadow_size,shadow_size,VK_FORMAT_D32_SFLOAT,VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT|VK_IMAGE_USAGE_SAMPLED_BIT,VK_IMAGE_ASPECT_DEPTH_BIT); - make_targets();make_descriptors();make_pipelines();white=std::make_shared();white->width=white->height=1;white->rgba={255,255,255,255};upload_texture(white);if(surface)make_swapchain(); + check(vkQueueSubmit2(queue, 1, &info, fence), "Submit frame"); + check(vkWaitForFences(device, 1, &fence, VK_TRUE, UINT64_MAX), "Wait frame fence"); } - void make_targets(){ - check(vkDeviceWaitIdle(device),"Wait resize");destroy(color);destroy(depth);destroy(readback); - color=make_image(width,height,VK_FORMAT_R8G8B8A8_UNORM,VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT|VK_IMAGE_USAGE_TRANSFER_SRC_BIT,VK_IMAGE_ASPECT_COLOR_BIT); - depth=make_image(width,height,VK_FORMAT_D32_SFLOAT,VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT,VK_IMAGE_ASPECT_DEPTH_BIT); - readback=make_buffer(VkDeviceSize(width)*height*4,VK_BUFFER_USAGE_TRANSFER_DST_BIT,VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT|VK_MEMORY_PROPERTY_HOST_COHERENT_BIT); + void initialize(const RendererConfig& c) { + config = c; + width = c.width; + height = c.height; + if (!width || !height) + throw std::invalid_argument("Renderer dimensions must be nonzero"); + std::vector extensions; + if (!c.headless) { + if (!SDL_InitSubSystem(SDL_INIT_VIDEO)) + throw std::runtime_error(SDL_GetError()); + sdl = true; + window = SDL_CreateWindow( + c.title.c_str(), static_cast(width), static_cast(height), + SDL_WINDOW_VULKAN | SDL_WINDOW_RESIZABLE | SDL_WINDOW_HIGH_PIXEL_DENSITY); + if (!window) + throw std::runtime_error(SDL_GetError()); + Uint32 count{}; + auto names = SDL_Vulkan_GetInstanceExtensions(&count); + if (!names) + throw std::runtime_error(SDL_GetError()); + extensions.assign(names, names + count); + SDL_StartTextInput(window); + } + std::uint32_t count{}; + check(vkEnumerateInstanceLayerProperties(&count, nullptr), "Enumerate layers"); + std::vector layers(count); + check(vkEnumerateInstanceLayerProperties(&count, layers.data()), "Enumerate layers"); + bool validation = c.validation && std::any_of(layers.begin(), layers.end(), [](auto& p) { + return std::strcmp(p.layerName, "VK_LAYER_KHRONOS_validation") == 0; + }); + if (c.validation && !validation) + std::cerr << "[Faset] Vulkan validation layer not installed; diagnostics disabled.\n"; + if (validation) + extensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME); + VkApplicationInfo app{VK_STRUCTURE_TYPE_APPLICATION_INFO}; + app.pApplicationName = "Faset Engine"; + app.apiVersion = VK_API_VERSION_1_3; + VkDebugUtilsMessengerCreateInfoEXT debug_info{ + VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT}; + debug_info.messageSeverity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT | + VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT; + debug_info.messageType = VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT | + VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT | + VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT; + debug_info.pfnUserCallback = debug; + debug_info.pUserData = this; + const char* validation_name = "VK_LAYER_KHRONOS_validation"; + VkInstanceCreateInfo info{VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO}; + info.pApplicationInfo = &app; + info.enabledExtensionCount = static_cast(extensions.size()); + info.ppEnabledExtensionNames = extensions.data(); + if (validation) { + info.enabledLayerCount = 1; + info.ppEnabledLayerNames = &validation_name; + info.pNext = &debug_info; + } + check(vkCreateInstance(&info, nullptr, &instance), "Create Vulkan instance"); + if (validation) { + auto fn = reinterpret_cast( + vkGetInstanceProcAddr(instance, "vkCreateDebugUtilsMessengerEXT")); + if (fn) + check(fn(instance, &debug_info, nullptr, &messenger), + "Create validation messenger"); + } + if (window && !SDL_Vulkan_CreateSurface(window, instance, nullptr, &surface)) + throw std::runtime_error(SDL_GetError()); + check(vkEnumeratePhysicalDevices(instance, &count, nullptr), "Enumerate GPUs"); + std::vector devices(count); + check(vkEnumeratePhysicalDevices(instance, &count, devices.data()), "Enumerate GPUs"); + int best = -1; + for (auto gpu : devices) { + VkPhysicalDeviceProperties properties{}; + vkGetPhysicalDeviceProperties(gpu, &properties); + if (properties.apiVersion < VK_API_VERSION_1_3) + continue; + VkPhysicalDeviceVulkan13Features f13{ + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_3_FEATURES}; + VkPhysicalDeviceFeatures2 features{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2}; + features.pNext = &f13; + vkGetPhysicalDeviceFeatures2(gpu, &features); + if (!f13.synchronization2 || !f13.dynamicRendering) + continue; + VkFormatProperties color_props{}, depth_props{}; + vkGetPhysicalDeviceFormatProperties(gpu, VK_FORMAT_R8G8B8A8_UNORM, &color_props); + vkGetPhysicalDeviceFormatProperties(gpu, VK_FORMAT_D32_SFLOAT, &depth_props); + if (!(color_props.optimalTilingFeatures & VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT) || + !(depth_props.optimalTilingFeatures & + VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT) || + !(depth_props.optimalTilingFeatures & VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT)) + continue; + std::uint32_t n{}; + vkGetPhysicalDeviceQueueFamilyProperties(gpu, &n, nullptr); + std::vector queues(n); + vkGetPhysicalDeviceQueueFamilyProperties(gpu, &n, queues.data()); + for (std::uint32_t i = 0; i < n; ++i) { + VkBool32 supports = VK_TRUE; + if (surface) + check(vkGetPhysicalDeviceSurfaceSupportKHR(gpu, i, surface, &supports), + "Query present support"); + int score = properties.deviceType == VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU ? 3 + : properties.deviceType == VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU ? 2 + : 1; + if (supports && (queues[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) && score > best) { + best = score; + physical = gpu; + queue_family = i; + statistics.device = properties.deviceName; + timestamp_period = properties.limits.timestampPeriod; + timestamp_bits = queues[i].timestampValidBits; + } + } + } + if (!physical) + throw std::runtime_error("No Vulkan 1.3 device supports dynamic rendering, " + "synchronization2 and required color/depth formats"); + float priority = 1; + VkDeviceQueueCreateInfo qi{VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO}; + qi.queueFamilyIndex = queue_family; + qi.queueCount = 1; + qi.pQueuePriorities = &priority; + VkPhysicalDeviceVulkan13Features f13{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_3_FEATURES}; + f13.synchronization2 = VK_TRUE; + f13.dynamicRendering = VK_TRUE; + VkDeviceCreateInfo di{VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO}; + di.pNext = &f13; + di.queueCreateInfoCount = 1; + di.pQueueCreateInfos = &qi; + const char* swap_extension = VK_KHR_SWAPCHAIN_EXTENSION_NAME; + if (surface) { + di.enabledExtensionCount = 1; + di.ppEnabledExtensionNames = &swap_extension; + } + check(vkCreateDevice(physical, &di, nullptr, &device), "Create Vulkan device"); + vkGetDeviceQueue(device, queue_family, 0, &queue); + VkCommandPoolCreateInfo pi{VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO}; + pi.queueFamilyIndex = queue_family; + pi.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT; + check(vkCreateCommandPool(device, &pi, nullptr, &pool), "Create command pool"); + VkCommandBufferAllocateInfo ai{VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO}; + ai.commandPool = pool; + ai.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; + ai.commandBufferCount = 1; + check(vkAllocateCommandBuffers(device, &ai, &command), "Allocate command buffer"); + VkFenceCreateInfo fi{VK_STRUCTURE_TYPE_FENCE_CREATE_INFO}; + fi.flags = VK_FENCE_CREATE_SIGNALED_BIT; + check(vkCreateFence(device, &fi, nullptr, &fence), "Create frame fence"); + VkSemaphoreCreateInfo si{VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO}; + check(vkCreateSemaphore(device, &si, nullptr, &acquired), "Create acquire semaphore"); + check(vkCreateSemaphore(device, &si, nullptr, &present_ready), "Create present semaphore"); + if (timestamp_bits) { + VkQueryPoolCreateInfo query{VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO}; + query.queryType = VK_QUERY_TYPE_TIMESTAMP; + query.queryCount = 2; + check(vkCreateQueryPool(device, &query, nullptr, ×tamp_pool), + "Create GPU timestamp queries"); + } + shadow = + make_image(shadow_size, shadow_size, VK_FORMAT_D32_SFLOAT, + VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, + VK_IMAGE_ASPECT_DEPTH_BIT); + make_targets(); + make_descriptors(); + make_pipelines(); + white = std::make_shared(); + white->width = white->height = 1; + white->rgba = {255, 255, 255, 255}; + upload_texture(white); + if (surface) + make_swapchain(); + } + void make_targets() { + check(vkDeviceWaitIdle(device), "Wait resize"); + destroy(color); + destroy(depth); + destroy(readback); + color = make_image(width, height, VK_FORMAT_R8G8B8A8_UNORM, + VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT, + VK_IMAGE_ASPECT_COLOR_BIT); + depth = make_image(width, height, VK_FORMAT_D32_SFLOAT, + VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT, VK_IMAGE_ASPECT_DEPTH_BIT); + readback = + make_buffer(VkDeviceSize(width) * height * 4, VK_BUFFER_USAGE_TRANSFER_DST_BIT, + VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT); last_pixels.clear(); } - void make_swapchain(){ - if(!surface)return;int w{},h{};SDL_GetWindowSizeInPixels(window,&w,&h);if(w<=0||h<=0)return; - check(vkDeviceWaitIdle(device),"Wait swapchain");VkSurfaceCapabilitiesKHR caps{};check(vkGetPhysicalDeviceSurfaceCapabilitiesKHR(physical,surface,&caps),"Read surface capabilities"); - std::uint32_t count{};check(vkGetPhysicalDeviceSurfaceFormatsKHR(physical,surface,&count,nullptr),"Read surface formats");std::vector formats(count);check(vkGetPhysicalDeviceSurfaceFormatsKHR(physical,surface,&count,formats.data()),"Read surface formats");if(formats.empty())throw std::runtime_error("Window surface has no formats");auto chosen=formats.front();for(auto f:formats)if(f.format==VK_FORMAT_B8G8R8A8_UNORM&&f.colorSpace==VK_COLOR_SPACE_SRGB_NONLINEAR_KHR)chosen=f; - VkFormatProperties properties{};vkGetPhysicalDeviceFormatProperties(physical,chosen.format,&properties);if(!(caps.supportedUsageFlags&VK_IMAGE_USAGE_TRANSFER_DST_BIT)||!(properties.optimalTilingFeatures&VK_FORMAT_FEATURE_BLIT_DST_BIT))throw std::runtime_error("Window surface does not support transfer presentation"); - swap_extent=caps.currentExtent;if(swap_extent.width==UINT32_MAX)swap_extent={std::clamp(static_cast(w),caps.minImageExtent.width,caps.maxImageExtent.width),std::clamp(static_cast(h),caps.minImageExtent.height,caps.maxImageExtent.height)}; - count=caps.minImageCount+1;if(caps.maxImageCount)count=std::min(count,caps.maxImageCount);VkSwapchainCreateInfoKHR info{VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR};info.surface=surface;info.minImageCount=count;info.imageFormat=chosen.format;info.imageColorSpace=chosen.colorSpace;info.imageExtent=swap_extent;info.imageArrayLayers=1;info.imageUsage=VK_IMAGE_USAGE_TRANSFER_DST_BIT;info.imageSharingMode=VK_SHARING_MODE_EXCLUSIVE;info.preTransform=caps.currentTransform;info.compositeAlpha=VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR; - if(!(caps.supportedCompositeAlpha&info.compositeAlpha)){for(auto a:{VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR,VK_COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR,VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR})if(caps.supportedCompositeAlpha&a){info.compositeAlpha=a;break;}} - info.presentMode=VK_PRESENT_MODE_FIFO_KHR;info.clipped=VK_TRUE;info.oldSwapchain=swapchain;VkSwapchainKHR next{};check(vkCreateSwapchainKHR(device,&info,nullptr,&next),"Create swapchain");if(swapchain)vkDestroySwapchainKHR(device,swapchain,nullptr);swapchain=next;swap_format=chosen.format; - check(vkGetSwapchainImagesKHR(device,swapchain,&count,nullptr),"Get swapchain images");swap_images.resize(count);check(vkGetSwapchainImagesKHR(device,swapchain,&count,swap_images.data()),"Get swapchain images");swap_layouts.assign(count,VK_IMAGE_LAYOUT_UNDEFINED);dirty_swapchain=false; - if(width!=swap_extent.width||height!=swap_extent.height){width=swap_extent.width;height=swap_extent.height;make_targets();} + void make_swapchain() { + if (!surface) + return; + int w{}, h{}; + SDL_GetWindowSizeInPixels(window, &w, &h); + if (w <= 0 || h <= 0) + return; + check(vkDeviceWaitIdle(device), "Wait swapchain"); + VkSurfaceCapabilitiesKHR caps{}; + check(vkGetPhysicalDeviceSurfaceCapabilitiesKHR(physical, surface, &caps), + "Read surface capabilities"); + std::uint32_t count{}; + check(vkGetPhysicalDeviceSurfaceFormatsKHR(physical, surface, &count, nullptr), + "Read surface formats"); + std::vector formats(count); + check(vkGetPhysicalDeviceSurfaceFormatsKHR(physical, surface, &count, formats.data()), + "Read surface formats"); + if (formats.empty()) + throw std::runtime_error("Window surface has no formats"); + auto chosen = formats.front(); + for (auto f : formats) + if (f.format == VK_FORMAT_B8G8R8A8_UNORM && + f.colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR) + chosen = f; + VkFormatProperties properties{}; + vkGetPhysicalDeviceFormatProperties(physical, chosen.format, &properties); + if (!(caps.supportedUsageFlags & VK_IMAGE_USAGE_TRANSFER_DST_BIT) || + !(properties.optimalTilingFeatures & VK_FORMAT_FEATURE_BLIT_DST_BIT)) + throw std::runtime_error("Window surface does not support transfer presentation"); + swap_extent = caps.currentExtent; + if (swap_extent.width == UINT32_MAX) + swap_extent = {std::clamp(static_cast(w), caps.minImageExtent.width, + caps.maxImageExtent.width), + std::clamp(static_cast(h), caps.minImageExtent.height, + caps.maxImageExtent.height)}; + count = caps.minImageCount + 1; + if (caps.maxImageCount) + count = std::min(count, caps.maxImageCount); + VkSwapchainCreateInfoKHR info{VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR}; + info.surface = surface; + info.minImageCount = count; + info.imageFormat = chosen.format; + info.imageColorSpace = chosen.colorSpace; + info.imageExtent = swap_extent; + info.imageArrayLayers = 1; + info.imageUsage = VK_IMAGE_USAGE_TRANSFER_DST_BIT; + info.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE; + info.preTransform = caps.currentTransform; + info.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR; + if (!(caps.supportedCompositeAlpha & info.compositeAlpha)) { + for (auto a : + {VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR, + VK_COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR, VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR}) + if (caps.supportedCompositeAlpha & a) { + info.compositeAlpha = a; + break; + } + } + info.presentMode = VK_PRESENT_MODE_FIFO_KHR; + info.clipped = VK_TRUE; + info.oldSwapchain = swapchain; + VkSwapchainKHR next{}; + check(vkCreateSwapchainKHR(device, &info, nullptr, &next), "Create swapchain"); + if (swapchain) + vkDestroySwapchainKHR(device, swapchain, nullptr); + swapchain = next; + swap_format = chosen.format; + check(vkGetSwapchainImagesKHR(device, swapchain, &count, nullptr), "Get swapchain images"); + swap_images.resize(count); + check(vkGetSwapchainImagesKHR(device, swapchain, &count, swap_images.data()), + "Get swapchain images"); + swap_layouts.assign(count, VK_IMAGE_LAYOUT_UNDEFINED); + dirty_swapchain = false; + if (width != swap_extent.width || height != swap_extent.height) { + width = swap_extent.width; + height = swap_extent.height; + make_targets(); + } } - void make_descriptors(){ - std::array bindings{};for(std::uint32_t i=0;i<4;++i){bindings[i].binding=i;bindings[i].descriptorType=i%2?VK_DESCRIPTOR_TYPE_SAMPLER:VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE;bindings[i].descriptorCount=1;bindings[i].stageFlags=VK_SHADER_STAGE_FRAGMENT_BIT;} - VkDescriptorSetLayoutCreateInfo li{VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO};li.bindingCount=4;li.pBindings=bindings.data();check(vkCreateDescriptorSetLayout(device,&li,nullptr,&descriptor_layout),"Create descriptor layout"); - VkDescriptorPoolSize sizes[]={{VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE,2048},{VK_DESCRIPTOR_TYPE_SAMPLER,2048}};VkDescriptorPoolCreateInfo pi{VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO};pi.flags=VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT;pi.maxSets=1024;pi.poolSizeCount=2;pi.pPoolSizes=sizes;check(vkCreateDescriptorPool(device,&pi,nullptr,&descriptor_pool),"Create descriptor pool"); - VkSamplerCreateInfo si{VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO};si.magFilter=si.minFilter=VK_FILTER_NEAREST;si.mipmapMode=VK_SAMPLER_MIPMAP_MODE_NEAREST;si.addressModeU=si.addressModeV=si.addressModeW=VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;si.maxLod=0;check(vkCreateSampler(device,&si,nullptr,&shadow_sampler),"Create shadow sampler");si.magFilter=si.minFilter=VK_FILTER_LINEAR;check(vkCreateSampler(device,&si,nullptr,&color_sampler),"Create color sampler"); + void make_descriptors() { + std::array bindings{}; + for (std::uint32_t i = 0; i < 4; ++i) { + bindings[i].binding = i; + bindings[i].descriptorType = + i % 2 ? VK_DESCRIPTOR_TYPE_SAMPLER : VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE; + bindings[i].descriptorCount = 1; + bindings[i].stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT; + } + VkDescriptorSetLayoutCreateInfo li{VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO}; + li.bindingCount = 4; + li.pBindings = bindings.data(); + check(vkCreateDescriptorSetLayout(device, &li, nullptr, &descriptor_layout), + "Create descriptor layout"); + VkDescriptorPoolSize sizes[] = {{VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, 2048}, + {VK_DESCRIPTOR_TYPE_SAMPLER, 2048}}; + VkDescriptorPoolCreateInfo pi{VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO}; + pi.flags = VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT; + pi.maxSets = 1024; + pi.poolSizeCount = 2; + pi.pPoolSizes = sizes; + check(vkCreateDescriptorPool(device, &pi, nullptr, &descriptor_pool), + "Create descriptor pool"); + VkSamplerCreateInfo si{VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO}; + si.magFilter = si.minFilter = VK_FILTER_NEAREST; + si.mipmapMode = VK_SAMPLER_MIPMAP_MODE_NEAREST; + si.addressModeU = si.addressModeV = si.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; + si.maxLod = 0; + check(vkCreateSampler(device, &si, nullptr, &shadow_sampler), "Create shadow sampler"); + si.magFilter = si.minFilter = VK_FILTER_LINEAR; + check(vkCreateSampler(device, &si, nullptr, &color_sampler), "Create color sampler"); } - VkDescriptorSet upload_texture(std::shared_ptr source){ - if(!source)source=white;if(!source||!source->width||!source->height||source->rgba.size()!=std::size_t(source->width)*source->height*4)throw std::invalid_argument("Texture requires width * height * 4 RGBA bytes"); - auto found=textures.find(source.get());if(found!=textures.end()&&found->second.revision==source->revision)return found->second.descriptor; - check(vkDeviceWaitIdle(device),"Wait texture upload");GpuTexture texture{};texture.source=source;texture.revision=source->revision; - texture.image=make_image(source->width,source->height,source->srgb?VK_FORMAT_R8G8B8A8_SRGB:VK_FORMAT_R8G8B8A8_UNORM,VK_IMAGE_USAGE_TRANSFER_DST_BIT|VK_IMAGE_USAGE_SAMPLED_BIT,VK_IMAGE_ASPECT_COLOR_BIT); + VkDescriptorSet upload_texture(std::shared_ptr source) { + if (!source) + source = white; + if (!source || !source->width || !source->height || + source->rgba.size() != std::size_t(source->width) * source->height * 4) + throw std::invalid_argument("Texture requires width * height * 4 RGBA bytes"); + auto found = textures.find(source.get()); + if (found != textures.end() && found->second.revision == source->revision) + return found->second.descriptor; + check(vkDeviceWaitIdle(device), "Wait texture upload"); + GpuTexture texture{}; + texture.source = source; + texture.revision = source->revision; + texture.image = + make_image(source->width, source->height, + source->srgb ? VK_FORMAT_R8G8B8A8_SRGB : VK_FORMAT_R8G8B8A8_UNORM, + VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, + VK_IMAGE_ASPECT_COLOR_BIT); Buffer staging{}; - try{staging=make_buffer(source->rgba.size(),VK_BUFFER_USAGE_TRANSFER_SRC_BIT,VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT|VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);void* mapped{};check(vkMapMemory(device,staging.memory,0,staging.size,0,&mapped),"Map texture staging");std::memcpy(mapped,source->rgba.data(),source->rgba.size());vkUnmapMemory(device,staging.memory);begin();transition(command,texture.image,VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,VK_IMAGE_ASPECT_COLOR_BIT);VkBufferImageCopy copy{};copy.imageSubresource={VK_IMAGE_ASPECT_COLOR_BIT,0,0,1};copy.imageExtent={source->width,source->height,1};vkCmdCopyBufferToImage(command,staging.handle,texture.image.handle,VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,1,©);transition(command,texture.image,VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,VK_IMAGE_ASPECT_COLOR_BIT);submit();destroy(staging); - VkDescriptorSetAllocateInfo ai{VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO};ai.descriptorPool=descriptor_pool;ai.descriptorSetCount=1;ai.pSetLayouts=&descriptor_layout;check(vkAllocateDescriptorSets(device,&ai,&texture.descriptor),"Allocate texture descriptor"); - VkDescriptorImageInfo images[]={{VK_NULL_HANDLE,shadow.view,VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_OPTIMAL},{shadow_sampler,VK_NULL_HANDLE,VK_IMAGE_LAYOUT_UNDEFINED},{VK_NULL_HANDLE,texture.image.view,VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL},{color_sampler,VK_NULL_HANDLE,VK_IMAGE_LAYOUT_UNDEFINED}}; - std::array writes{};for(std::uint32_t i=0;i<4;++i){writes[i]={VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET};writes[i].dstSet=texture.descriptor;writes[i].dstBinding=i;writes[i].descriptorCount=1;writes[i].descriptorType=i%2?VK_DESCRIPTOR_TYPE_SAMPLER:VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE;writes[i].pImageInfo=&images[i];}vkUpdateDescriptorSets(device,4,writes.data(),0,nullptr); - }catch(...){destroy(staging);destroy(texture.image);throw;} - if(found!=textures.end()){destroy(found->second.image);vkFreeDescriptorSets(device,descriptor_pool,1,&found->second.descriptor);found->second=std::move(texture);return found->second.descriptor;} - auto [inserted,_]=textures.emplace(source.get(),std::move(texture));return inserted->second.descriptor; + try { + staging = make_buffer(source->rgba.size(), VK_BUFFER_USAGE_TRANSFER_SRC_BIT, + VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | + VK_MEMORY_PROPERTY_HOST_COHERENT_BIT); + void* mapped{}; + check(vkMapMemory(device, staging.memory, 0, staging.size, 0, &mapped), + "Map texture staging"); + std::memcpy(mapped, source->rgba.data(), source->rgba.size()); + vkUnmapMemory(device, staging.memory); + begin(); + transition(command, texture.image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + VK_IMAGE_ASPECT_COLOR_BIT); + VkBufferImageCopy copy{}; + copy.imageSubresource = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1}; + copy.imageExtent = {source->width, source->height, 1}; + vkCmdCopyBufferToImage(command, staging.handle, texture.image.handle, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ©); + transition(command, texture.image, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, + VK_IMAGE_ASPECT_COLOR_BIT); + submit(); + destroy(staging); + VkDescriptorSetAllocateInfo ai{VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO}; + ai.descriptorPool = descriptor_pool; + ai.descriptorSetCount = 1; + ai.pSetLayouts = &descriptor_layout; + check(vkAllocateDescriptorSets(device, &ai, &texture.descriptor), + "Allocate texture descriptor"); + VkDescriptorImageInfo images[] = { + {VK_NULL_HANDLE, shadow.view, VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_OPTIMAL}, + {shadow_sampler, VK_NULL_HANDLE, VK_IMAGE_LAYOUT_UNDEFINED}, + {VK_NULL_HANDLE, texture.image.view, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL}, + {color_sampler, VK_NULL_HANDLE, VK_IMAGE_LAYOUT_UNDEFINED}}; + std::array writes{}; + for (std::uint32_t i = 0; i < 4; ++i) { + writes[i] = {VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET}; + writes[i].dstSet = texture.descriptor; + writes[i].dstBinding = i; + writes[i].descriptorCount = 1; + writes[i].descriptorType = + i % 2 ? VK_DESCRIPTOR_TYPE_SAMPLER : VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE; + writes[i].pImageInfo = &images[i]; + } + vkUpdateDescriptorSets(device, 4, writes.data(), 0, nullptr); + } catch (...) { + destroy(staging); + destroy(texture.image); + throw; + } + if (found != textures.end()) { + destroy(found->second.image); + vkFreeDescriptorSets(device, descriptor_pool, 1, &found->second.descriptor); + found->second = std::move(texture); + return found->second.descriptor; + } + auto [inserted, _] = textures.emplace(source.get(), std::move(texture)); + return inserted->second.descriptor; } - VkShaderModule shader(const char* name){ - std::vector roots;const char* base=SDL_GetBasePath();if(base)roots.emplace_back(std::filesystem::path(base)/"shaders");roots.emplace_back(std::filesystem::current_path()/"shaders");roots.emplace_back(FASET_SHADER_DIRECTORY); - std::ifstream file;for(const auto& root:roots){file.open(root/(std::string(name)+".spv"),std::ios::binary|std::ios::ate);if(file)break;file.clear();}if(!file)throw std::runtime_error(std::string("Compiled Slang shader missing: ")+name+".spv");auto size=file.tellg();if(size<=0||size%4!=0)throw std::runtime_error("Invalid SPIR-V byte length");std::vector bytes(static_cast(size)/4);file.seekg(0);file.read(reinterpret_cast(bytes.data()),size);VkShaderModuleCreateInfo ci{VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO};ci.codeSize=static_cast(size);ci.pCode=bytes.data();VkShaderModule result{};check(vkCreateShaderModule(device,&ci,nullptr,&result),"Create shader module");return result; + VkShaderModule shader(const char* name) { + std::vector roots; + const char* base = SDL_GetBasePath(); + if (base) + roots.emplace_back(std::filesystem::path(base) / "shaders"); + roots.emplace_back(std::filesystem::current_path() / "shaders"); + roots.emplace_back(FASET_SHADER_DIRECTORY); + std::ifstream file; + for (const auto& root : roots) { + file.open(root / (std::string(name) + ".spv"), std::ios::binary | std::ios::ate); + if (file) + break; + file.clear(); + } + if (!file) + throw std::runtime_error(std::string("Compiled Slang shader missing: ") + name + + ".spv"); + auto size = file.tellg(); + if (size <= 0 || size % 4 != 0) + throw std::runtime_error("Invalid SPIR-V byte length"); + std::vector bytes(static_cast(size) / 4); + file.seekg(0); + file.read(reinterpret_cast(bytes.data()), size); + VkShaderModuleCreateInfo ci{VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO}; + ci.codeSize = static_cast(size); + ci.pCode = bytes.data(); + VkShaderModule result{}; + check(vkCreateShaderModule(device, &ci, nullptr, &result), "Create shader module"); + return result; } - void make_pipelines(){ - VkPushConstantRange push{VK_SHADER_STAGE_VERTEX_BIT|VK_SHADER_STAGE_FRAGMENT_BIT,0,sizeof(Push)};VkPipelineLayoutCreateInfo li{VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO};li.setLayoutCount=1;li.pSetLayouts=&descriptor_layout;li.pushConstantRangeCount=1;li.pPushConstantRanges=&push;check(vkCreatePipelineLayout(device,&li,nullptr,&pipeline_layout),"Create pipeline layout"); - VkShaderModule vertex{},fragment{},shadow_vertex{}; - try{vertex=shader("vertexMain");fragment=shader("fragmentMain");shadow_vertex=shader("shadowMain");for(int mode=0;mode<3;++mode){bool shadow_pass=mode==2,ui=mode==1; - VkPipelineShaderStageCreateInfo stages[2]{};stages[0]={VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO};stages[0].stage=VK_SHADER_STAGE_VERTEX_BIT;stages[0].module=shadow_pass?shadow_vertex:vertex;stages[0].pName="main";stages[1]={VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO};stages[1].stage=VK_SHADER_STAGE_FRAGMENT_BIT;stages[1].module=fragment;stages[1].pName="main"; - VkVertexInputBindingDescription binding{0,sizeof(GpuVertex),VK_VERTEX_INPUT_RATE_VERTEX};VkVertexInputAttributeDescription attrs[]={{0,0,VK_FORMAT_R32G32B32A32_SFLOAT,offsetof(GpuVertex,clip)},{1,0,VK_FORMAT_R32G32B32_SFLOAT,offsetof(GpuVertex,world)},{2,0,VK_FORMAT_R32G32B32_SFLOAT,offsetof(GpuVertex,normal)},{3,0,VK_FORMAT_R32G32B32A32_SFLOAT,offsetof(GpuVertex,color)},{4,0,VK_FORMAT_R32G32_SFLOAT,offsetof(GpuVertex,material)},{5,0,VK_FORMAT_R32G32_SFLOAT,offsetof(GpuVertex,uv)}}; - VkPipelineVertexInputStateCreateInfo vi{VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO};vi.vertexBindingDescriptionCount=1;vi.pVertexBindingDescriptions=&binding;vi.vertexAttributeDescriptionCount=shadow_pass?1:6;vi.pVertexAttributeDescriptions=shadow_pass?attrs+1:attrs;VkPipelineInputAssemblyStateCreateInfo ia{VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO};ia.topology=VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST; - VkPipelineViewportStateCreateInfo vp{VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO};vp.viewportCount=vp.scissorCount=1;VkPipelineRasterizationStateCreateInfo rs{VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO};rs.polygonMode=VK_POLYGON_MODE_FILL;rs.cullMode=VK_CULL_MODE_NONE;rs.frontFace=VK_FRONT_FACE_COUNTER_CLOCKWISE;rs.lineWidth=1; - VkPipelineMultisampleStateCreateInfo ms{VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO};ms.rasterizationSamples=VK_SAMPLE_COUNT_1_BIT;VkPipelineDepthStencilStateCreateInfo ds{VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO};ds.depthTestEnable=!ui;ds.depthWriteEnable=!ui;ds.depthCompareOp=VK_COMPARE_OP_LESS_OR_EQUAL; - VkPipelineColorBlendAttachmentState blend{};blend.colorWriteMask=15;blend.blendEnable=VK_TRUE;blend.srcColorBlendFactor=VK_BLEND_FACTOR_SRC_ALPHA;blend.dstColorBlendFactor=VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;blend.colorBlendOp=VK_BLEND_OP_ADD;blend.srcAlphaBlendFactor=VK_BLEND_FACTOR_ONE;blend.dstAlphaBlendFactor=VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;blend.alphaBlendOp=VK_BLEND_OP_ADD;VkPipelineColorBlendStateCreateInfo cb{VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO};cb.attachmentCount=shadow_pass?0:1;cb.pAttachments=&blend; - VkDynamicState states[]={VK_DYNAMIC_STATE_VIEWPORT,VK_DYNAMIC_STATE_SCISSOR};VkPipelineDynamicStateCreateInfo dynamic{VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO};dynamic.dynamicStateCount=2;dynamic.pDynamicStates=states;VkFormat format=VK_FORMAT_R8G8B8A8_UNORM;VkPipelineRenderingCreateInfo rendering{VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO};rendering.colorAttachmentCount=shadow_pass?0:1;rendering.pColorAttachmentFormats=&format;rendering.depthAttachmentFormat=VK_FORMAT_D32_SFLOAT; - VkGraphicsPipelineCreateInfo pi{VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO};pi.pNext=&rendering;pi.stageCount=shadow_pass?1:2;pi.pStages=stages;pi.pVertexInputState=&vi;pi.pInputAssemblyState=&ia;pi.pViewportState=&vp;pi.pRasterizationState=&rs;pi.pMultisampleState=&ms;pi.pDepthStencilState=&ds;pi.pColorBlendState=&cb;pi.pDynamicState=&dynamic;pi.layout=pipeline_layout;auto* output=shadow_pass?&shadow_pipeline:ui?&ui_pipeline:&pipeline;check(vkCreateGraphicsPipelines(device,VK_NULL_HANDLE,1,&pi,nullptr,output),"Create graphics pipeline"); - }}catch(...){vkDestroyShaderModule(device,vertex,nullptr);vkDestroyShaderModule(device,fragment,nullptr);vkDestroyShaderModule(device,shadow_vertex,nullptr);throw;} - vkDestroyShaderModule(device,vertex,nullptr);vkDestroyShaderModule(device,fragment,nullptr);vkDestroyShaderModule(device,shadow_vertex,nullptr); + void make_pipelines() { + VkPushConstantRange push{VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0, + sizeof(Push)}; + VkPipelineLayoutCreateInfo li{VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO}; + li.setLayoutCount = 1; + li.pSetLayouts = &descriptor_layout; + li.pushConstantRangeCount = 1; + li.pPushConstantRanges = &push; + check(vkCreatePipelineLayout(device, &li, nullptr, &pipeline_layout), + "Create pipeline layout"); + VkShaderModule vertex{}, fragment{}, shadow_vertex{}; + try { + vertex = shader("vertexMain"); + fragment = shader("fragmentMain"); + shadow_vertex = shader("shadowMain"); + for (int mode = 0; mode < 3; ++mode) { + bool shadow_pass = mode == 2, ui = mode == 1; + VkPipelineShaderStageCreateInfo stages[2]{}; + stages[0] = {VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO}; + stages[0].stage = VK_SHADER_STAGE_VERTEX_BIT; + stages[0].module = shadow_pass ? shadow_vertex : vertex; + stages[0].pName = "main"; + stages[1] = {VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO}; + stages[1].stage = VK_SHADER_STAGE_FRAGMENT_BIT; + stages[1].module = fragment; + stages[1].pName = "main"; + VkVertexInputBindingDescription binding{0, sizeof(GpuVertex), + VK_VERTEX_INPUT_RATE_VERTEX}; + VkVertexInputAttributeDescription attrs[] = { + {0, 0, VK_FORMAT_R32G32B32A32_SFLOAT, offsetof(GpuVertex, clip)}, + {1, 0, VK_FORMAT_R32G32B32_SFLOAT, offsetof(GpuVertex, world)}, + {2, 0, VK_FORMAT_R32G32B32_SFLOAT, offsetof(GpuVertex, normal)}, + {3, 0, VK_FORMAT_R32G32B32A32_SFLOAT, offsetof(GpuVertex, color)}, + {4, 0, VK_FORMAT_R32G32_SFLOAT, offsetof(GpuVertex, material)}, + {5, 0, VK_FORMAT_R32G32_SFLOAT, offsetof(GpuVertex, uv)}}; + VkPipelineVertexInputStateCreateInfo vi{ + VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO}; + vi.vertexBindingDescriptionCount = 1; + vi.pVertexBindingDescriptions = &binding; + vi.vertexAttributeDescriptionCount = shadow_pass ? 1 : 6; + vi.pVertexAttributeDescriptions = shadow_pass ? attrs + 1 : attrs; + VkPipelineInputAssemblyStateCreateInfo ia{ + VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO}; + ia.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST; + VkPipelineViewportStateCreateInfo vp{ + VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO}; + vp.viewportCount = vp.scissorCount = 1; + VkPipelineRasterizationStateCreateInfo rs{ + VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO}; + rs.polygonMode = VK_POLYGON_MODE_FILL; + rs.cullMode = VK_CULL_MODE_NONE; + rs.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE; + rs.lineWidth = 1; + rs.depthBiasEnable = shadow_pass; + rs.depthBiasConstantFactor = 1.25f; + rs.depthBiasSlopeFactor = 1.75f; + VkPipelineMultisampleStateCreateInfo ms{ + VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO}; + ms.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT; + VkPipelineDepthStencilStateCreateInfo ds{ + VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO}; + ds.depthTestEnable = !ui; + ds.depthWriteEnable = !ui; + ds.depthCompareOp = VK_COMPARE_OP_LESS_OR_EQUAL; + VkPipelineColorBlendAttachmentState blend{}; + blend.colorWriteMask = 15; + blend.blendEnable = VK_TRUE; + blend.srcColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA; + blend.dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA; + blend.colorBlendOp = VK_BLEND_OP_ADD; + blend.srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE; + blend.dstAlphaBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA; + blend.alphaBlendOp = VK_BLEND_OP_ADD; + VkPipelineColorBlendStateCreateInfo cb{ + VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO}; + cb.attachmentCount = shadow_pass ? 0 : 1; + cb.pAttachments = &blend; + VkDynamicState states[] = {VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR}; + VkPipelineDynamicStateCreateInfo dynamic{ + VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO}; + dynamic.dynamicStateCount = 2; + dynamic.pDynamicStates = states; + VkFormat format = VK_FORMAT_R8G8B8A8_UNORM; + VkPipelineRenderingCreateInfo rendering{ + VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO}; + rendering.colorAttachmentCount = shadow_pass ? 0 : 1; + rendering.pColorAttachmentFormats = &format; + rendering.depthAttachmentFormat = VK_FORMAT_D32_SFLOAT; + VkGraphicsPipelineCreateInfo pi{VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO}; + pi.pNext = &rendering; + pi.stageCount = shadow_pass ? 1 : 2; + pi.pStages = stages; + pi.pVertexInputState = &vi; + pi.pInputAssemblyState = &ia; + pi.pViewportState = &vp; + pi.pRasterizationState = &rs; + pi.pMultisampleState = &ms; + pi.pDepthStencilState = &ds; + pi.pColorBlendState = &cb; + pi.pDynamicState = &dynamic; + pi.layout = pipeline_layout; + auto* output = shadow_pass ? &shadow_pipeline : ui ? &ui_pipeline : &pipeline; + check(vkCreateGraphicsPipelines(device, VK_NULL_HANDLE, 1, &pi, nullptr, output), + "Create graphics pipeline"); + } + } catch (...) { + vkDestroyShaderModule(device, vertex, nullptr); + vkDestroyShaderModule(device, fragment, nullptr); + vkDestroyShaderModule(device, shadow_vertex, nullptr); + throw; + } + vkDestroyShaderModule(device, vertex, nullptr); + vkDestroyShaderModule(device, fragment, nullptr); + vkDestroyShaderModule(device, shadow_vertex, nullptr); } - GpuVertex gpu_vertex(const Vertex& v,const DrawItem& item,const Mat4& vp){ - GpuVertex out{};auto world=point(item.model,{v.position[0],v.position[1],v.position[2],1});auto clip=point(vp,world);std::copy(clip.begin(),clip.end(),out.clip);std::copy_n(world.begin(),3,out.world); + GpuVertex gpu_vertex(const Vertex& v, const DrawItem& item, const Mat4& vp) { + GpuVertex out{}; + auto world = point(item.model, {v.position[0], v.position[1], v.position[2], 1}); + auto clip = point(vp, world); + std::copy(clip.begin(), clip.end(), out.clip); + std::copy_n(world.begin(), 3, out.world); // Inverse-transpose 3x3, including nonuniform scale. Singular models have no valid normal. - const auto& m=item.model;Vec3 a{m[0],m[1],m[2]},b{m[4],m[5],m[6]},c{m[8],m[9],m[10]}; - auto cross=[](Vec3 x,Vec3 y){return Vec3{x[1]*y[2]-x[2]*y[1],x[2]*y[0]-x[0]*y[2],x[0]*y[1]-x[1]*y[0]};};auto ca=cross(b,c),cb=cross(c,a),cc=cross(a,b);float determinant=a[0]*ca[0]+a[1]*ca[1]+a[2]*ca[2]; - for(int i=0;i<3;++i)out.normal[i]=std::abs(determinant)>1e-8f?(ca[i]*v.normal[0]+cb[i]*v.normal[1]+cc[i]*v.normal[2])/determinant:0; - for(int i=0;i<4;++i)out.color[i]=item.color[i]*v.color[i];out.material[0]=item.roughness;out.material[1]=item.metallic;out.uv[0]=v.uv[0];out.uv[1]=v.uv[1];return out; - } - bool outside(const std::vector& data,std::size_t start) const { - for(int plane=0;plane<6;++plane){bool all=true;for(std::size_t i=start;i=0){all=false;break;}}if(all)return true;}return false; - } - void quad(std::vector& data,const Quad& q){ - const float xy[4][2]={{q.x,q.y},{q.x+q.width,q.y},{q.x+q.width,q.y+q.height},{q.x,q.y+q.height}}; - const float uv[4][2]={{q.uv_rect[0],q.uv_rect[1]},{q.uv_rect[2],q.uv_rect[1]},{q.uv_rect[2],q.uv_rect[3]},{q.uv_rect[0],q.uv_rect[3]}}; - for(auto i:{0,1,2,0,2,3}){GpuVertex v{};v.clip[0]=xy[i][0]/float(width)*2-1;v.clip[1]=xy[i][1]/float(height)*2-1;v.clip[3]=1;std::copy(q.color.begin(),q.color.end(),v.color);v.uv[0]=uv[i][0];v.uv[1]=uv[i][1];data.push_back(v);} - } - void draw_debug_text(std::vector& data,const Text& text){ - // Small diagnostic alphabet only. The editor supplies shaped Unicode text as texture quads. - static const std::unordered_map> glyphs={ - {'A',{14,17,17,31,17,17,17}},{'B',{30,17,17,30,17,17,30}},{'C',{14,17,16,16,16,17,14}},{'D',{30,17,17,17,17,17,30}},{'E',{31,16,16,30,16,16,31}},{'F',{31,16,16,30,16,16,16}},{'G',{14,17,16,23,17,17,15}},{'H',{17,17,17,31,17,17,17}},{'I',{14,4,4,4,4,4,14}},{'J',{7,2,2,2,18,18,12}},{'K',{17,18,20,24,20,18,17}},{'L',{16,16,16,16,16,16,31}},{'M',{17,27,21,21,17,17,17}},{'N',{17,25,21,19,17,17,17}},{'O',{14,17,17,17,17,17,14}},{'P',{30,17,17,30,16,16,16}},{'Q',{14,17,17,17,21,18,13}},{'R',{30,17,17,30,20,18,17}},{'S',{15,16,16,14,1,1,30}},{'T',{31,4,4,4,4,4,4}},{'U',{17,17,17,17,17,17,14}},{'V',{17,17,17,17,17,10,4}},{'W',{17,17,17,21,21,27,17}},{'X',{17,17,10,4,10,17,17}},{'Y',{17,17,10,4,4,4,4}},{'Z',{31,1,2,4,8,16,31}}, - {'0',{14,17,19,21,25,17,14}},{'1',{4,12,4,4,4,4,14}},{'2',{14,17,1,2,4,8,31}},{'3',{30,1,1,14,1,1,30}},{'4',{2,6,10,18,31,2,2}},{'5',{31,16,16,30,1,1,30}},{'6',{14,16,16,30,17,17,14}},{'7',{31,1,2,4,8,8,8}},{'8',{14,17,17,14,17,17,14}},{'9',{14,17,17,15,1,1,14}}, - {'.',{0,0,0,0,0,12,12}},{':',{0,12,12,0,12,12,0}},{'-',{0,0,0,31,0,0,0}},{'/',{1,1,2,4,8,16,16}},{'_', {0,0,0,0,0,0,31}},{'(',{2,4,8,8,8,4,2}},{')',{8,4,2,2,2,4,8}},{'+',{0,4,4,31,4,4,0}},{'=',{0,0,31,0,31,0,0}},{'[',{14,8,8,8,8,8,14}},{']',{14,2,2,2,2,2,14}},{'?',{14,17,1,2,4,0,4}},{'!',{4,4,4,4,4,0,4}} + const auto& m = item.model; + Vec3 a{m[0], m[1], m[2]}, b{m[4], m[5], m[6]}, c{m[8], m[9], m[10]}; + auto cross = [](Vec3 x, Vec3 y) { + return Vec3{x[1] * y[2] - x[2] * y[1], x[2] * y[0] - x[0] * y[2], + x[0] * y[1] - x[1] * y[0]}; }; - float x=text.x,y=text.y,unit=text.size/7;for(unsigned char c:text.value){if(c=='\n'){x=text.x;y+=text.size*1.4f;continue;}if(c>='a'&&c<='z')c-=32;if(c!=' '){auto it=glyphs.find(static_cast(c));auto pattern=it==glyphs.end()?std::array{31,17,17,17,17,17,31}:it->second;for(int row=0;row<7;++row)for(int col=0;col<5;++col)if(pattern[row]&(1<<(4-col)))quad(data,{x+col*unit,y+row*unit,unit,unit,text.color});}x+=6*unit;} + auto ca = cross(b, c), cb = cross(c, a), cc = cross(a, b); + float determinant = a[0] * ca[0] + a[1] * ca[1] + a[2] * ca[2]; + for (int i = 0; i < 3; ++i) + out.normal[i] = + determinant != 0 + ? (ca[i] * v.normal[0] + cb[i] * v.normal[1] + cc[i] * v.normal[2]) * + (determinant < 0 ? -1.f : 1.f) + : 0; + float normal_length = std::hypot(out.normal[0], out.normal[1], out.normal[2]); + if (normal_length > 0) + for (float& component : out.normal) + component /= normal_length; + for (int i = 0; i < 4; ++i) + out.color[i] = item.color[i] * v.color[i]; + out.material[0] = item.roughness; + out.material[1] = item.metallic; + out.uv[0] = v.uv[0]; + out.uv[1] = v.uv[1]; + return out; } - void render(const Snapshot& snapshot){ - auto start=std::chrono::steady_clock::now();statistics.draw_calls=statistics.culled_meshes=0; - if(surface){int w{},h{};SDL_GetWindowSizeInPixels(window,&w,&h);if(w<=0||h<=0)return;if(dirty_swapchain||!swapchain)make_swapchain();} + bool outside(const std::vector& data, std::size_t start) const { + for (int plane = 0; plane < 6; ++plane) { + bool all = true; + for (std::size_t i = start; i < data.size(); ++i) { + auto& p = data[i].clip; + float d = plane == 0 ? p[0] + p[3] + : plane == 1 ? p[3] - p[0] + : plane == 2 ? p[1] + p[3] + : plane == 3 ? p[3] - p[1] + : plane == 4 ? p[2] + : p[3] - p[2]; + if (d >= 0) { + all = false; + break; + } + } + if (all) + return true; + } + return false; + } + void quad(std::vector& data, const Quad& q) { + const float xy[4][2] = {{q.x, q.y}, + {q.x + q.width, q.y}, + {q.x + q.width, q.y + q.height}, + {q.x, q.y + q.height}}; + const float uv[4][2] = {{q.uv_rect[0], q.uv_rect[1]}, + {q.uv_rect[2], q.uv_rect[1]}, + {q.uv_rect[2], q.uv_rect[3]}, + {q.uv_rect[0], q.uv_rect[3]}}; + for (auto i : {0, 1, 2, 0, 2, 3}) { + GpuVertex v{}; + v.clip[0] = xy[i][0] / float(width) * 2 - 1; + v.clip[1] = xy[i][1] / float(height) * 2 - 1; + v.clip[3] = 1; + std::copy(q.color.begin(), q.color.end(), v.color); + v.uv[0] = uv[i][0]; + v.uv[1] = uv[i][1]; + v.material[0] = q.texture && q.texture->srgb ? 1.f : 0.f; + data.push_back(v); + } + } + void draw_debug_text(std::vector& data, const Text& text) { + // Small diagnostic alphabet only. The editor supplies shaped Unicode text as texture quads. + static const std::unordered_map> glyphs = { + {'A', {14, 17, 17, 31, 17, 17, 17}}, {'B', {30, 17, 17, 30, 17, 17, 30}}, + {'C', {14, 17, 16, 16, 16, 17, 14}}, {'D', {30, 17, 17, 17, 17, 17, 30}}, + {'E', {31, 16, 16, 30, 16, 16, 31}}, {'F', {31, 16, 16, 30, 16, 16, 16}}, + {'G', {14, 17, 16, 23, 17, 17, 15}}, {'H', {17, 17, 17, 31, 17, 17, 17}}, + {'I', {14, 4, 4, 4, 4, 4, 14}}, {'J', {7, 2, 2, 2, 18, 18, 12}}, + {'K', {17, 18, 20, 24, 20, 18, 17}}, {'L', {16, 16, 16, 16, 16, 16, 31}}, + {'M', {17, 27, 21, 21, 17, 17, 17}}, {'N', {17, 25, 21, 19, 17, 17, 17}}, + {'O', {14, 17, 17, 17, 17, 17, 14}}, {'P', {30, 17, 17, 30, 16, 16, 16}}, + {'Q', {14, 17, 17, 17, 21, 18, 13}}, {'R', {30, 17, 17, 30, 20, 18, 17}}, + {'S', {15, 16, 16, 14, 1, 1, 30}}, {'T', {31, 4, 4, 4, 4, 4, 4}}, + {'U', {17, 17, 17, 17, 17, 17, 14}}, {'V', {17, 17, 17, 17, 17, 10, 4}}, + {'W', {17, 17, 17, 21, 21, 27, 17}}, {'X', {17, 17, 10, 4, 10, 17, 17}}, + {'Y', {17, 17, 10, 4, 4, 4, 4}}, {'Z', {31, 1, 2, 4, 8, 16, 31}}, + {'0', {14, 17, 19, 21, 25, 17, 14}}, {'1', {4, 12, 4, 4, 4, 4, 14}}, + {'2', {14, 17, 1, 2, 4, 8, 31}}, {'3', {30, 1, 1, 14, 1, 1, 30}}, + {'4', {2, 6, 10, 18, 31, 2, 2}}, {'5', {31, 16, 16, 30, 1, 1, 30}}, + {'6', {14, 16, 16, 30, 17, 17, 14}}, {'7', {31, 1, 2, 4, 8, 8, 8}}, + {'8', {14, 17, 17, 14, 17, 17, 14}}, {'9', {14, 17, 17, 15, 1, 1, 14}}, + {'.', {0, 0, 0, 0, 0, 12, 12}}, {':', {0, 12, 12, 0, 12, 12, 0}}, + {'-', {0, 0, 0, 31, 0, 0, 0}}, {'/', {1, 1, 2, 4, 8, 16, 16}}, + {'_', {0, 0, 0, 0, 0, 0, 31}}, {'(', {2, 4, 8, 8, 8, 4, 2}}, + {')', {8, 4, 2, 2, 2, 4, 8}}, {'+', {0, 4, 4, 31, 4, 4, 0}}, + {'=', {0, 0, 31, 0, 31, 0, 0}}, {'[', {14, 8, 8, 8, 8, 8, 14}}, + {']', {14, 2, 2, 2, 2, 2, 14}}, {'?', {14, 17, 1, 2, 4, 0, 4}}, + {'!', {4, 4, 4, 4, 4, 0, 4}}}; + float x = text.x, y = text.y, unit = text.size / 7; + for (unsigned char c : text.value) { + if (c == '\n') { + x = text.x; + y += text.size * 1.4f; + continue; + } + if (c >= 'a' && c <= 'z') + c -= 32; + if (c != ' ') { + auto it = glyphs.find(static_cast(c)); + auto pattern = it == glyphs.end() + ? std::array{31, 17, 17, 17, 17, 17, 31} + : it->second; + for (int row = 0; row < 7; ++row) + for (int col = 0; col < 5; ++col) + if (pattern[row] & (1 << (4 - col))) + quad(data, {x + col * unit, y + row * unit, unit, unit, text.color}); + } + x += 6 * unit; + } + } + void render(const Snapshot& snapshot) { + auto start = std::chrono::steady_clock::now(); + statistics.draw_calls = statistics.culled_meshes = 0; + if (surface) { + int w{}, h{}; + SDL_GetWindowSizeInPixels(window, &w, &h); + if (w <= 0 || h <= 0) + return; + if (dirty_swapchain || !swapchain) + make_swapchain(); + } // Retire atlas/image resources no longer retained by a caller. - for(auto it=textures.begin();it!=textures.end();){if(it->first!=white.get()&&it->second.source.use_count()==1){destroy(it->second.image);vkFreeDescriptorSets(device,descriptor_pool,1,&it->second.descriptor);it=textures.erase(it);}else ++it;} - const VkDescriptorSet white_descriptor=upload_texture(white);for(const auto& q:snapshot.ui_quads)if(q.texture)upload_texture(q.texture);for(const auto& draw:snapshot.draws)if(draw.texture)upload_texture(draw.texture);for(const auto& sprite:snapshot.sprites)if(sprite.texture)upload_texture(sprite.texture); - std::vector data;std::vector scene_batches,shadow_batches,ui_batches; - for(const auto& item:snapshot.draws){if(!item.mesh)continue;auto first=data.size();const auto& mesh=*item.mesh;auto emit=[&](std::uint32_t index){if(index>=mesh.vertices.size())throw std::out_of_range("Mesh index outside vertex range");data.push_back(gpu_vertex(mesh.vertices[index],item,snapshot.view_projection));};if(mesh.indices.empty())for(std::uint32_t i=0;i(data.size()-first);if(count%3)throw std::invalid_argument("Mesh triangle vertex count must be divisible by three");if(!count)continue;Batch batch{static_cast(first),count,item.texture?item.texture.get():white.get()};if(item.cast_shadow)shadow_batches.push_back(batch);if(outside(data,first))++statistics.culled_meshes;else scene_batches.push_back(batch);} - for(const auto& sprite:snapshot.sprites){auto first=static_cast(data.size());float c=std::cos(sprite.rotation),s=std::sin(sprite.rotation);for(auto i:{0,1,2,0,2,3}){const float corners[4][2]={{-.5f,-.5f},{.5f,-.5f},{.5f,.5f},{-.5f,.5f}};float x=corners[i][0]*sprite.size[0],y=corners[i][1]*sprite.size[1];auto clip=point(snapshot.view_projection,{sprite.position[0]+c*x-s*y,sprite.position[1]+s*x+c*y,sprite.position[2],1});GpuVertex vertex{};std::copy(clip.begin(),clip.end(),vertex.clip);std::copy(sprite.color.begin(),sprite.color.end(),vertex.color);vertex.uv[0]=corners[i][0]+.5f;vertex.uv[1]=.5f-corners[i][1];data.push_back(vertex);}scene_batches.push_back({first,6,sprite.texture?sprite.texture.get():white.get()});} - for(const auto& q:snapshot.ui_quads){auto first=static_cast(data.size());quad(data,q);const Texture* texture=q.texture?q.texture.get():white.get();if(!ui_batches.empty()&&ui_batches.back().texture==texture)ui_batches.back().count+=6;else ui_batches.push_back({first,6,texture});} - auto text_first=static_cast(data.size());for(const auto& text:snapshot.ui_text)draw_debug_text(data,text);if(data.size()>text_first)ui_batches.push_back({text_first,static_cast(data.size()-text_first),white.get()}); - statistics.vertices=static_cast(data.size());auto byte_count=std::max(sizeof(GpuVertex),data.size()*sizeof(GpuVertex));if(vertices.size.98f?Vec3{0,0,1}:Vec3{0,1,0};Push push{multiply(orthographic(-20,20,-20,20,.1f,80),look_at(light_eye,{0,0,0},light_up)),{direction[0],direction[1],direction[2],0},{snapshot.eye[0],snapshot.eye[1],snapshot.eye[2],1}}; + for (auto it = textures.begin(); it != textures.end();) { + if (it->first != white.get() && it->second.source.use_count() == 1) { + destroy(it->second.image); + vkFreeDescriptorSets(device, descriptor_pool, 1, &it->second.descriptor); + it = textures.erase(it); + } else + ++it; + } + const VkDescriptorSet white_descriptor = upload_texture(white); + for (const auto& q : snapshot.ui_quads) + if (q.texture) + upload_texture(q.texture); + for (const auto& draw : snapshot.draws) + if (draw.texture) + upload_texture(draw.texture); + for (const auto& sprite : snapshot.sprites) + if (sprite.texture) + upload_texture(sprite.texture); + std::vector data; + std::vector scene_batches, shadow_batches, ui_batches; + for (const auto& item : snapshot.draws) { + if (!item.mesh) + continue; + auto first = data.size(); + const auto& mesh = *item.mesh; + auto emit = [&](std::uint32_t index) { + if (index >= mesh.vertices.size()) + throw std::out_of_range("Mesh index outside vertex range"); + data.push_back(gpu_vertex(mesh.vertices[index], item, snapshot.view_projection)); + }; + if (mesh.indices.empty()) + for (std::uint32_t i = 0; i < mesh.vertices.size(); ++i) + emit(i); + else + for (auto i : mesh.indices) + emit(i); + auto count = static_cast(data.size() - first); + if (count % 3) + throw std::invalid_argument( + "Mesh triangle vertex count must be divisible by three"); + if (!count) + continue; + Batch batch{static_cast(first), count, + item.texture ? item.texture.get() : white.get()}; + if (item.cast_shadow) + shadow_batches.push_back(batch); + if (outside(data, first)) + ++statistics.culled_meshes; + else + scene_batches.push_back(batch); + } + for (const auto& sprite : snapshot.sprites) { + auto first = static_cast(data.size()); + float c = std::cos(sprite.rotation), s = std::sin(sprite.rotation); + for (auto i : {0, 1, 2, 0, 2, 3}) { + const float corners[4][2] = {{-.5f, -.5f}, {.5f, -.5f}, {.5f, .5f}, {-.5f, .5f}}; + float x = corners[i][0] * sprite.size[0], y = corners[i][1] * sprite.size[1]; + auto clip = point(snapshot.view_projection, + {sprite.position[0] + c * x - s * y, + sprite.position[1] + s * x + c * y, sprite.position[2], 1}); + GpuVertex vertex{}; + std::copy(clip.begin(), clip.end(), vertex.clip); + std::copy(sprite.color.begin(), sprite.color.end(), vertex.color); + vertex.uv[0] = corners[i][0] + .5f; + vertex.uv[1] = .5f - corners[i][1]; + vertex.material[0] = sprite.texture && sprite.texture->srgb ? 1.f : 0.f; + data.push_back(vertex); + } + scene_batches.push_back( + {first, 6, sprite.texture ? sprite.texture.get() : white.get()}); + } + for (const auto& q : snapshot.ui_quads) { + auto first = static_cast(data.size()); + quad(data, q); + const Texture* texture = q.texture ? q.texture.get() : white.get(); + if (!ui_batches.empty() && ui_batches.back().texture == texture) + ui_batches.back().count += 6; + else + ui_batches.push_back({first, 6, texture}); + } + auto text_first = static_cast(data.size()); + for (const auto& text : snapshot.ui_text) + draw_debug_text(data, text); + if (data.size() > text_first) + ui_batches.push_back( + {text_first, static_cast(data.size() - text_first), white.get()}); + statistics.vertices = static_cast(data.size()); + auto byte_count = std::max(sizeof(GpuVertex), data.size() * sizeof(GpuVertex)); + if (vertices.size < byte_count) { + destroy(vertices); + vertices = make_buffer(byte_count, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, + VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | + VK_MEMORY_PROPERTY_HOST_COHERENT_BIT); + } + void* mapped{}; + check(vkMapMemory(device, vertices.memory, 0, vertices.size, 0, &mapped), "Map vertices"); + if (!data.empty()) + std::memcpy(mapped, data.data(), data.size() * sizeof(GpuVertex)); + vkUnmapMemory(device, vertices.memory); + Vec3 direction = snapshot.light_direction; + float length = std::sqrt(direction[0] * direction[0] + direction[1] * direction[1] + + direction[2] * direction[2]); + if (length < 1e-5f) { + direction = {-.5f, -1, -.3f}; + length = std::sqrt(1.34f); + } + for (auto& v : direction) + v /= length; + Vec3 light_eye{-direction[0] * 30, -direction[1] * 30, -direction[2] * 30}; + Vec3 light_up = std::abs(direction[1]) > .98f ? Vec3{0, 0, 1} : Vec3{0, 1, 0}; + Push push{multiply(orthographic(-20, 20, -20, 20, .1f, 80), + look_at(light_eye, {0, 0, 0}, light_up)), + {direction[0], direction[1], direction[2], 0}, + {snapshot.eye[0], snapshot.eye[1], snapshot.eye[2], 1}}; std::optional swap_index; - if(surface){std::uint32_t index{};auto result=vkAcquireNextImageKHR(device,swapchain,UINT64_MAX,acquired,VK_NULL_HANDLE,&index);if(result==VK_ERROR_OUT_OF_DATE_KHR){dirty_swapchain=true;return;}if(result==VK_SUBOPTIMAL_KHR)dirty_swapchain=true;else check(result,"Acquire swapchain image");swap_index=index;} - begin();if(timestamp_pool){vkCmdResetQueryPool(command,timestamp_pool,0,2);vkCmdWriteTimestamp2(command,VK_PIPELINE_STAGE_2_TOP_OF_PIPE_BIT,timestamp_pool,0);}VkDeviceSize offset{};vkCmdBindVertexBuffers(command,0,1,&vertices.handle,&offset);vkCmdPushConstants(command,pipeline_layout,VK_SHADER_STAGE_VERTEX_BIT|VK_SHADER_STAGE_FRAGMENT_BIT,0,sizeof(push),&push); - auto set_viewport=[&](std::uint32_t w,std::uint32_t h){VkViewport viewport{0,0,float(w),float(h),0,1};VkRect2D scissor{{0,0},{w,h}};vkCmdSetViewport(command,0,1,&viewport);vkCmdSetScissor(command,0,1,&scissor);}; + if (surface) { + std::uint32_t index{}; + auto result = vkAcquireNextImageKHR(device, swapchain, UINT64_MAX, acquired, + VK_NULL_HANDLE, &index); + if (result == VK_ERROR_OUT_OF_DATE_KHR) { + dirty_swapchain = true; + return; + } + if (result == VK_SUBOPTIMAL_KHR) + dirty_swapchain = true; + else + check(result, "Acquire swapchain image"); + swap_index = index; + } + begin(); + if (timestamp_pool) { + vkCmdResetQueryPool(command, timestamp_pool, 0, 2); + vkCmdWriteTimestamp2(command, VK_PIPELINE_STAGE_2_TOP_OF_PIPE_BIT, timestamp_pool, 0); + } + VkDeviceSize offset{}; + vkCmdBindVertexBuffers(command, 0, 1, &vertices.handle, &offset); + vkCmdPushConstants(command, pipeline_layout, + VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0, + sizeof(push), &push); + auto set_viewport = [&](std::uint32_t w, std::uint32_t h) { + VkViewport viewport{0, 0, float(w), float(h), 0, 1}; + VkRect2D scissor{{0, 0}, {w, h}}; + vkCmdSetViewport(command, 0, 1, &viewport); + vkCmdSetScissor(command, 0, 1, &scissor); + }; RenderGraph graph; - graph.add("ShadowMap",{}, {"shadow"},[&]{ - transition(command,shadow,VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL,VK_IMAGE_ASPECT_DEPTH_BIT);VkRenderingAttachmentInfo attachment{VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO};attachment.imageView=shadow.view;attachment.imageLayout=VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL;attachment.loadOp=VK_ATTACHMENT_LOAD_OP_CLEAR;attachment.storeOp=VK_ATTACHMENT_STORE_OP_STORE;attachment.clearValue.depthStencil={1,0};VkRenderingInfo rendering{VK_STRUCTURE_TYPE_RENDERING_INFO};rendering.renderArea={{0,0},{shadow_size,shadow_size}};rendering.layerCount=1;rendering.pDepthAttachment=&attachment;vkCmdBeginRendering(command,&rendering);set_viewport(shadow_size,shadow_size);vkCmdBindPipeline(command,VK_PIPELINE_BIND_POINT_GRAPHICS,shadow_pipeline);vkCmdPushConstants(command,pipeline_layout,VK_SHADER_STAGE_VERTEX_BIT|VK_SHADER_STAGE_FRAGMENT_BIT,0,sizeof(push),&push);for(auto batch:shadow_batches){vkCmdDraw(command,batch.count,1,batch.first,0);++statistics.draw_calls;}vkCmdEndRendering(command);transition(command,shadow,VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_OPTIMAL,VK_IMAGE_ASPECT_DEPTH_BIT); + graph.add("ShadowMap", {}, {"shadow"}, [&] { + transition(command, shadow, VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL, + VK_IMAGE_ASPECT_DEPTH_BIT); + VkRenderingAttachmentInfo attachment{VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO}; + attachment.imageView = shadow.view; + attachment.imageLayout = VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL; + attachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; + attachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE; + attachment.clearValue.depthStencil = {1, 0}; + VkRenderingInfo rendering{VK_STRUCTURE_TYPE_RENDERING_INFO}; + rendering.renderArea = {{0, 0}, {shadow_size, shadow_size}}; + rendering.layerCount = 1; + rendering.pDepthAttachment = &attachment; + vkCmdBeginRendering(command, &rendering); + set_viewport(shadow_size, shadow_size); + vkCmdBindPipeline(command, VK_PIPELINE_BIND_POINT_GRAPHICS, shadow_pipeline); + vkCmdPushConstants(command, pipeline_layout, + VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0, + sizeof(push), &push); + for (auto batch : shadow_batches) { + vkCmdDraw(command, batch.count, 1, batch.first, 0); + ++statistics.draw_calls; + } + vkCmdEndRendering(command); + transition(command, shadow, VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_OPTIMAL, + VK_IMAGE_ASPECT_DEPTH_BIT); }); - graph.add("ForwardAndUI",{"shadow"},{"color","depth"},[&]{ - transition(command,color,VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,VK_IMAGE_ASPECT_COLOR_BIT);transition(command,depth,VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL,VK_IMAGE_ASPECT_DEPTH_BIT);VkRenderingAttachmentInfo ca{VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO};ca.imageView=color.view;ca.imageLayout=VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;ca.loadOp=VK_ATTACHMENT_LOAD_OP_CLEAR;ca.storeOp=VK_ATTACHMENT_STORE_OP_STORE;std::copy(snapshot.clear_color.begin(),snapshot.clear_color.end(),ca.clearValue.color.float32);VkRenderingAttachmentInfo da{VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO};da.imageView=depth.view;da.imageLayout=VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL;da.loadOp=VK_ATTACHMENT_LOAD_OP_CLEAR;da.storeOp=VK_ATTACHMENT_STORE_OP_DONT_CARE;da.clearValue.depthStencil={1,0};VkRenderingInfo rendering{VK_STRUCTURE_TYPE_RENDERING_INFO};rendering.renderArea={{0,0},{width,height}};rendering.layerCount=1;rendering.colorAttachmentCount=1;rendering.pColorAttachments=&ca;rendering.pDepthAttachment=&da;vkCmdBeginRendering(command,&rendering);set_viewport(width,height);if(snapshot.scene_rect[2]>0&&snapshot.scene_rect[3]>0){auto r=snapshot.scene_rect;float x=std::clamp(r[0],0.f,float(width)),y=std::clamp(r[1],0.f,float(height));float w=std::min(r[2],float(width)-x),h=std::min(r[3],float(height)-y);VkViewport viewport{x,y,w,h,0,1};VkRect2D scissor{{static_cast(x),static_cast(y)},{static_cast(w),static_cast(h)}};vkCmdSetViewport(command,0,1,&viewport);vkCmdSetScissor(command,0,1,&scissor);}vkCmdBindPipeline(command,VK_PIPELINE_BIND_POINT_GRAPHICS,pipeline);vkCmdPushConstants(command,pipeline_layout,VK_SHADER_STAGE_VERTEX_BIT|VK_SHADER_STAGE_FRAGMENT_BIT,0,sizeof(push),&push);vkCmdBindDescriptorSets(command,VK_PIPELINE_BIND_POINT_GRAPHICS,pipeline_layout,0,1,&white_descriptor,0,nullptr);for(auto batch:scene_batches){auto descriptor=textures.at(batch.texture).descriptor;vkCmdBindDescriptorSets(command,VK_PIPELINE_BIND_POINT_GRAPHICS,pipeline_layout,0,1,&descriptor,0,nullptr);vkCmdDraw(command,batch.count,1,batch.first,0);++statistics.draw_calls;}set_viewport(width,height);vkCmdBindPipeline(command,VK_PIPELINE_BIND_POINT_GRAPHICS,ui_pipeline);vkCmdPushConstants(command,pipeline_layout,VK_SHADER_STAGE_VERTEX_BIT|VK_SHADER_STAGE_FRAGMENT_BIT,0,sizeof(push),&push);for(auto batch:ui_batches){auto descriptor=textures.at(batch.texture).descriptor;vkCmdBindDescriptorSets(command,VK_PIPELINE_BIND_POINT_GRAPHICS,pipeline_layout,0,1,&descriptor,0,nullptr);vkCmdDraw(command,batch.count,1,batch.first,0);++statistics.draw_calls;}vkCmdEndRendering(command); + graph.add("ForwardAndUI", {"shadow"}, {"color", "depth"}, [&] { + transition(command, color, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, + VK_IMAGE_ASPECT_COLOR_BIT); + transition(command, depth, VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL, + VK_IMAGE_ASPECT_DEPTH_BIT); + VkRenderingAttachmentInfo ca{VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO}; + ca.imageView = color.view; + ca.imageLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + ca.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; + ca.storeOp = VK_ATTACHMENT_STORE_OP_STORE; + std::copy(snapshot.clear_color.begin(), snapshot.clear_color.end(), + ca.clearValue.color.float32); + VkRenderingAttachmentInfo da{VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO}; + da.imageView = depth.view; + da.imageLayout = VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL; + da.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; + da.storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; + da.clearValue.depthStencil = {1, 0}; + VkRenderingInfo rendering{VK_STRUCTURE_TYPE_RENDERING_INFO}; + rendering.renderArea = {{0, 0}, {width, height}}; + rendering.layerCount = 1; + rendering.colorAttachmentCount = 1; + rendering.pColorAttachments = &ca; + rendering.pDepthAttachment = &da; + vkCmdBeginRendering(command, &rendering); + set_viewport(width, height); + if (snapshot.scene_rect[2] > 0 && snapshot.scene_rect[3] > 0) { + auto r = snapshot.scene_rect; + float x = std::clamp(r[0], 0.f, float(width)), + y = std::clamp(r[1], 0.f, float(height)); + float w = std::min(r[2], float(width) - x), h = std::min(r[3], float(height) - y); + VkViewport viewport{x, y, w, h, 0, 1}; + VkRect2D scissor{{static_cast(x), static_cast(y)}, + {static_cast(w), static_cast(h)}}; + vkCmdSetViewport(command, 0, 1, &viewport); + vkCmdSetScissor(command, 0, 1, &scissor); + } + vkCmdBindPipeline(command, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline); + vkCmdPushConstants(command, pipeline_layout, + VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0, + sizeof(push), &push); + vkCmdBindDescriptorSets(command, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_layout, 0, 1, + &white_descriptor, 0, nullptr); + for (auto batch : scene_batches) { + auto descriptor = textures.at(batch.texture).descriptor; + vkCmdBindDescriptorSets(command, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_layout, + 0, 1, &descriptor, 0, nullptr); + vkCmdDraw(command, batch.count, 1, batch.first, 0); + ++statistics.draw_calls; + } + set_viewport(width, height); + vkCmdBindPipeline(command, VK_PIPELINE_BIND_POINT_GRAPHICS, ui_pipeline); + vkCmdPushConstants(command, pipeline_layout, + VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0, + sizeof(push), &push); + for (auto batch : ui_batches) { + auto descriptor = textures.at(batch.texture).descriptor; + vkCmdBindDescriptorSets(command, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_layout, + 0, 1, &descriptor, 0, nullptr); + vkCmdDraw(command, batch.count, 1, batch.first, 0); + ++statistics.draw_calls; + } + vkCmdEndRendering(command); }); - graph.add("Readback",{"color"},{"capture"},[&]{transition(command,color,VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,VK_IMAGE_ASPECT_COLOR_BIT);VkBufferImageCopy copy{};copy.imageSubresource={VK_IMAGE_ASPECT_COLOR_BIT,0,0,1};copy.imageExtent={width,height,1};vkCmdCopyImageToBuffer(command,color.handle,VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,readback.handle,1,©);}); - if(swap_index)graph.add("Presentation",{"color"},{"swapchain"},[&]{auto index=*swap_index;transition(command,swap_images[index],swap_layouts[index],VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,VK_IMAGE_ASPECT_COLOR_BIT);VkImageBlit blit{};blit.srcSubresource={VK_IMAGE_ASPECT_COLOR_BIT,0,0,1};blit.srcOffsets[1]={static_cast(width),static_cast(height),1};blit.dstSubresource={VK_IMAGE_ASPECT_COLOR_BIT,0,0,1};blit.dstOffsets[1]={static_cast(swap_extent.width),static_cast(swap_extent.height),1};vkCmdBlitImage(command,color.handle,VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,swap_images[index],VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,1,&blit,VK_FILTER_NEAREST);transition(command,swap_images[index],swap_layouts[index],VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,VK_IMAGE_ASPECT_COLOR_BIT);}); - graph.execute();if(timestamp_pool)vkCmdWriteTimestamp2(command,VK_PIPELINE_STAGE_2_BOTTOM_OF_PIPE_BIT,timestamp_pool,1);submit(swap_index.has_value());if(timestamp_pool){std::uint64_t stamps[2]{};check(vkGetQueryPoolResults(device,timestamp_pool,0,2,sizeof(stamps),stamps,sizeof(std::uint64_t),VK_QUERY_RESULT_64_BIT|VK_QUERY_RESULT_WAIT_BIT),"Read GPU timestamps");auto delta=stamps[1]-stamps[0];if(timestamp_bits<64)delta&=(std::uint64_t(1)<(std::chrono::steady_clock::now()-start).count(); + graph.add("Readback", {"color"}, {"capture"}, [&] { + transition(command, color, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, + VK_IMAGE_ASPECT_COLOR_BIT); + VkBufferImageCopy copy{}; + copy.imageSubresource = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1}; + copy.imageExtent = {width, height, 1}; + vkCmdCopyImageToBuffer(command, color.handle, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, + readback.handle, 1, ©); + }); + if (swap_index) + graph.add("Presentation", {"color"}, {"swapchain"}, [&] { + auto index = *swap_index; + transition(command, swap_images[index], swap_layouts[index], + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_ASPECT_COLOR_BIT); + VkImageBlit blit{}; + blit.srcSubresource = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1}; + blit.srcOffsets[1] = {static_cast(width), static_cast(height), 1}; + blit.dstSubresource = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1}; + blit.dstOffsets[1] = {static_cast(swap_extent.width), + static_cast(swap_extent.height), 1}; + vkCmdBlitImage(command, color.handle, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, + swap_images[index], VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &blit, + VK_FILTER_NEAREST); + transition(command, swap_images[index], swap_layouts[index], + VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, VK_IMAGE_ASPECT_COLOR_BIT); + }); + graph.execute(); + if (timestamp_pool) + vkCmdWriteTimestamp2(command, VK_PIPELINE_STAGE_2_BOTTOM_OF_PIPE_BIT, timestamp_pool, + 1); + submit(swap_index.has_value()); + if (timestamp_pool) { + std::uint64_t stamps[2]{}; + check(vkGetQueryPoolResults(device, timestamp_pool, 0, 2, sizeof(stamps), stamps, + sizeof(std::uint64_t), + VK_QUERY_RESULT_64_BIT | VK_QUERY_RESULT_WAIT_BIT), + "Read GPU timestamps"); + auto delta = stamps[1] - stamps[0]; + if (timestamp_bits < 64) + delta &= (std::uint64_t(1) << timestamp_bits) - 1; + statistics.gpu_ms = double(delta) * timestamp_period / 1000000.0; + } + if (swap_index) { + VkPresentInfoKHR present{VK_STRUCTURE_TYPE_PRESENT_INFO_KHR}; + present.waitSemaphoreCount = 1; + present.pWaitSemaphores = &present_ready; + present.swapchainCount = 1; + present.pSwapchains = &swapchain; + present.pImageIndices = &*swap_index; + auto result = vkQueuePresentKHR(queue, &present); + if (result == VK_ERROR_OUT_OF_DATE_KHR || result == VK_SUBOPTIMAL_KHR) + dirty_swapchain = true; + else + check(result, "Present frame"); + check(vkQueueWaitIdle(queue), "Wait presentation"); + } + last_pixels.resize(std::size_t(width) * height * 4); + check(vkMapMemory(device, readback.memory, 0, readback.size, 0, &mapped), + "Map captured frame"); + std::memcpy(last_pixels.data(), mapped, last_pixels.size()); + vkUnmapMemory(device, readback.memory); + ++statistics.frame; + statistics.validation_errors = validation_errors.load(); + statistics.cpu_ms = + std::chrono::duration(std::chrono::steady_clock::now() - start) + .count(); } }; -Renderer::Renderer(const RendererConfig& config):impl_(std::make_unique()){impl_->initialize(config);} -Renderer::~Renderer()=default; -Renderer::Renderer(Renderer&&) noexcept=default; -Renderer& Renderer::operator=(Renderer&&) noexcept=default; -void Renderer::render(const Snapshot& snapshot){impl_->render(snapshot);} -bool Renderer::reload_shaders(std::string& error){ - auto& r=*impl_;check(vkDeviceWaitIdle(r.device),"Wait shader reload"); - auto previous_layout=r.pipeline_layout;auto previous=r.pipeline;auto previous_ui=r.ui_pipeline;auto previous_shadow=r.shadow_pipeline; - r.pipeline_layout={};r.pipeline={};r.ui_pipeline={};r.shadow_pipeline={}; - try{r.make_pipelines();}catch(const std::exception& exception){ - if(r.pipeline)vkDestroyPipeline(r.device,r.pipeline,nullptr);if(r.ui_pipeline)vkDestroyPipeline(r.device,r.ui_pipeline,nullptr);if(r.shadow_pipeline)vkDestroyPipeline(r.device,r.shadow_pipeline,nullptr);if(r.pipeline_layout)vkDestroyPipelineLayout(r.device,r.pipeline_layout,nullptr); - r.pipeline_layout=previous_layout;r.pipeline=previous;r.ui_pipeline=previous_ui;r.shadow_pipeline=previous_shadow;error=exception.what();return false; +Renderer::Renderer(const RendererConfig& config) : impl_(std::make_unique()) { + impl_->initialize(config); +} +Renderer::~Renderer() = default; +Renderer::Renderer(Renderer&&) noexcept = default; +Renderer& Renderer::operator=(Renderer&&) noexcept = default; +void Renderer::render(const Snapshot& snapshot) { + impl_->render(snapshot); +} +bool Renderer::reload_shaders(std::string& error) { + auto& r = *impl_; + check(vkDeviceWaitIdle(r.device), "Wait shader reload"); + auto previous_layout = r.pipeline_layout; + auto previous = r.pipeline; + auto previous_ui = r.ui_pipeline; + auto previous_shadow = r.shadow_pipeline; + r.pipeline_layout = {}; + r.pipeline = {}; + r.ui_pipeline = {}; + r.shadow_pipeline = {}; + try { + r.make_pipelines(); + } catch (const std::exception& exception) { + if (r.pipeline) + vkDestroyPipeline(r.device, r.pipeline, nullptr); + if (r.ui_pipeline) + vkDestroyPipeline(r.device, r.ui_pipeline, nullptr); + if (r.shadow_pipeline) + vkDestroyPipeline(r.device, r.shadow_pipeline, nullptr); + if (r.pipeline_layout) + vkDestroyPipelineLayout(r.device, r.pipeline_layout, nullptr); + r.pipeline_layout = previous_layout; + r.pipeline = previous; + r.ui_pipeline = previous_ui; + r.shadow_pipeline = previous_shadow; + error = exception.what(); + return false; } - vkDestroyPipeline(r.device,previous,nullptr);vkDestroyPipeline(r.device,previous_ui,nullptr);vkDestroyPipeline(r.device,previous_shadow,nullptr);vkDestroyPipelineLayout(r.device,previous_layout,nullptr);error.clear();return true; + vkDestroyPipeline(r.device, previous, nullptr); + vkDestroyPipeline(r.device, previous_ui, nullptr); + vkDestroyPipeline(r.device, previous_shadow, nullptr); + vkDestroyPipelineLayout(r.device, previous_layout, nullptr); + error.clear(); + return true; } -void Renderer::resize(std::uint32_t w,std::uint32_t h){if(!w||!h)return;if(impl_->window){SDL_SetWindowSize(impl_->window,static_cast(w),static_cast(h));impl_->dirty_swapchain=true;}else if(w!=impl_->width||h!=impl_->height){impl_->width=w;impl_->height=h;impl_->make_targets();}} -std::uint32_t Renderer::width()const{return impl_->width;} -std::uint32_t Renderer::height()const{return impl_->height;} -bool Renderer::should_close()const{return impl_->close;} -const FrameStats& Renderer::stats()const{return impl_->statistics;} -std::vector Renderer::pixels()const{return impl_->last_pixels;} -void Renderer::capture(const std::filesystem::path& path){if(impl_->last_pixels.empty())throw std::runtime_error("Cannot capture before a completed frame");std::ofstream out(path,std::ios::binary);if(!out)throw std::runtime_error("Cannot write screenshot: "+path.string());out<<"P6\n"<last_pixels.size();i+=4)out.write(reinterpret_cast(impl_->last_pixels.data()+i),3);if(!out)throw std::runtime_error("Screenshot write failed");} -void Renderer::set_title(const std::string& title){if(impl_->window)SDL_SetWindowTitle(impl_->window,title.c_str());} -void Renderer::set_text_input(bool enabled){if(!impl_->window)return;if(enabled)SDL_StartTextInput(impl_->window);else SDL_StopTextInput(impl_->window);} -void Renderer::set_text_input_area(float x,float y,float width,float height){ - if(!impl_->window)return;int w{},h{},pw{},ph{};SDL_GetWindowSize(impl_->window,&w,&h);SDL_GetWindowSizeInPixels(impl_->window,&pw,&ph);float sx=pw>0?float(w)/float(pw):1,sy=ph>0?float(h)/float(ph):1;SDL_Rect rectangle{int(x*sx),int(y*sy),std::max(1,int(width*sx)),std::max(1,int(height*sy))};if(!SDL_SetTextInputArea(impl_->window,&rectangle,0))throw std::runtime_error(SDL_GetError()); +void Renderer::resize(std::uint32_t w, std::uint32_t h) { + if (!w || !h) + return; + if (impl_->window) { + SDL_SetWindowSize(impl_->window, static_cast(w), static_cast(h)); + impl_->dirty_swapchain = true; + } else if (w != impl_->width || h != impl_->height) { + impl_->width = w; + impl_->height = h; + impl_->make_targets(); + } } -void Renderer::set_clipboard(const std::string& text){if(!SDL_SetClipboardText(text.c_str()))throw std::runtime_error(SDL_GetError());} -std::string Renderer::clipboard()const{char* text=SDL_GetClipboardText();if(!text)return {};std::string result=text;SDL_free(text);return result;} -std::vector Renderer::poll_events(){ - std::vector result;SDL_Event event{};while(SDL_PollEvent(&event)){Event item;bool emit=true;auto modifiers=SDL_GetModState();item.control=(modifiers&SDL_KMOD_CTRL)!=0;item.shift=(modifiers&SDL_KMOD_SHIFT)!=0;item.alt=(modifiers&SDL_KMOD_ALT)!=0; - switch(event.type){ - case SDL_EVENT_QUIT:case SDL_EVENT_WINDOW_CLOSE_REQUESTED:item.type=Event::Type::Quit;impl_->close=true;break; - case SDL_EVENT_WINDOW_RESIZED:case SDL_EVENT_WINDOW_PIXEL_SIZE_CHANGED:item.type=Event::Type::Resize;item.x=float(event.window.data1);item.y=float(event.window.data2);impl_->dirty_swapchain=true;break; - case SDL_EVENT_WINDOW_FOCUS_GAINED:item.type=Event::Type::FocusGained;break; - case SDL_EVENT_WINDOW_FOCUS_LOST:item.type=Event::Type::FocusLost;break; - case SDL_EVENT_MOUSE_MOTION:item.type=Event::Type::MouseMove;item.x=event.motion.x;item.y=event.motion.y;break; - case SDL_EVENT_MOUSE_BUTTON_DOWN:case SDL_EVENT_MOUSE_BUTTON_UP:item.type=event.type==SDL_EVENT_MOUSE_BUTTON_DOWN?Event::Type::MouseDown:Event::Type::MouseUp;item.x=event.button.x;item.y=event.button.y;item.button=event.button.button;break; - case SDL_EVENT_MOUSE_WHEEL:item.type=Event::Type::Wheel;item.x=event.wheel.x;item.y=event.wheel.y;break; - case SDL_EVENT_KEY_DOWN:case SDL_EVENT_KEY_UP:item.type=event.type==SDL_EVENT_KEY_DOWN?Event::Type::KeyDown:Event::Type::KeyUp;item.key=SDL_GetKeyName(event.key.key);item.repeat=event.key.repeat;break; - case SDL_EVENT_TEXT_INPUT:item.type=Event::Type::TextInput;item.text=event.text.text;break; - case SDL_EVENT_TEXT_EDITING:item.type=Event::Type::TextEditing;item.text=event.edit.text;item.edit_start=event.edit.start;item.edit_length=event.edit.length;break; - default:emit=false; +std::uint32_t Renderer::width() const { + return impl_->width; +} +std::uint32_t Renderer::height() const { + return impl_->height; +} +bool Renderer::should_close() const { + return impl_->close; +} +const FrameStats& Renderer::stats() const { + return impl_->statistics; +} +std::vector Renderer::pixels() const { + return impl_->last_pixels; +} +void Renderer::capture(const std::filesystem::path& path) { + if (impl_->last_pixels.empty()) + throw std::runtime_error("Cannot capture before a completed frame"); + std::ofstream out(path, std::ios::binary); + if (!out) + throw std::runtime_error("Cannot write screenshot: " + path.string()); + out << "P6\n" << width() << ' ' << height() << "\n255\n"; + for (std::size_t i = 0; i < impl_->last_pixels.size(); i += 4) + out.write(reinterpret_cast(impl_->last_pixels.data() + i), 3); + if (!out) + throw std::runtime_error("Screenshot write failed"); +} +void Renderer::set_title(const std::string& title) { + if (impl_->window) + SDL_SetWindowTitle(impl_->window, title.c_str()); +} +void Renderer::set_text_input(bool enabled) { + if (!impl_->window) + return; + if (enabled) + SDL_StartTextInput(impl_->window); + else + SDL_StopTextInput(impl_->window); +} +void Renderer::set_text_input_area(float x, float y, float width, float height) { + if (!impl_->window) + return; + int w{}, h{}, pw{}, ph{}; + SDL_GetWindowSize(impl_->window, &w, &h); + SDL_GetWindowSizeInPixels(impl_->window, &pw, &ph); + float sx = pw > 0 ? float(w) / float(pw) : 1, sy = ph > 0 ? float(h) / float(ph) : 1; + SDL_Rect rectangle{int(x * sx), int(y * sy), std::max(1, int(width * sx)), + std::max(1, int(height * sy))}; + if (!SDL_SetTextInputArea(impl_->window, &rectangle, 0)) + throw std::runtime_error(SDL_GetError()); +} +void Renderer::set_clipboard(const std::string& text) { + if (!SDL_SetClipboardText(text.c_str())) + throw std::runtime_error(SDL_GetError()); +} +std::string Renderer::clipboard() const { + char* text = SDL_GetClipboardText(); + if (!text) + return {}; + std::string result = text; + SDL_free(text); + return result; +} +std::vector Renderer::poll_events() { + std::vector result; + SDL_Event event{}; + while (SDL_PollEvent(&event)) { + Event item; + bool emit = true; + auto modifiers = SDL_GetModState(); + item.control = (modifiers & SDL_KMOD_CTRL) != 0; + item.shift = (modifiers & SDL_KMOD_SHIFT) != 0; + item.alt = (modifiers & SDL_KMOD_ALT) != 0; + switch (event.type) { + case SDL_EVENT_QUIT: + case SDL_EVENT_WINDOW_CLOSE_REQUESTED: + item.type = Event::Type::Quit; + impl_->close = true; + break; + case SDL_EVENT_WINDOW_RESIZED: + case SDL_EVENT_WINDOW_PIXEL_SIZE_CHANGED: + item.type = Event::Type::Resize; + item.x = float(event.window.data1); + item.y = float(event.window.data2); + impl_->dirty_swapchain = true; + break; + case SDL_EVENT_WINDOW_FOCUS_GAINED: + item.type = Event::Type::FocusGained; + break; + case SDL_EVENT_WINDOW_FOCUS_LOST: + item.type = Event::Type::FocusLost; + break; + case SDL_EVENT_MOUSE_MOTION: + item.type = Event::Type::MouseMove; + item.x = event.motion.x; + item.y = event.motion.y; + break; + case SDL_EVENT_MOUSE_BUTTON_DOWN: + case SDL_EVENT_MOUSE_BUTTON_UP: + item.type = event.type == SDL_EVENT_MOUSE_BUTTON_DOWN ? Event::Type::MouseDown + : Event::Type::MouseUp; + item.x = event.button.x; + item.y = event.button.y; + item.button = event.button.button; + break; + case SDL_EVENT_MOUSE_WHEEL: + item.type = Event::Type::Wheel; + item.x = event.wheel.x; + item.y = event.wheel.y; + break; + case SDL_EVENT_KEY_DOWN: + case SDL_EVENT_KEY_UP: + item.type = + event.type == SDL_EVENT_KEY_DOWN ? Event::Type::KeyDown : Event::Type::KeyUp; + item.key = SDL_GetKeyName(event.key.key); + item.repeat = event.key.repeat; + break; + case SDL_EVENT_TEXT_INPUT: + item.type = Event::Type::TextInput; + item.text = event.text.text; + break; + case SDL_EVENT_TEXT_EDITING: + item.type = Event::Type::TextEditing; + item.text = event.edit.text; + item.edit_start = event.edit.start; + item.edit_length = event.edit.length; + break; + default: + emit = false; } - // Rendering/UI coordinates use drawable pixels; SDL pointer events use logical window units. - if(impl_->window&&(item.type==Event::Type::MouseMove||item.type==Event::Type::MouseDown||item.type==Event::Type::MouseUp)){int w{},h{},pw{},ph{};SDL_GetWindowSize(impl_->window,&w,&h);SDL_GetWindowSizeInPixels(impl_->window,&pw,&ph);if(w>0&&h>0){item.x*=float(pw)/float(w);item.y*=float(ph)/float(h);}} - if(emit)result.push_back(std::move(item)); - }return result; -} + // Rendering/UI coordinates use drawable pixels; SDL pointer events use logical window + // units. + if (impl_->window && + (item.type == Event::Type::MouseMove || item.type == Event::Type::MouseDown || + item.type == Event::Type::MouseUp)) { + int w{}, h{}, pw{}, ph{}; + SDL_GetWindowSize(impl_->window, &w, &h); + SDL_GetWindowSizeInPixels(impl_->window, &pw, &ph); + if (w > 0 && h > 0) { + item.x *= float(pw) / float(w); + item.y *= float(ph) / float(h); + } + } + if (emit) + result.push_back(std::move(item)); + } + return result; } +} // namespace faset::render diff --git a/src/runtime/Physics.cpp b/src/runtime/Physics.cpp index ddd50a4..d48609a 100644 --- a/src/runtime/Physics.cpp +++ b/src/runtime/Physics.cpp @@ -1,7 +1,7 @@ #include "Physics.hpp" +#include #include #include -#include #include #include #include @@ -15,103 +15,245 @@ b3Quat quaternion(Vec3 e) { return b3MulQuat(z, b3MulQuat(y, x)); } Vec3 euler(b3Quat q) { - const float x=q.v.x, y=q.v.y, z=q.v.z, w=q.s; - return {std::atan2(2*(w*x+y*z), 1-2*(x*x+y*y)), - std::asin(std::clamp(2*(w*y-z*x), -1.0f, 1.0f)), - std::atan2(2*(w*z+x*y), 1-2*(y*y+z*z))}; -} + const float x = q.v.x, y = q.v.y, z = q.v.z, w = q.s; + return {std::atan2(2 * (w * x + y * z), 1 - 2 * (x * x + y * y)), + std::asin(std::clamp(2 * (w * y - z * x), -1.0f, 1.0f)), + std::atan2(2 * (w * z + x * y), 1 - 2 * (y * y + z * z))}; } +} // namespace struct Physics::Impl { - struct Body { b2BodyId two{}; b3BodyId three{}; std::uint64_t shape{}; bool dynamic{}; }; + struct Body { + b2BodyId two{}; + b3BodyId three{}; + std::uint64_t shape{}; + bool dynamic{}; + bool contactQueryValid{}; + }; int dimension; int substeps; + Vec3 up{0, 1, 0}; b2WorldId world2{}; b3WorldId world3{}; std::unordered_map bodies; std::unordered_map shapes; - Impl(int dim, Vec3 gravity, int count):dimension(dim),substeps(count) { - if(dim==2) { auto def=b2DefaultWorldDef(); def.gravity={gravity[0],gravity[1]}; world2=b2CreateWorld(&def); } - else { auto def=b3DefaultWorldDef(); def.gravity={gravity[0],gravity[1],gravity[2]}; world3=b3CreateWorld(&def); } + Impl(int dim, Vec3 gravity, int count) : dimension(dim), substeps(count) { + const float length = std::sqrt(gravity[0] * gravity[0] + gravity[1] * gravity[1] + + (dim == 3 ? gravity[2] * gravity[2] : 0)); + if (length > 0.00001f) + up = {-gravity[0] / length, -gravity[1] / length, dim == 3 ? -gravity[2] / length : 0}; + if (dim == 2) { + auto def = b2DefaultWorldDef(); + def.gravity = {gravity[0], gravity[1]}; + world2 = b2CreateWorld(&def); + } else { + auto def = b3DefaultWorldDef(); + def.gravity = {gravity[0], gravity[1], gravity[2]}; + world3 = b3CreateWorld(&def); + } + } + ~Impl() { + if (dimension == 2) + b2DestroyWorld(world2); + else + b3DestroyWorld(world3); } - ~Impl() { if(dimension==2) b2DestroyWorld(world2); else b3DestroyWorld(world3); } }; -Physics::Physics(int dimension, Vec3 gravity, int substeps):impl_(std::make_unique(dimension,gravity,substeps)){} -Physics::~Physics()=default; +Physics::Physics(int dimension, Vec3 gravity, int substeps) + : impl_(std::make_unique(dimension, gravity, substeps)) {} +Physics::~Physics() = default; void Physics::add(std::uint32_t id, const Transform& t, const BodySettings& settings) { - if(contains(id)) throw std::logic_error("physics body already exists"); - Impl::Body body{}; body.dynamic=settings.type=="dynamic"; - if(impl_->dimension==2) { - auto def=b2DefaultBodyDef(); - def.type=settings.type=="static"?b2_staticBody:settings.type=="kinematic"?b2_kinematicBody:b2_dynamicBody; - def.position={t.position[0],t.position[1]}; def.rotation=b2MakeRot(t.rotation[2]); - def.linearVelocity={settings.linearVelocity[0],settings.linearVelocity[1]}; def.gravityScale=settings.gravityScale; - body.two=b2CreateBody(impl_->world2,&def); - auto shape=b2DefaultShapeDef(); shape.density=settings.density; shape.material.friction=settings.friction; - shape.material.restitution=settings.restitution; shape.enableContactEvents=true; - shape.filter.categoryBits=settings.categoryBits; shape.filter.maskBits=settings.maskBits; - const auto box=b2MakeBox(settings.halfExtents[0]*std::abs(t.scale[0]),settings.halfExtents[1]*std::abs(t.scale[1])); - body.shape=b2StoreShapeId(b2CreatePolygonShape(body.two,&shape,&box)); + if (contains(id)) + throw std::logic_error("physics body already exists"); + Impl::Body body{}; + body.dynamic = settings.type == "dynamic"; + if (impl_->dimension == 2) { + auto def = b2DefaultBodyDef(); + def.type = settings.type == "static" ? b2_staticBody + : settings.type == "kinematic" ? b2_kinematicBody + : b2_dynamicBody; + def.position = {t.position[0], t.position[1]}; + def.rotation = b2MakeRot(t.rotation[2]); + def.linearVelocity = {settings.linearVelocity[0], settings.linearVelocity[1]}; + def.gravityScale = settings.gravityScale; + body.two = b2CreateBody(impl_->world2, &def); + auto shape = b2DefaultShapeDef(); + shape.density = settings.density; + shape.material.friction = settings.friction; + shape.material.restitution = settings.restitution; + shape.enableContactEvents = true; + shape.filter.categoryBits = settings.categoryBits; + shape.filter.maskBits = settings.maskBits; + const auto box = b2MakeBox(settings.halfExtents[0] * std::abs(t.scale[0]), + settings.halfExtents[1] * std::abs(t.scale[1])); + body.shape = b2StoreShapeId(b2CreatePolygonShape(body.two, &shape, &box)); } else { - auto def=b3DefaultBodyDef(); - def.type=settings.type=="static"?b3_staticBody:settings.type=="kinematic"?b3_kinematicBody:b3_dynamicBody; - def.position={t.position[0],t.position[1],t.position[2]}; def.rotation=quaternion(t.rotation); - def.linearVelocity={settings.linearVelocity[0],settings.linearVelocity[1],settings.linearVelocity[2]}; def.gravityScale=settings.gravityScale; - body.three=b3CreateBody(impl_->world3,&def); - auto shape=b3DefaultShapeDef(); shape.density=settings.density; shape.baseMaterial.friction=settings.friction; - shape.baseMaterial.restitution=settings.restitution; shape.enableContactEvents=true; - shape.filter.categoryBits=settings.categoryBits; shape.filter.maskBits=settings.maskBits; - auto box=b3MakeBoxHull(settings.halfExtents[0]*std::abs(t.scale[0]),settings.halfExtents[1]*std::abs(t.scale[1]),settings.halfExtents[2]*std::abs(t.scale[2])); - body.shape=b3StoreShapeId(b3CreateHullShape(body.three,&shape,&box.base)); + auto def = b3DefaultBodyDef(); + def.type = settings.type == "static" ? b3_staticBody + : settings.type == "kinematic" ? b3_kinematicBody + : b3_dynamicBody; + def.position = {t.position[0], t.position[1], t.position[2]}; + def.rotation = quaternion(t.rotation); + def.linearVelocity = {settings.linearVelocity[0], settings.linearVelocity[1], + settings.linearVelocity[2]}; + def.gravityScale = settings.gravityScale; + body.three = b3CreateBody(impl_->world3, &def); + auto shape = b3DefaultShapeDef(); + shape.density = settings.density; + shape.baseMaterial.friction = settings.friction; + shape.baseMaterial.restitution = settings.restitution; + shape.enableContactEvents = true; + shape.filter.categoryBits = settings.categoryBits; + shape.filter.maskBits = settings.maskBits; + auto box = b3MakeBoxHull(settings.halfExtents[0] * std::abs(t.scale[0]), + settings.halfExtents[1] * std::abs(t.scale[1]), + settings.halfExtents[2] * std::abs(t.scale[2])); + body.shape = b3StoreShapeId(b3CreateHullShape(body.three, &shape, &box.base)); } - impl_->shapes.emplace(body.shape,id); impl_->bodies.emplace(id,body); + impl_->shapes.emplace(body.shape, id); + impl_->bodies.emplace(id, body); } void Physics::remove(std::uint32_t id) { - const auto it=impl_->bodies.find(id); if(it==impl_->bodies.end()) return; + const auto it = impl_->bodies.find(id); + if (it == impl_->bodies.end()) + return; impl_->shapes.erase(it->second.shape); - if(impl_->dimension==2) b2DestroyBody(it->second.two); else b3DestroyBody(it->second.three); + if (impl_->dimension == 2) + b2DestroyBody(it->second.two); + else + b3DestroyBody(it->second.three); impl_->bodies.erase(it); } -bool Physics::contains(std::uint32_t id) const { return impl_->bodies.contains(id); } -bool Physics::dynamic(std::uint32_t id) const { return impl_->bodies.at(id).dynamic; } +bool Physics::contains(std::uint32_t id) const { + return impl_->bodies.contains(id); +} +bool Physics::dynamic(std::uint32_t id) const { + return impl_->bodies.at(id).dynamic; +} Transform Physics::transform(std::uint32_t id, Transform t) const { - const auto& body=impl_->bodies.at(id); - if(impl_->dimension==2) { auto p=b2Body_GetPosition(body.two); t.position[0]=p.x;t.position[1]=p.y;t.rotation[2]=b2Rot_GetAngle(b2Body_GetRotation(body.two)); } - else { auto p=b3Body_GetPosition(body.three);t.position={float(p.x),float(p.y),float(p.z)};t.rotation=euler(b3Body_GetRotation(body.three)); } + const auto& body = impl_->bodies.at(id); + if (impl_->dimension == 2) { + auto p = b2Body_GetPosition(body.two); + t.position[0] = p.x; + t.position[1] = p.y; + t.rotation[2] = b2Rot_GetAngle(b2Body_GetRotation(body.two)); + } else { + auto p = b3Body_GetPosition(body.three); + t.position = {float(p.x), float(p.y), float(p.z)}; + t.rotation = euler(b3Body_GetRotation(body.three)); + } return t; } Vec3 Physics::velocity(std::uint32_t id) const { - const auto& body=impl_->bodies.at(id); - if(impl_->dimension==2) { auto v=b2Body_GetLinearVelocity(body.two);return {v.x,v.y,0}; } - auto v=b3Body_GetLinearVelocity(body.three);return {v.x,v.y,v.z}; + const auto& body = impl_->bodies.at(id); + if (impl_->dimension == 2) { + auto v = b2Body_GetLinearVelocity(body.two); + return {v.x, v.y, 0}; + } + auto v = b3Body_GetLinearVelocity(body.three); + return {v.x, v.y, v.z}; +} +bool Physics::grounded(std::uint32_t id) const { + const auto& body = impl_->bodies.at(id); + if (!body.contactQueryValid) + return false; + auto supports = [&](Vec3 normal, float sign) { + return sign * (normal[0] * impl_->up[0] + normal[1] * impl_->up[1] + + normal[2] * impl_->up[2]) > + 0.6f; + }; + if (impl_->dimension == 2) { + const int capacity = b2Body_GetContactCapacity(body.two); + if (capacity <= 0) + return false; + std::vector contacts(static_cast(capacity)); + const int count = b2Body_GetContactData(body.two, contacts.data(), capacity); + for (int i = 0; i < count; ++i) { + const auto& c = contacts[i]; + const float sign = b2StoreShapeId(c.shapeIdA) == body.shape ? -1.0f : 1.0f; + if (!supports({c.manifold.normal.x, c.manifold.normal.y, 0}, sign)) + continue; + for (int p = 0; p < c.manifold.pointCount; ++p) + if (c.manifold.points[p].separation <= 0.02f) + return true; + } + } else { + const int capacity = b3Body_GetContactCapacity(body.three); + if (capacity <= 0) + return false; + std::vector contacts(static_cast(capacity)); + const int count = b3Body_GetContactData(body.three, contacts.data(), capacity); + for (int i = 0; i < count; ++i) { + const auto& c = contacts[i]; + const float sign = b3StoreShapeId(c.shapeIdA) == body.shape ? -1.0f : 1.0f; + // Box3D's manifold pointer is consumed now and never retained. + for (int m = 0; m < c.manifoldCount; ++m) { + const auto& manifold = c.manifolds[m]; + if (!supports({manifold.normal.x, manifold.normal.y, manifold.normal.z}, sign)) + continue; + for (int p = 0; p < manifold.pointCount; ++p) + if (manifold.points[p].separation <= 0.02f) + return true; + } + } + } + return false; } void Physics::teleport(std::uint32_t id, const Transform& t) { - const auto& body=impl_->bodies.at(id); - if(impl_->dimension==2) b2Body_SetTransform(body.two,{t.position[0],t.position[1]},b2MakeRot(t.rotation[2])); - else b3Body_SetTransform(body.three,{t.position[0],t.position[1],t.position[2]},quaternion(t.rotation)); + auto& body = impl_->bodies.at(id); + body.contactQueryValid = false; + if (impl_->dimension == 2) { + b2Body_SetTransform(body.two, {t.position[0], t.position[1]}, b2MakeRot(t.rotation[2])); + b2Body_SetAwake(body.two, true); + } else { + b3Body_SetTransform(body.three, {t.position[0], t.position[1], t.position[2]}, + quaternion(t.rotation)); + b3Body_SetAwake(body.three, true); + } } void Physics::setVelocity(std::uint32_t id, Vec3 v) { - const auto& body=impl_->bodies.at(id); - if(impl_->dimension==2) b2Body_SetLinearVelocity(body.two,{v[0],v[1]}); else b3Body_SetLinearVelocity(body.three,{v[0],v[1],v[2]}); + const auto& body = impl_->bodies.at(id); + if (impl_->dimension == 2) + b2Body_SetLinearVelocity(body.two, {v[0], v[1]}); + else + b3Body_SetLinearVelocity(body.three, {v[0], v[1], v[2]}); } void Physics::impulse(std::uint32_t id, Vec3 v) { - const auto& body=impl_->bodies.at(id); - if(impl_->dimension==2) b2Body_ApplyLinearImpulseToCenter(body.two,{v[0],v[1]},true); else b3Body_ApplyLinearImpulseToCenter(body.three,{v[0],v[1],v[2]},true); + const auto& body = impl_->bodies.at(id); + if (impl_->dimension == 2) + b2Body_ApplyLinearImpulseToCenter(body.two, {v[0], v[1]}, true); + else + b3Body_ApplyLinearImpulseToCenter(body.three, {v[0], v[1], v[2]}, true); } std::vector Physics::step(float delta) { std::vector contacts; - auto append=[&](std::uint64_t a,std::uint64_t b,bool began) { - auto first=impl_->shapes.find(a),second=impl_->shapes.find(b); - if(first!=impl_->shapes.end() && second!=impl_->shapes.end()) contacts.push_back({first->second,second->second,began}); + auto append = [&](std::uint64_t a, std::uint64_t b, bool began) { + auto first = impl_->shapes.find(a), second = impl_->shapes.find(b); + if (first != impl_->shapes.end() && second != impl_->shapes.end()) + contacts.push_back({first->second, second->second, began}); }; - if(impl_->dimension==2) { - b2World_Step(impl_->world2,delta,impl_->substeps);auto events=b2World_GetContactEvents(impl_->world2); - for(int i=0;idimension == 2) { + b2World_Step(impl_->world2, delta, impl_->substeps); + auto events = b2World_GetContactEvents(impl_->world2); + for (int i = 0; i < events.beginCount; ++i) + append(b2StoreShapeId(events.beginEvents[i].shapeIdA), + b2StoreShapeId(events.beginEvents[i].shapeIdB), true); + for (int i = 0; i < events.endCount; ++i) + append(b2StoreShapeId(events.endEvents[i].shapeIdA), + b2StoreShapeId(events.endEvents[i].shapeIdB), false); } else { - b3World_Step(impl_->world3,delta,impl_->substeps);auto events=b3World_GetContactEvents(impl_->world3); - for(int i=0;iworld3, delta, impl_->substeps); + auto events = b3World_GetContactEvents(impl_->world3); + for (int i = 0; i < events.beginCount; ++i) + append(b3StoreShapeId(events.beginEvents[i].shapeIdA), + b3StoreShapeId(events.beginEvents[i].shapeIdB), true); + for (int i = 0; i < events.endCount; ++i) + append(b3StoreShapeId(events.endEvents[i].shapeIdA), + b3StoreShapeId(events.endEvents[i].shapeIdB), false); + } + for (auto& [id, body] : impl_->bodies) { + (void)id; + body.contactQueryValid = true; } return contacts; } -} +} // namespace faset::runtime::detail diff --git a/src/runtime/Physics.hpp b/src/runtime/Physics.hpp index 2c87feb..c5a3229 100644 --- a/src/runtime/Physics.hpp +++ b/src/runtime/Physics.hpp @@ -14,9 +14,13 @@ struct BodySettings { std::uint64_t categoryBits{1}; std::uint64_t maskBits{~std::uint64_t{0}}; }; -struct Contact { std::uint32_t first; std::uint32_t second; bool began; }; +struct Contact { + std::uint32_t first; + std::uint32_t second; + bool began; +}; class Physics { -public: + public: Physics(int dimension, Vec3 gravity, int substeps); ~Physics(); void add(std::uint32_t id, const Transform&, const BodySettings&); @@ -25,12 +29,14 @@ public: bool dynamic(std::uint32_t id) const; Transform transform(std::uint32_t id, Transform previous) const; Vec3 velocity(std::uint32_t id) const; + bool grounded(std::uint32_t id) const; void teleport(std::uint32_t id, const Transform&); void setVelocity(std::uint32_t id, Vec3); void impulse(std::uint32_t id, Vec3); std::vector step(float delta); -private: + + private: struct Impl; std::unique_ptr impl_; }; -} +} // namespace faset::runtime::detail diff --git a/src/runtime/Runtime.cpp b/src/runtime/Runtime.cpp index 975311c..9b4e7b6 100644 --- a/src/runtime/Runtime.cpp +++ b/src/runtime/Runtime.cpp @@ -1,10 +1,10 @@ -#include #include "Physics.hpp" -#include #include #include #include #include +#include +#include #include #include #include @@ -12,282 +12,761 @@ namespace faset::runtime { namespace { -using Json=nlohmann::json; +using Json = nlohmann::json; std::atomic nextSession{1}; -constexpr const char* body2="faset.rigid_body_2d"; -constexpr const char* body3="faset.rigid_body_3d"; -void require(bool condition,const std::string& message) { if(!condition) throw std::invalid_argument(message); } -template std::array vectorValue(const Json& object,const char* key,std::array fallback) { - if(!object.contains(key)) return fallback; - const auto& value=object.at(key); require(value.is_array()&&value.size()==N,std::string(key)+": wrong vector size"); - for(std::size_t i=0;i(); require(std::isfinite(fallback[i]),std::string(key)+": nonfinite value"); } +constexpr const char* body2 = "faset.rigid_body_2d"; +constexpr const char* body3 = "faset.rigid_body_3d"; +void require(bool condition, const std::string& message) { + if (!condition) + throw std::invalid_argument(message); +} +template +std::array vectorValue(const Json& object, const char* key, + std::array fallback) { + if (!object.contains(key)) + return fallback; + const auto& value = object.at(key); + require(value.is_array() && value.size() == N, std::string(key) + ": wrong vector size"); + for (std::size_t i = 0; i < N; ++i) { + require(value[i].is_number(), std::string(key) + ": expected number"); + fallback[i] = value[i].get(); + require(std::isfinite(fallback[i]), std::string(key) + ": nonfinite value"); + } return fallback; } -float number(const Json& fields,const char* key,float fallback) { - if(!fields.contains(key)) return fallback; - require(fields.at(key).is_number(),std::string(key)+": expected number"); - float v=fields.at(key).get();require(std::isfinite(v),std::string(key)+": nonfinite value");return v; +float number(const Json& fields, const char* key, float fallback) { + if (!fields.contains(key)) + return fallback; + require(fields.at(key).is_number(), std::string(key) + ": expected number"); + float v = fields.at(key).get(); + require(std::isfinite(v), std::string(key) + ": nonfinite value"); + return v; } Transform readTransform(const Json& fields) { - return {vectorValue<3>(fields,"position",{0,0,0}),vectorValue<3>(fields,"rotation",{0,0,0}),vectorValue<3>(fields,"scale",{1,1,1})}; + return {vectorValue<3>(fields, "position", {0, 0, 0}), + vectorValue<3>(fields, "rotation", {0, 0, 0}), + vectorValue<3>(fields, "scale", {1, 1, 1})}; } void validateTransform(const Transform& t) { - for(const auto& values:{t.position,t.rotation,t.scale}) for(float value:values) require(std::isfinite(value),"nonfinite transform"); + for (const auto& values : {t.position, t.rotation, t.scale}) + for (float value : values) + require(std::isfinite(value), "nonfinite transform"); } -Json transformJson(const Transform& t) { return {{"position",t.position},{"rotation",t.rotation},{"scale",t.scale}}; } -detail::BodySettings settings(const Json& fields,int dimension) { +Json transformJson(const Transform& t) { + return {{"position", t.position}, {"rotation", t.rotation}, {"scale", t.scale}}; +} +detail::BodySettings settings(const Json& fields, int dimension) { detail::BodySettings b; - b.type=fields.value("body_type",std::string("dynamic"));require(b.type=="dynamic"||b.type=="static"||b.type=="kinematic","invalid body_type"); - if(dimension==2) { - auto half=vectorValue<2>(fields,"half_extents",{0.5f,0.5f});b.halfExtents={half[0],half[1],0.5f}; - auto vel=vectorValue<2>(fields,"linear_velocity",{0,0});b.linearVelocity={vel[0],vel[1],0}; - } else { b.halfExtents=vectorValue<3>(fields,"half_extents",{0.5f,0.5f,0.5f});b.linearVelocity=vectorValue<3>(fields,"linear_velocity",{0,0,0}); } - for(float extent:b.halfExtents) require(extent>0&&extent<100000,"half_extents must be positive and finite"); - b.density=number(fields,"density",1); b.friction=number(fields,"friction",0.3f); - b.restitution=number(fields,"restitution",0);b.gravityScale=number(fields,"gravity_scale",1); - require(b.density>0&&b.friction>=0&&b.restitution>=0&&b.restitution<=1,"invalid physics material"); - auto bits=[&](const char* name,std::uint64_t fallback) { if(!fields.contains(name))return fallback; const auto& value=fields.at(name);require(value.is_number_unsigned()||(value.is_number_integer()&&value.get()>=0),std::string(name)+": expected nonnegative bits");return value.get(); }; - b.categoryBits=bits("category_bits",1);b.maskBits=bits("mask_bits",~std::uint64_t{0});return b; -} -void validateEntity(const Json& entity,int dimension) { - require(entity.is_object(),"entity must be an object"); - require(entity.contains("id")&&entity["id"].is_string()&&!entity["id"].get().empty(),"entity requires id"); - require(!entity.contains("name")||entity["name"].is_string(),"entity name must be a string"); - require(entity.contains("components")&&entity["components"].is_array(),"entity requires components array"); - if(entity.contains("parent"))require(entity["parent"].is_null()||entity["parent"].is_string(),"parent must be an id or null"); - std::set types, ids;Transform transform{};bool physical=false; - for(const auto& component:entity["components"]) { - require(component.is_object()&&component.contains("id")&&component["id"].is_string()&&!component["id"].get().empty(),"component requires id"); - require(component.contains("type")&&component["type"].is_string()&&!component["type"].get().empty(),"component requires type"); - require(component.value("version",1)==1,"unsupported component version"); - require(component.contains("fields")&&component["fields"].is_object(),"component requires fields"); - require(ids.insert(component["id"].get()).second,"duplicate component id"); - const auto type=component["type"].get();require(types.insert(type).second,"duplicate component type"); - const auto& f=component["fields"]; - if(type=="faset.transform")transform=readTransform(f); - if(type==body2||type==body3) { require(type==(dimension==2?body2:body3),"physics dimension does not match scene");settings(f,dimension);physical=true; } - if(type=="faset.sprite") {vectorValue<4>(f,"color",{1,1,1,1});auto size=vectorValue<2>(f,"size",{1,1});require(size[0]>0&&size[1]>0,"sprite size must be positive");require(!f.contains("texture")||f["texture"].is_string(),"sprite texture must be a string");require(!f.contains("layer")||f["layer"].is_number_integer(),"sprite layer must be an integer");} - if(type=="faset.mesh") {vectorValue<4>(f,"color",{1,1,1,1});require(!f.contains("asset")||f["asset"].is_string(),"mesh asset must be a string");require(!f.contains("primitive")||f["primitive"].is_string(),"mesh primitive must be a string");} + b.type = fields.value("body_type", std::string("dynamic")); + require(b.type == "dynamic" || b.type == "static" || b.type == "kinematic", + "invalid body_type"); + if (dimension == 2) { + auto half = vectorValue<2>(fields, "half_extents", {0.5f, 0.5f}); + b.halfExtents = {half[0], half[1], 0.5f}; + auto vel = vectorValue<2>(fields, "linear_velocity", {0, 0}); + b.linearVelocity = {vel[0], vel[1], 0}; + } else { + b.halfExtents = vectorValue<3>(fields, "half_extents", {0.5f, 0.5f, 0.5f}); + b.linearVelocity = vectorValue<3>(fields, "linear_velocity", {0, 0, 0}); } - if(physical) { - require(!entity.contains("parent")||entity["parent"].is_null(),"physics bodies must be root entities in the initial runtime"); - for(int i=0;i0.00001f,"physics scale must be nonzero"); - if(dimension==2) require(transform.rotation[0]==0&&transform.rotation[1]==0,"2D physics rotates only around Z"); - } -} -Transform interpolate(const Transform& a,const Transform& b,float alpha) { - Transform out; - for(int i=0;i<3;++i) { - out.position[i]=std::lerp(a.position[i],b.position[i],alpha);out.scale[i]=std::lerp(a.scale[i],b.scale[i],alpha); - } - auto quaternion=[](Vec3 r) { - const float cx=std::cos(r[0]*0.5f),sx=std::sin(r[0]*0.5f),cy=std::cos(r[1]*0.5f),sy=std::sin(r[1]*0.5f),cz=std::cos(r[2]*0.5f),sz=std::sin(r[2]*0.5f); - return Vec4{sx*cy*cz-cx*sy*sz,cx*sy*cz+sx*cy*sz,cx*cy*sz-sx*sy*cz,cx*cy*cz+sx*sy*sz}; + for (float extent : b.halfExtents) + require(extent > 0 && extent < 100000, "half_extents must be positive and finite"); + b.density = number(fields, "density", 1); + b.friction = number(fields, "friction", 0.3f); + b.restitution = number(fields, "restitution", 0); + b.gravityScale = number(fields, "gravity_scale", 1); + require(b.density > 0 && b.friction >= 0 && b.restitution >= 0 && b.restitution <= 1, + "invalid physics material"); + auto bits = [&](const char* name, std::uint64_t fallback) { + if (!fields.contains(name)) + return fallback; + const auto& value = fields.at(name); + require(value.is_number_unsigned() || + (value.is_number_integer() && value.get() >= 0), + std::string(name) + ": expected nonnegative bits"); + return value.get(); }; - auto qa=quaternion(a.rotation),qb=quaternion(b.rotation);float dot=0; - for(int i=0;i<4;++i)dot+=qa[i]*qb[i]; - if(dot<0){for(auto& q:qb)q=-q;dot=-dot;} - float wa=1-alpha,wb=alpha; - if(dot<0.9995f){const float angle=std::acos(std::clamp(dot,-1.0f,1.0f)),denom=std::sin(angle);wa=std::sin((1-alpha)*angle)/denom;wb=std::sin(alpha*angle)/denom;} - Vec4 q{};float length=0;for(int i=0;i<4;++i){q[i]=wa*qa[i]+wb*qb[i];length+=q[i]*q[i];}for(auto& v:q)v/=std::sqrt(length); - const auto [x,y,z,w]=q; - out.rotation={std::atan2(2*(w*x+y*z),1-2*(x*x+y*y)),std::asin(std::clamp(2*(w*y-z*x),-1.0f,1.0f)),std::atan2(2*(w*z+x*y),1-2*(y*y+z*z))}; + b.categoryBits = bits("category_bits", 1); + b.maskBits = bits("mask_bits", ~std::uint64_t{0}); + return b; +} +void validateEntity(const Json& entity, int dimension) { + require(entity.is_object(), "entity must be an object"); + require(entity.contains("id") && entity["id"].is_string() && + !entity["id"].get().empty(), + "entity requires id"); + require(!entity.contains("name") || entity["name"].is_string(), "entity name must be a string"); + require(entity.contains("components") && entity["components"].is_array(), + "entity requires components array"); + if (entity.contains("parent")) + require(entity["parent"].is_null() || entity["parent"].is_string(), + "parent must be an id or null"); + std::set types, ids; + Transform transform{}; + bool physical = false; + for (const auto& component : entity["components"]) { + require(component.is_object() && component.contains("id") && component["id"].is_string() && + !component["id"].get().empty(), + "component requires id"); + require(component.contains("type") && component["type"].is_string() && + !component["type"].get().empty(), + "component requires type"); + require(component.value("version", 1) == 1, "unsupported component version"); + require(component.contains("fields") && component["fields"].is_object(), + "component requires fields"); + require(ids.insert(component["id"].get()).second, "duplicate component id"); + const auto type = component["type"].get(); + require(types.insert(type).second, "duplicate component type"); + const auto& f = component["fields"]; + if (type == "faset.transform") + transform = readTransform(f); + if (type == body2 || type == body3) { + require(type == (dimension == 2 ? body2 : body3), + "physics dimension does not match scene"); + settings(f, dimension); + physical = true; + } + if (type == "faset.sprite") { + vectorValue<4>(f, "color", {1, 1, 1, 1}); + auto size = vectorValue<2>(f, "size", {1, 1}); + require(size[0] > 0 && size[1] > 0, "sprite size must be positive"); + require(!f.contains("texture") || f["texture"].is_string(), + "sprite texture must be a string"); + require(!f.contains("layer") || f["layer"].is_number_integer(), + "sprite layer must be an integer"); + } + if (type == "faset.mesh") { + vectorValue<4>(f, "color", {1, 1, 1, 1}); + require(!f.contains("asset") || f["asset"].is_string(), "mesh asset must be a string"); + require(!f.contains("primitive") || f["primitive"].is_string(), + "mesh primitive must be a string"); + } + } + if (physical) { + require(!entity.contains("parent") || entity["parent"].is_null(), + "physics bodies must be root entities in the initial runtime"); + for (int i = 0; i < dimension; ++i) + require(std::abs(transform.scale[i]) > 0.00001f, "physics scale must be nonzero"); + if (dimension == 2) + require(transform.rotation[0] == 0 && transform.rotation[1] == 0, + "2D physics rotates only around Z"); + } +} +Transform interpolate(const Transform& a, const Transform& b, float alpha) { + Transform out; + for (int i = 0; i < 3; ++i) { + out.position[i] = std::lerp(a.position[i], b.position[i], alpha); + out.scale[i] = std::lerp(a.scale[i], b.scale[i], alpha); + } + auto quaternion = [](Vec3 r) { + const float cx = std::cos(r[0] * 0.5f), sx = std::sin(r[0] * 0.5f), + cy = std::cos(r[1] * 0.5f), sy = std::sin(r[1] * 0.5f), + cz = std::cos(r[2] * 0.5f), sz = std::sin(r[2] * 0.5f); + return Vec4{sx * cy * cz - cx * sy * sz, cx * sy * cz + sx * cy * sz, + cx * cy * sz - sx * sy * cz, cx * cy * cz + sx * sy * sz}; + }; + auto qa = quaternion(a.rotation), qb = quaternion(b.rotation); + float dot = 0; + for (int i = 0; i < 4; ++i) + dot += qa[i] * qb[i]; + if (dot < 0) { + for (auto& q : qb) + q = -q; + dot = -dot; + } + float wa = 1 - alpha, wb = alpha; + if (dot < 0.9995f) { + const float angle = std::acos(std::clamp(dot, -1.0f, 1.0f)), denom = std::sin(angle); + wa = std::sin((1 - alpha) * angle) / denom; + wb = std::sin(alpha * angle) / denom; + } + Vec4 q{}; + float length = 0; + for (int i = 0; i < 4; ++i) { + q[i] = wa * qa[i] + wb * qb[i]; + length += q[i] * q[i]; + } + for (auto& v : q) + v /= std::sqrt(length); + const auto [x, y, z, w] = q; + out.rotation = {std::atan2(2 * (w * x + y * z), 1 - 2 * (x * x + y * y)), + std::asin(std::clamp(2 * (w * y - z * x), -1.0f, 1.0f)), + std::atan2(2 * (w * z + x * y), 1 - 2 * (y * y + z * z))}; return out; } -} +} // namespace struct Runtime::Impl { - struct Data { Json document; std::uint64_t generation; }; - struct Pose { Transform previous,current,presented; bool changedInUpdate{}; }; + struct Data { + Json document; + std::uint64_t generation; + }; + struct Pose { + Transform previous, current, presented; + bool changedInUpdate{}; + }; enum class Phase { Idle, Initialize, Fixed, Update, Late, Destroy }; enum class Kind { Spawn, Destroy, Add, Remove }; - struct Command { Kind kind; EntityHandle handle; Json payload; std::string type; }; + struct Command { + Kind kind; + EntityHandle handle; + Json payload; + std::string type; + }; Runtime* owner; RuntimeConfig config; entt::registry registry; - std::unordered_map ids; - std::unordered_map behaviors; + std::unordered_map ids; + std::unordered_map behaviors; std::vector order; std::deque pending; std::unique_ptr physics; std::vector contacts; std::vector diagnostics; std::uint64_t session{nextSession.fetch_add(1)}; - std::uint64_t generation{},tick{}; + std::uint64_t generation{}, tick{}; int dimension{3}; - double accumulator{},alpha{}; - bool paused{},busy{}; - InputState currentInput{},queuedInput{}; + double accumulator{}, alpha{}; + bool paused{}, busy{}; + InputState currentInput{}, queuedInput{}; Phase phase{Phase::Idle}; - Impl(Runtime* runtime,RuntimeConfig cfg):owner(runtime),config(cfg){} - EntityHandle handle(entt::entity e) const {return {session,entt::to_integral(e),registry.get(e).generation};} - bool valid(EntityHandle h)const noexcept { auto e=static_cast(h.slot);return h.session==session&®istry.valid(e)&®istry.all_of(e)&®istry.get(e).generation==h.generation; } - entt::entity entity(EntityHandle h)const {if(!valid(h))throw std::invalid_argument("stale or foreign runtime handle");return static_cast(h.slot);} - const Json* component(entt::entity e,const std::string& type)const {for(const auto& c:registry.get(e).document["components"])if(c["type"]==type)return &c;return nullptr;} - void callback(const Behavior::Callback& fn,entt::entity e,double dt) { - if(!fn)return; - try {fn(*owner,handle(e),dt);}catch(const std::exception& ex){diagnostics.push_back("gameplay "+registry.get(e).document["id"].get()+": "+ex.what());}catch(...){diagnostics.push_back("unknown gameplay exception");} + Impl(Runtime* runtime, RuntimeConfig cfg) : owner(runtime), config(cfg) {} + EntityHandle handle(entt::entity e) const { + return {session, entt::to_integral(e), registry.get(e).generation}; } - void lifecycle(entt::entity e,Behavior::Callback Behavior::* member,double dt) { - const auto components=registry.get(e).document["components"]; - for(const auto& c:components) {auto it=behaviors.find(c["type"].get());if(it!=behaviors.end())callback(it->second.*member,e,dt);} + bool valid(EntityHandle h) const noexcept { + auto e = static_cast(h.slot); + return h.session == session && registry.valid(e) && registry.all_of(e) && + registry.get(e).generation == h.generation; + } + entt::entity entity(EntityHandle h) const { + if (!valid(h)) + throw std::invalid_argument("stale or foreign runtime handle"); + return static_cast(h.slot); + } + const Json* component(entt::entity e, const std::string& type) const { + for (const auto& c : registry.get(e).document["components"]) + if (c["type"] == type) + return &c; + return nullptr; + } + void callback(const Behavior::Callback& fn, entt::entity e, double dt) { + if (!fn) + return; + try { + fn(*owner, handle(e), dt); + } catch (const std::exception& ex) { + diagnostics.push_back("gameplay " + + registry.get(e).document["id"].get() + ": " + + ex.what()); + } catch (...) { + diagnostics.push_back("unknown gameplay exception"); + } + } + void lifecycle(entt::entity e, Behavior::Callback Behavior::* member, double dt) { + const auto components = registry.get(e).document["components"]; + for (const auto& c : components) { + auto it = behaviors.find(c["type"].get()); + if (it != behaviors.end()) + callback(it->second.*member, e, dt); + } + } + void all(Behavior::Callback Behavior::* member, double dt) { + for (auto e : order) + if (registry.valid(e)) + lifecycle(e, member, dt); } - void all(Behavior::Callback Behavior::* member,double dt) {for(auto e:order)if(registry.valid(e))lifecycle(e,member,dt);} void syncVisual(entt::entity e) { - if(auto c=component(e,"faset.sprite")){const auto& f=(*c)["fields"];registry.emplace_or_replace(e,vectorValue<4>(f,"color",{1,1,1,1}),vectorValue<2>(f,"size",{1,1}),f.value("texture",std::string{}),f.value("layer",0));}else registry.remove(e); - if(auto c=component(e,"faset.mesh")){const auto& f=(*c)["fields"];registry.emplace_or_replace(e,f.value("asset",std::string{}),vectorValue<4>(f,"color",{1,1,1,1}),f.value("primitive",std::string("cube")));}else registry.remove(e); + if (auto c = component(e, "faset.sprite")) { + const auto& f = (*c)["fields"]; + registry.emplace_or_replace( + e, vectorValue<4>(f, "color", {1, 1, 1, 1}), vectorValue<2>(f, "size", {1, 1}), + f.value("texture", std::string{}), f.value("layer", 0)); + } else + registry.remove(e); + if (auto c = component(e, "faset.mesh")) { + const auto& f = (*c)["fields"]; + registry.emplace_or_replace(e, f.value("asset", std::string{}), + vectorValue<4>(f, "color", {1, 1, 1, 1}), + f.value("primitive", std::string("cube"))); + } else + registry.remove(e); } void addPhysics(entt::entity e) { - require(bool(physics),"load a scene before creating physics"); - auto c=component(e,dimension==2?body2:body3);if(c)physics->add(entt::to_integral(e),registry.get(e).current,settings((*c)["fields"],dimension)); + require(bool(physics), "load a scene before creating physics"); + auto c = component(e, dimension == 2 ? body2 : body3); + if (c) + physics->add(entt::to_integral(e), registry.get(e).current, + settings((*c)["fields"], dimension)); } entt::entity create(Json document) { - const auto id=document["id"].get();require(!ids.contains(id),"duplicate entity id: "+id); - auto e=registry.create();Transform t{}; - for(const auto& c:document["components"])if(c["type"]=="faset.transform")t=readTransform(c["fields"]); - registry.emplace(e,std::move(document),++generation);registry.emplace(e,t,t,t,false);ids.emplace(id,e);order.push_back(e);addPhysics(e);syncVisual(e);return e; + const auto id = document["id"].get(); + require(!ids.contains(id), "duplicate entity id: " + id); + auto e = registry.create(); + Transform t{}; + for (const auto& c : document["components"]) + if (c["type"] == "faset.transform") + t = readTransform(c["fields"]); + registry.emplace(e, std::move(document), ++generation); + registry.emplace(e, t, t, t, false); + ids.emplace(id, e); + order.push_back(e); + addPhysics(e); + syncVisual(e); + return e; } void erase(entt::entity e) { // Authoring hierarchy destruction has the same subtree semantics in runtime. - auto id=registry.get(e).document["id"].get(); + auto id = registry.get(e).document["id"].get(); std::vector children; - for(auto child:order)if(registry.valid(child)&®istry.get(child).document.value("parent",Json{})==id)children.push_back(child); - for(auto child:children)erase(child); - phase=Phase::Destroy;lifecycle(e,&Behavior::onDestroy,0); - physics->remove(entt::to_integral(e));ids.erase(id);registry.destroy(e); - std::erase(order,e); + for (auto child : order) + if (registry.valid(child) && + registry.get(child).document.value("parent", Json{}) == id) + children.push_back(child); + for (auto child : children) + erase(child); + phase = Phase::Destroy; + lifecycle(e, &Behavior::onDestroy, 0); + physics->remove(entt::to_integral(e)); + ids.erase(id); + registry.destroy(e); + std::erase(order, e); } void commands() { - auto commands=std::move(pending);pending.clear(); - for(auto& command:commands)try { - if(command.kind==Kind::Spawn) { - validateEntity(command.payload,dimension); - auto parent=command.payload.value("parent",Json{});require(parent.is_null()||ids.contains(parent.get()),"spawn parent is absent"); - auto e=create(std::move(command.payload));phase=Phase::Initialize;lifecycle(e,&Behavior::onStart,0);continue; + auto commands = std::move(pending); + pending.clear(); + for (auto& command : commands) + try { + if (command.kind == Kind::Spawn) { + validateEntity(command.payload, dimension); + auto parent = command.payload.value("parent", Json{}); + require(parent.is_null() || ids.contains(parent.get()), + "spawn parent is absent"); + auto e = create(std::move(command.payload)); + phase = Phase::Initialize; + lifecycle(e, &Behavior::onStart, 0); + continue; + } + if (!valid(command.handle)) { + diagnostics.push_back("ignored structural command for stale handle"); + continue; + } + auto e = entity(command.handle); + if (command.kind == Kind::Destroy) { + erase(e); + continue; + } + auto candidate = registry.get(e).document; + auto& components = candidate["components"]; + if (command.kind == Kind::Add) { + components.push_back(command.payload); + validateEntity(candidate, dimension); + } else { + auto it = + std::find_if(components.begin(), components.end(), + [&](const Json& c) { return c["type"] == command.type; }); + if (it == components.end()) + continue; + if (command.type == "faset.transform" && physics->contains(command.handle.slot)) + throw std::invalid_argument("remove physics before removing transform"); + auto behavior = behaviors.find(command.type); + if (behavior != behaviors.end()) { + phase = Phase::Destroy; + callback(behavior->second.onDestroy, e, 0); + } + components.erase(it); + } + const std::string changed = command.kind == Kind::Add + ? command.payload["type"].get() + : command.type; + if ((changed == body2 || changed == body3) && command.kind == Kind::Add) { + const auto& pose = registry.get(e).current; + for (int i = 0; i < dimension; ++i) + require(std::abs(pose.scale[i]) > 0.00001f, + "runtime physics scale must be nonzero"); + if (dimension == 2) + require(pose.rotation[0] == 0 && pose.rotation[1] == 0, + "2D physics rotates only around Z"); + } + registry.get(e).document = std::move(candidate); + syncVisual(e); + if (changed == body2 || changed == body3) { + if (command.kind == Kind::Add) + addPhysics(e); + else + physics->remove(command.handle.slot); + } + if (changed == "faset.transform") { + auto& d = registry.get(e); + d.current = command.kind == Kind::Add ? readTransform(command.payload["fields"]) + : Transform{}; + d.previous = d.presented = d.current; + } + if (command.kind == Kind::Add) { + auto it = behaviors.find(changed); + if (it != behaviors.end()) { + phase = Phase::Initialize; + callback(it->second.onStart, e, 0); + } + } + } catch (const std::exception& ex) { + diagnostics.push_back(std::string("structural command rejected: ") + ex.what()); } - if(!valid(command.handle)){diagnostics.push_back("ignored structural command for stale handle");continue;} - auto e=entity(command.handle); - if(command.kind==Kind::Destroy){erase(e);continue;} - auto candidate=registry.get(e).document; - auto& components=candidate["components"]; - if(command.kind==Kind::Add) {components.push_back(command.payload);validateEntity(candidate,dimension);} - else { auto it=std::find_if(components.begin(),components.end(),[&](const Json& c){return c["type"]==command.type;});if(it==components.end())continue; - if(command.type=="faset.transform"&&physics->contains(command.handle.slot))throw std::invalid_argument("remove physics before removing transform"); - auto behavior=behaviors.find(command.type);if(behavior!=behaviors.end()){phase=Phase::Destroy;callback(behavior->second.onDestroy,e,0);}components.erase(it); - } - const std::string changed=command.kind==Kind::Add?command.payload["type"].get():command.type; - if((changed==body2||changed==body3)&&command.kind==Kind::Add) { - const auto& pose=registry.get(e).current; - for(int i=0;i0.00001f,"runtime physics scale must be nonzero"); - if(dimension==2)require(pose.rotation[0]==0&&pose.rotation[1]==0,"2D physics rotates only around Z"); - } - registry.get(e).document=std::move(candidate);syncVisual(e); - if(changed==body2||changed==body3) {if(command.kind==Kind::Add)addPhysics(e);else physics->remove(command.handle.slot);} - if(changed=="faset.transform") {auto& d=registry.get(e);d.current=command.kind==Kind::Add?readTransform(command.payload["fields"]):Transform{};d.previous=d.presented=d.current;} - if(command.kind==Kind::Add){auto it=behaviors.find(changed);if(it!=behaviors.end()){phase=Phase::Initialize;callback(it->second.onStart,e,0);}} - }catch(const std::exception& ex){diagnostics.push_back(std::string("structural command rejected: ")+ex.what());} } void fixed() { - commands();phase=Phase::Fixed; - for(auto [e,d]:registry.view().each()){(void)e;d.previous=d.current;} - currentInput=queuedInput;queuedInput.jumpPressed=false;queuedInput.interactPressed=false; - all(&Behavior::fixedUpdate,config.fixedDelta); - contacts.clear(); - if(physics) { - auto events=physics->step(static_cast(config.fixedDelta)); - for(auto e:order)if(physics->contains(entt::to_integral(e))) {auto& d=registry.get(e);d.current=physics->transform(entt::to_integral(e),d.current);} - for(const auto& event:events) { - auto a=static_cast(event.first),b=static_cast(event.second); - if(!registry.valid(a)||!registry.valid(b))continue; - contacts.push_back({handle(a),handle(b),event.began}); - } - for(const auto& event:contacts)for(auto h:{event.first,event.second}) { - auto e=entity(h);for(const auto& c:registry.get(e).document["components"]) { - auto it=behaviors.find(c["type"].get());if(it!=behaviors.end()&&it->second.onCollision) - try{it->second.onCollision(*owner,h,event);}catch(const std::exception& ex){diagnostics.push_back(std::string("collision callback: ")+ex.what());}catch(...){diagnostics.push_back("unknown collision callback exception");} - } - } + commands(); + phase = Phase::Fixed; + for (auto [e, d] : registry.view().each()) { + (void)e; + d.previous = d.current; } - ++tick;phase=Phase::Idle; + currentInput = queuedInput; + queuedInput.jumpPressed = false; + queuedInput.interactPressed = false; + all(&Behavior::fixedUpdate, config.fixedDelta); + contacts.clear(); + if (physics) { + auto events = physics->step(static_cast(config.fixedDelta)); + for (auto e : order) + if (physics->contains(entt::to_integral(e))) { + auto& d = registry.get(e); + d.current = physics->transform(entt::to_integral(e), d.current); + } + for (const auto& event : events) { + auto a = static_cast(event.first), + b = static_cast(event.second); + if (!registry.valid(a) || !registry.valid(b)) + continue; + contacts.push_back({handle(a), handle(b), event.began}); + } + for (const auto& event : contacts) + for (auto h : {event.first, event.second}) { + auto e = entity(h); + for (const auto& c : registry.get(e).document["components"]) { + auto it = behaviors.find(c["type"].get()); + if (it != behaviors.end() && it->second.onCollision) + try { + it->second.onCollision(*owner, h, event); + } catch (const std::exception& ex) { + diagnostics.push_back(std::string("collision callback: ") + + ex.what()); + } catch (...) { + diagnostics.push_back("unknown collision callback exception"); + } + } + } + } + ++tick; + phase = Phase::Idle; } - FrameStats frame(double elapsed,InputState input,bool step) { - require(std::isfinite(elapsed)&&elapsed>=0,"elapsed time must be finite and nonnegative");require(!busy,"recursive runtime advance"); - require(std::isfinite(input.horizontal)&&std::isfinite(input.vertical),"input axes must be finite"); - struct Guard {bool& busy;~Guard(){busy=false;}}guard{busy};busy=true; + FrameStats frame(double elapsed, InputState input, bool step) { + require(std::isfinite(elapsed) && elapsed >= 0, + "elapsed time must be finite and nonnegative"); + require(!busy, "recursive runtime advance"); + require(std::isfinite(input.horizontal) && std::isfinite(input.vertical), + "input axes must be finite"); + struct Guard { + bool& busy; + ~Guard() { + busy = false; + } + } guard{busy}; + busy = true; FrameStats stats{}; - if(paused&&!step){accumulator=0;currentInput={};queuedInput={};return {0,0,alpha,tick};} - queuedInput.horizontal=input.horizontal;queuedInput.vertical=input.vertical; - queuedInput.jumpPressed=queuedInput.jumpPressed||input.jumpPressed;queuedInput.interactPressed=queuedInput.interactPressed||input.interactPressed; - for(auto [e,d]:registry.view().each()){(void)e;d.changedInUpdate=false;} - accumulator+=step?config.fixedDelta:elapsed; - while(accumulator+1e-12>=config.fixedDelta&&stats.fixedTicks<(step?1u:config.maxCatchUpTicks)) {fixed();accumulator=std::max(0.0,accumulator-config.fixedDelta);++stats.fixedTicks;} - if(accumulator>=config.fixedDelta){auto remaining=std::fmod(accumulator,config.fixedDelta);stats.droppedTime=accumulator-remaining;accumulator=remaining;diagnostics.push_back("dropped_time="+std::to_string(stats.droppedTime));} - currentInput=input;phase=Phase::Update;all(&Behavior::update,step?config.fixedDelta:elapsed); - alpha=step?1.0:std::clamp(accumulator/config.fixedDelta,0.0,1.0); - for(auto [e,d]:registry.view().each()){(void)e;d.presented=d.changedInUpdate?d.current:interpolate(d.previous,d.current,static_cast(alpha));} - phase=Phase::Late;all(&Behavior::lateUpdate,step?config.fixedDelta:elapsed);phase=Phase::Idle; - stats.interpolationAlpha=alpha;stats.tick=tick;return stats; + if (paused && !step) { + accumulator = 0; + currentInput = {}; + queuedInput = {}; + return {0, 0, alpha, tick}; + } + queuedInput.horizontal = input.horizontal; + queuedInput.vertical = input.vertical; + queuedInput.jumpPressed = queuedInput.jumpPressed || input.jumpPressed; + queuedInput.interactPressed = queuedInput.interactPressed || input.interactPressed; + for (auto [e, d] : registry.view().each()) { + (void)e; + d.changedInUpdate = false; + } + accumulator += step ? config.fixedDelta : elapsed; + while (accumulator + 1e-12 >= config.fixedDelta && + stats.fixedTicks < (step ? 1u : config.maxCatchUpTicks)) { + fixed(); + accumulator = std::max(0.0, accumulator - config.fixedDelta); + ++stats.fixedTicks; + } + if (accumulator >= config.fixedDelta) { + auto remaining = std::fmod(accumulator, config.fixedDelta); + stats.droppedTime = accumulator - remaining; + accumulator = remaining; + diagnostics.push_back("dropped_time=" + std::to_string(stats.droppedTime)); + } + currentInput = input; + phase = Phase::Update; + all(&Behavior::update, step ? config.fixedDelta : elapsed); + alpha = step ? 1.0 : std::clamp(accumulator / config.fixedDelta, 0.0, 1.0); + for (auto [e, d] : registry.view().each()) { + (void)e; + d.presented = d.changedInUpdate + ? d.current + : interpolate(d.previous, d.current, static_cast(alpha)); + } + phase = Phase::Late; + all(&Behavior::lateUpdate, step ? config.fixedDelta : elapsed); + phase = Phase::Idle; + stats.interpolationAlpha = alpha; + stats.tick = tick; + return stats; } }; -Runtime::Runtime(RuntimeConfig cfg):impl_(std::make_unique(this,cfg)) { - require(std::isfinite(cfg.fixedDelta)&&cfg.fixedDelta>0&&cfg.fixedDelta<=1,"invalid fixed delta"); - require(cfg.maxCatchUpTicks>0&&cfg.maxCatchUpTicks<=1024,"invalid catchup limit");require(cfg.physicsSubsteps>0&&cfg.physicsSubsteps<=128,"invalid physics substeps"); - for(float value:cfg.gravity)require(std::isfinite(value),"invalid gravity"); +Runtime::Runtime(RuntimeConfig cfg) : impl_(std::make_unique(this, cfg)) { + require(std::isfinite(cfg.fixedDelta) && cfg.fixedDelta > 0 && cfg.fixedDelta <= 1, + "invalid fixed delta"); + require(cfg.maxCatchUpTicks > 0 && cfg.maxCatchUpTicks <= 1024, "invalid catchup limit"); + require(cfg.physicsSubsteps > 0 && cfg.physicsSubsteps <= 128, "invalid physics substeps"); + for (float value : cfg.gravity) + require(std::isfinite(value), "invalid gravity"); } -Runtime::~Runtime(){try{clear();}catch(...){}} -void Runtime::registerBehavior(std::string type,Behavior behavior) { - require(!impl_->busy&&impl_->ids.empty(),"register gameplay before loading scene");require(!type.empty()&&!impl_->behaviors.contains(type),"duplicate or empty behavior type");impl_->behaviors.emplace(std::move(type),std::move(behavior)); +Runtime::~Runtime() { + try { + clear(); + } catch (...) { + } +} +void Runtime::registerBehavior(std::string type, Behavior behavior) { + require(!impl_->busy && impl_->ids.empty(), "register gameplay before loading scene"); + require(!type.empty() && !impl_->behaviors.contains(type), "duplicate or empty behavior type"); + impl_->behaviors.emplace(std::move(type), std::move(behavior)); } void Runtime::load(const Json& scene) { - require(!impl_->busy,"cannot load scene from gameplay callback"); - require(scene.is_object()&&scene.value("format",std::string{})=="faset.scene"&&scene.value("version",0)==1,"unsupported scene format/version"); - const int dimension=scene.value("dimension",3);require(dimension==2||dimension==3,"scene dimension must be 2 or 3"); - require(scene.contains("entities")&&scene["entities"].is_array(),"scene entities must be an array"); - require(!scene.contains("instances")||(scene["instances"].is_array()&&scene["instances"].empty()),"resolve template instances before runtime loading"); - std::unordered_map entities; - for(const auto& entity:scene["entities"]) {validateEntity(entity,dimension);require(entities.emplace(entity["id"].get(),entity).second,"duplicate scene entity id");} - for(const auto& [id,entity]:entities) { - std::set visited{id};auto parent=entity.value("parent",Json{}); - while(!parent.is_null()){auto key=parent.get();require(entities.contains(key),"unknown parent entity");require(visited.insert(key).second,"cyclic parent hierarchy");parent=entities.at(key).value("parent",Json{});} + require(!impl_->busy, "cannot load scene from gameplay callback"); + require(scene.is_object() && scene.value("format", std::string{}) == "faset.scene" && + scene.value("version", 0) == 1, + "unsupported scene format/version"); + const int dimension = scene.value("dimension", 3); + require(dimension == 2 || dimension == 3, "scene dimension must be 2 or 3"); + require(scene.contains("entities") && scene["entities"].is_array(), + "scene entities must be an array"); + require(!scene.contains("instances") || + (scene["instances"].is_array() && scene["instances"].empty()), + "resolve template instances before runtime loading"); + std::unordered_map entities; + for (const auto& entity : scene["entities"]) { + validateEntity(entity, dimension); + require(entities.emplace(entity["id"].get(), entity).second, + "duplicate scene entity id"); } - auto next=std::make_unique(this,impl_->config);next->dimension=dimension;next->behaviors=impl_->behaviors; - next->physics=std::make_unique(dimension,next->config.gravity,next->config.physicsSubsteps); - for(const auto& entity:scene["entities"])next->create(entity); - clear();impl_=std::move(next);impl_->busy=true;impl_->phase=Impl::Phase::Initialize;impl_->all(&Behavior::onStart,0);impl_->phase=Impl::Phase::Idle;impl_->busy=false; + for (const auto& [id, entity] : entities) { + std::set visited{id}; + auto parent = entity.value("parent", Json{}); + while (!parent.is_null()) { + auto key = parent.get(); + require(entities.contains(key), "unknown parent entity"); + require(visited.insert(key).second, "cyclic parent hierarchy"); + parent = entities.at(key).value("parent", Json{}); + } + } + auto next = std::make_unique(this, impl_->config); + next->dimension = dimension; + next->behaviors = impl_->behaviors; + next->physics = std::make_unique(dimension, next->config.gravity, + next->config.physicsSubsteps); + for (const auto& entity : scene["entities"]) + next->create(entity); + clear(); + impl_ = std::move(next); + impl_->busy = true; + impl_->phase = Impl::Phase::Initialize; + impl_->all(&Behavior::onStart, 0); + impl_->phase = Impl::Phase::Idle; + impl_->busy = false; } -void Runtime::clear(){require(!impl_->busy,"cannot clear runtime from gameplay callback");impl_->busy=true;while(!impl_->order.empty())impl_->erase(impl_->order.back());impl_->pending.clear();impl_->contacts.clear();impl_->physics.reset();impl_->accumulator=0;impl_->tick=0;impl_->session=nextSession.fetch_add(1);impl_->busy=false;} -FrameStats Runtime::advance(double dt,InputState input){return impl_->frame(dt,input,false);} -FrameStats Runtime::singleStep(InputState input){return impl_->frame(0,input,true);} -void Runtime::setPaused(bool value){require(!impl_->busy,"pause control belongs outside gameplay callbacks");impl_->paused=value;impl_->accumulator=0;impl_->queuedInput={};impl_->alpha=0;for(auto [e,pose]:impl_->registry.view().each()){(void)e;pose.previous=pose.presented=pose.current;}} -bool Runtime::paused()const noexcept{return impl_->paused;} -EntityHandle Runtime::find(const std::string& id)const{auto it=impl_->ids.find(id);return it==impl_->ids.end()?EntityHandle{}:impl_->handle(it->second);} -bool Runtime::valid(EntityHandle handle)const noexcept{return impl_->valid(handle);} -Transform Runtime::transform(EntityHandle h)const{return impl_->registry.get(impl_->entity(h)).current;} -Transform Runtime::presentation(EntityHandle h)const{return impl_->registry.get(impl_->entity(h)).presented;} -Json Runtime::fields(EntityHandle h,const std::string& type)const{auto c=impl_->component(impl_->entity(h),type);if(!c)throw std::invalid_argument("entity has no component: "+type);return (*c)["fields"];} -Vec3 Runtime::velocity(EntityHandle h)const{impl_->entity(h);if(!impl_->physics||!impl_->physics->contains(h.slot))throw std::invalid_argument("entity has no physics body");return impl_->physics->velocity(h.slot);} -InputState Runtime::input()const noexcept{return impl_->currentInput;} -const std::vector& Runtime::collisions()const noexcept{return impl_->contacts;} -void Runtime::setTransform(EntityHandle h,const Transform& value){validateTransform(value);auto e=impl_->entity(h);if(impl_->physics&&impl_->physics->contains(h.slot))throw std::invalid_argument("physics transform requires teleport");auto& d=impl_->registry.get(e);d.current=value;if(impl_->phase!=Impl::Phase::Fixed){d.previous=d.presented=value;d.changedInUpdate=true;}} -void Runtime::setPresentation(EntityHandle h,const Transform& value){validateTransform(value);require(impl_->phase==Impl::Phase::Late,"presentation may only be changed during LateUpdate");impl_->registry.get(impl_->entity(h)).presented=value;} -void Runtime::teleport(EntityHandle h,const Transform& value){validateTransform(value);auto e=impl_->entity(h);auto& d=impl_->registry.get(e);if(impl_->physics&&impl_->physics->contains(h.slot)){require(d.current.scale==value.scale,"changing collider scale requires remove/add body");if(impl_->dimension==2)require(value.rotation[0]==0&&value.rotation[1]==0,"2D physics rotates only around Z");impl_->physics->teleport(h.slot,value);}d.previous=d.current=d.presented=value;d.changedInUpdate=true;} -void Runtime::setVelocity(EntityHandle h,Vec3 value){impl_->entity(h);for(float v:value)require(std::isfinite(v),"nonfinite velocity");if(!impl_->physics||!impl_->physics->contains(h.slot))throw std::invalid_argument("entity has no physics body");impl_->physics->setVelocity(h.slot,value);} -void Runtime::applyImpulse(EntityHandle h,Vec3 value){impl_->entity(h);for(float v:value)require(std::isfinite(v),"nonfinite impulse");if(!impl_->physics||!impl_->physics->contains(h.slot))throw std::invalid_argument("entity has no physics body");impl_->physics->impulse(h.slot,value);} -void Runtime::spawn(Json entity){require(bool(impl_->physics),"load a scene before spawning");validateEntity(entity,impl_->dimension);impl_->pending.push_back({Impl::Kind::Spawn,{},std::move(entity),{}});} -void Runtime::destroy(EntityHandle h){impl_->entity(h);impl_->pending.push_back({Impl::Kind::Destroy,h,{},{}});} -void Runtime::addComponent(EntityHandle h,Json component){impl_->entity(h);impl_->pending.push_back({Impl::Kind::Add,h,std::move(component),{}});} -void Runtime::removeComponent(EntityHandle h,const std::string& type){impl_->entity(h);impl_->pending.push_back({Impl::Kind::Remove,h,{},type});} -RuntimeSnapshot Runtime::snapshot()const { - RuntimeSnapshot out{impl_->dimension,impl_->tick,impl_->alpha,{}};out.entities.reserve(impl_->order.size()); - for(auto e:impl_->order) {const auto& d=impl_->registry.get(e);RenderEntity item;item.id=d.document["id"].get();item.name=d.document.value("name",item.id);item.transform=impl_->registry.get(e).presented; - if(d.document.contains("parent")&&!d.document["parent"].is_null())item.parent=d.document["parent"].get(); - if(auto sprite=impl_->registry.try_get(e))item.sprite=*sprite; - if(auto mesh=impl_->registry.try_get(e))item.mesh=*mesh; +void Runtime::clear() { + require(!impl_->busy, "cannot clear runtime from gameplay callback"); + impl_->busy = true; + while (!impl_->order.empty()) + impl_->erase(impl_->order.back()); + impl_->pending.clear(); + impl_->contacts.clear(); + impl_->physics.reset(); + impl_->accumulator = 0; + impl_->tick = 0; + impl_->session = nextSession.fetch_add(1); + impl_->busy = false; +} +FrameStats Runtime::advance(double dt, InputState input) { + return impl_->frame(dt, input, false); +} +FrameStats Runtime::singleStep(InputState input) { + return impl_->frame(0, input, true); +} +void Runtime::setPaused(bool value) { + require(!impl_->busy, "pause control belongs outside gameplay callbacks"); + impl_->paused = value; + impl_->accumulator = 0; + impl_->queuedInput = {}; + impl_->alpha = 0; + for (auto [e, pose] : impl_->registry.view().each()) { + (void)e; + pose.previous = pose.presented = pose.current; + } +} +bool Runtime::paused() const noexcept { + return impl_->paused; +} +EntityHandle Runtime::find(const std::string& id) const { + auto it = impl_->ids.find(id); + return it == impl_->ids.end() ? EntityHandle{} : impl_->handle(it->second); +} +bool Runtime::valid(EntityHandle handle) const noexcept { + return impl_->valid(handle); +} +Transform Runtime::transform(EntityHandle h) const { + return impl_->registry.get(impl_->entity(h)).current; +} +Transform Runtime::presentation(EntityHandle h) const { + return impl_->registry.get(impl_->entity(h)).presented; +} +Json Runtime::fields(EntityHandle h, const std::string& type) const { + auto c = impl_->component(impl_->entity(h), type); + if (!c) + throw std::invalid_argument("entity has no component: " + type); + return (*c)["fields"]; +} +Vec3 Runtime::velocity(EntityHandle h) const { + impl_->entity(h); + if (!impl_->physics || !impl_->physics->contains(h.slot)) + throw std::invalid_argument("entity has no physics body"); + return impl_->physics->velocity(h.slot); +} +bool Runtime::grounded(EntityHandle h) const { + impl_->entity(h); + if (!impl_->physics || !impl_->physics->contains(h.slot)) + throw std::invalid_argument("entity has no physics body"); + return impl_->physics->grounded(h.slot); +} +InputState Runtime::input() const noexcept { + return impl_->currentInput; +} +const std::vector& Runtime::collisions() const noexcept { + return impl_->contacts; +} +void Runtime::setTransform(EntityHandle h, const Transform& value) { + validateTransform(value); + auto e = impl_->entity(h); + if (impl_->physics && impl_->physics->contains(h.slot)) + throw std::invalid_argument("physics transform requires teleport"); + auto& d = impl_->registry.get(e); + d.current = value; + if (impl_->phase != Impl::Phase::Fixed) { + d.previous = d.presented = value; + d.changedInUpdate = true; + } +} +void Runtime::setPresentation(EntityHandle h, const Transform& value) { + validateTransform(value); + require(impl_->phase == Impl::Phase::Late, + "presentation may only be changed during LateUpdate"); + impl_->registry.get(impl_->entity(h)).presented = value; +} +void Runtime::teleport(EntityHandle h, const Transform& value) { + validateTransform(value); + auto e = impl_->entity(h); + auto& d = impl_->registry.get(e); + if (impl_->physics && impl_->physics->contains(h.slot)) { + require(d.current.scale == value.scale, "changing collider scale requires remove/add body"); + if (impl_->dimension == 2) + require(value.rotation[0] == 0 && value.rotation[1] == 0, + "2D physics rotates only around Z"); + impl_->physics->teleport(h.slot, value); + } + d.previous = d.current = d.presented = value; + d.changedInUpdate = true; +} +void Runtime::setVelocity(EntityHandle h, Vec3 value) { + impl_->entity(h); + for (float v : value) + require(std::isfinite(v), "nonfinite velocity"); + if (!impl_->physics || !impl_->physics->contains(h.slot)) + throw std::invalid_argument("entity has no physics body"); + impl_->physics->setVelocity(h.slot, value); +} +void Runtime::applyImpulse(EntityHandle h, Vec3 value) { + impl_->entity(h); + for (float v : value) + require(std::isfinite(v), "nonfinite impulse"); + if (!impl_->physics || !impl_->physics->contains(h.slot)) + throw std::invalid_argument("entity has no physics body"); + impl_->physics->impulse(h.slot, value); +} +void Runtime::spawn(Json entity) { + require(bool(impl_->physics), "load a scene before spawning"); + validateEntity(entity, impl_->dimension); + impl_->pending.push_back({Impl::Kind::Spawn, {}, std::move(entity), {}}); +} +void Runtime::destroy(EntityHandle h) { + impl_->entity(h); + impl_->pending.push_back({Impl::Kind::Destroy, h, {}, {}}); +} +void Runtime::addComponent(EntityHandle h, Json component) { + impl_->entity(h); + impl_->pending.push_back({Impl::Kind::Add, h, std::move(component), {}}); +} +void Runtime::removeComponent(EntityHandle h, const std::string& type) { + impl_->entity(h); + impl_->pending.push_back({Impl::Kind::Remove, h, {}, type}); +} +RuntimeSnapshot Runtime::snapshot() const { + RuntimeSnapshot out{impl_->dimension, impl_->tick, impl_->alpha, {}}; + out.entities.reserve(impl_->order.size()); + for (auto e : impl_->order) { + const auto& d = impl_->registry.get(e); + RenderEntity item; + item.id = d.document["id"].get(); + item.name = d.document.value("name", item.id); + item.transform = impl_->registry.get(e).presented; + if (d.document.contains("parent") && !d.document["parent"].is_null()) + item.parent = d.document["parent"].get(); + if (auto sprite = impl_->registry.try_get(e)) + item.sprite = *sprite; + if (auto mesh = impl_->registry.try_get(e)) + item.mesh = *mesh; out.entities.push_back(std::move(item)); - }return out; + } + return out; } -Json Runtime::snapshotJson()const{auto value=snapshot();Json entities=Json::array();for(const auto& e:value.entities){Json item{{"id",e.id},{"name",e.name},{"parent",e.parent?Json(*e.parent):Json{}},{"transform",transformJson(e.transform)}};if(e.sprite)item["sprite"]={{"color",e.sprite->color},{"size",e.sprite->size},{"texture",e.sprite->texture},{"layer",e.sprite->layer}};if(e.mesh)item["mesh"]={{"asset",e.mesh->asset},{"color",e.mesh->color},{"primitive",e.mesh->primitive}};const auto entity=impl_->ids.at(e.id);for(const auto& type:{"faset.camera","faset.light"})if(auto c=impl_->component(entity,type))item[type==std::string("faset.camera")?"camera":"light"]=(*c)["fields"];entities.push_back(std::move(item));}return {{"dimension",value.dimension},{"tick",value.tick},{"alpha",value.alpha},{"entities",entities}};} -std::uint64_t Runtime::session()const noexcept{return impl_->session;} -const std::vector& Runtime::diagnostics()const noexcept{return impl_->diagnostics;} +Json Runtime::snapshotJson() const { + auto value = snapshot(); + Json entities = Json::array(); + for (const auto& e : value.entities) { + Json item{{"id", e.id}, + {"name", e.name}, + {"parent", e.parent ? Json(*e.parent) : Json{}}, + {"transform", transformJson(e.transform)}}; + if (e.sprite) + item["sprite"] = {{"color", e.sprite->color}, + {"size", e.sprite->size}, + {"texture", e.sprite->texture}, + {"layer", e.sprite->layer}}; + if (e.mesh) + item["mesh"] = {{"asset", e.mesh->asset}, + {"color", e.mesh->color}, + {"primitive", e.mesh->primitive}}; + const auto entity = impl_->ids.at(e.id); + for (const auto& type : {"faset.camera", "faset.light"}) + if (auto c = impl_->component(entity, type)) + item[type == std::string("faset.camera") ? "camera" : "light"] = (*c)["fields"]; + entities.push_back(std::move(item)); + } + return {{"dimension", value.dimension}, + {"tick", value.tick}, + {"alpha", value.alpha}, + {"entities", entities}}; } +std::uint64_t Runtime::session() const noexcept { + return impl_->session; +} +const std::vector& Runtime::diagnostics() const noexcept { + return impl_->diagnostics; +} +} // namespace faset::runtime diff --git a/src/ui/font.cpp b/src/ui/font.cpp new file mode 100644 index 0000000..e29f3f4 --- /dev/null +++ b/src/ui/font.cpp @@ -0,0 +1,171 @@ +#include +#include +#include FT_FREETYPE_H +#include +#include +#include +#include +#include +#include +#include + +namespace faset::ui { +namespace { +void quad(render::Snapshot& snapshot, render::Quad q, const Rect& clip) { + const Rect area{q.x, q.y, q.width, q.height}; + const auto visible = area.intersection(clip); + if (visible.width <= 0 || visible.height <= 0 || q.width <= 0 || q.height <= 0) + return; + const float u0 = q.uv_rect[0], v0 = q.uv_rect[1], du = q.uv_rect[2] - u0, + dv = q.uv_rect[3] - v0; + q.uv_rect = {u0 + (visible.x - q.x) / q.width * du, v0 + (visible.y - q.y) / q.height * dv, + u0 + (visible.x + visible.width - q.x) / q.width * du, + v0 + (visible.y + visible.height - q.y) / q.height * dv}; + q.x = visible.x; + q.y = visible.y; + q.width = visible.width; + q.height = visible.height; + snapshot.ui_quads.push_back(std::move(q)); +} +} // namespace +struct FontAtlas::Impl { + FT_Library library{}; + FT_Face face{}; + hb_font_t* font{}; + std::vector font_bytes; + std::shared_ptr atlas = std::make_shared(); + struct Glyph { + unsigned x, y, width, height; + int left, top; + }; + std::map, Glyph> glyphs; + unsigned x = 2, y = 2, row_height = 0, size = 0; + explicit Impl(const std::filesystem::path& path) { + std::ifstream in(path, std::ios::binary | std::ios::ate); + if (!in) + throw std::runtime_error("Cannot open UI font: " + path.string()); + auto length = in.tellg(); + if (length <= 0) + throw std::runtime_error("Empty UI font"); + font_bytes.resize(static_cast(length)); + in.seekg(0); + in.read(reinterpret_cast(font_bytes.data()), length); + if (!in) + throw std::runtime_error("Cannot read UI font"); + if (FT_Init_FreeType(&library)) + throw std::runtime_error("FreeType initialization failed"); + if (FT_New_Memory_Face(library, font_bytes.data(), static_cast(font_bytes.size()), + 0, &face)) { + FT_Done_FreeType(library); + library = nullptr; + throw std::runtime_error("Cannot load UI font face"); + } + font = hb_ft_font_create_referenced(face); + hb_ft_font_set_load_flags(font, FT_LOAD_DEFAULT); + atlas->width = atlas->height = 2048; + atlas->rgba.resize(2048 * 2048 * 4, 0); + atlas->revision = 1; + atlas->srgb = false; + } + ~Impl() { + if (font) + hb_font_destroy(font); + if (face) + FT_Done_Face(face); + if (library) + FT_Done_FreeType(library); + } + void set_size(float pixels) { + const auto wanted = static_cast(std::clamp(std::round(pixels), 6.f, 128.f)); + if (wanted != size) { + size = wanted; + if (FT_Set_Pixel_Sizes(face, 0, size)) + throw std::runtime_error("Invalid font size"); + hb_ft_font_changed(font); + } + } + Glyph glyph(unsigned index) { + const auto key = std::make_pair(size, index); + if (auto found = glyphs.find(key); found != glyphs.end()) + return found->second; + if (FT_Load_Glyph(face, index, FT_LOAD_DEFAULT) || + FT_Render_Glyph(face->glyph, FT_RENDER_MODE_NORMAL)) + throw std::runtime_error("Cannot rasterize UI glyph"); + const auto& bitmap = face->glyph->bitmap; + if (x + bitmap.width + 2 > atlas->width) { + x = 2; + y += row_height + 2; + row_height = 0; + } + if (y + bitmap.rows + 2 > atlas->height) + throw std::runtime_error("UI font atlas exhausted"); + Glyph result{ + x, y, bitmap.width, bitmap.rows, face->glyph->bitmap_left, face->glyph->bitmap_top}; + for (unsigned py = 0; py < bitmap.rows; ++py) { + const auto* row = bitmap.buffer + (bitmap.pitch >= 0 ? py : bitmap.rows - 1 - py) * + std::abs(bitmap.pitch); + for (unsigned px = 0; px < bitmap.width; ++px) { + const auto offset = ((y + py) * atlas->width + x + px) * 4; + atlas->rgba[offset] = atlas->rgba[offset + 1] = atlas->rgba[offset + 2] = 255; + atlas->rgba[offset + 3] = row[px]; + } + } + x += bitmap.width + 2; + row_height = std::max(row_height, bitmap.rows); + ++atlas->revision; + glyphs.emplace(key, result); + return result; + } + hb_buffer_t* shape(std::string_view text, float pixels) { + set_size(pixels); + auto* buffer = hb_buffer_create(); + hb_buffer_add_utf8(buffer, text.data(), static_cast(text.size()), 0, + static_cast(text.size())); + hb_buffer_guess_segment_properties(buffer); + hb_shape(font, buffer, nullptr, 0); + return buffer; + } +}; +FontAtlas::FontAtlas(const std::filesystem::path& path) : impl_(std::make_unique(path)) {} +FontAtlas::~FontAtlas() = default; +float FontAtlas::measure(std::string_view text, float pixels) { + auto* buffer = impl_->shape(text, pixels); + std::unique_ptr guard(buffer, &hb_buffer_destroy); + unsigned count = 0; + const auto* positions = hb_buffer_get_glyph_positions(buffer, &count); + float advance = 0; + for (unsigned i = 0; i < count; ++i) + advance += positions[i].x_advance / 64.f; + return advance; +} +void FontAtlas::draw(render::Snapshot& snapshot, std::string_view text, float x, float y, + float pixels, Color color, const Rect& clip) { + auto* buffer = impl_->shape(text, pixels); + std::unique_ptr guard(buffer, &hb_buffer_destroy); + unsigned count = 0; + const auto* infos = hb_buffer_get_glyph_infos(buffer, &count); + const auto* positions = hb_buffer_get_glyph_positions(buffer, &count); + const float baseline = y + impl_->face->size->metrics.ascender / 64.f; + for (unsigned i = 0; i < count; ++i) { + const auto glyph = impl_->glyph(infos[i].codepoint); + if (glyph.width && glyph.height) { + render::Quad q; + q.x = x + positions[i].x_offset / 64.f + glyph.left; + q.y = baseline - positions[i].y_offset / 64.f - glyph.top; + q.width = static_cast(glyph.width); + q.height = static_cast(glyph.height); + q.color = color; + q.texture = impl_->atlas; + q.uv_rect = {float(glyph.x) / impl_->atlas->width, + float(glyph.y) / impl_->atlas->height, + float(glyph.x + glyph.width) / impl_->atlas->width, + float(glyph.y + glyph.height) / impl_->atlas->height}; + quad(snapshot, std::move(q), clip); + } + x += positions[i].x_advance / 64.f; + } +} +std::shared_ptr FontAtlas::texture() const { + return impl_->atlas; +} +} // namespace faset::ui diff --git a/src/ui/text.cpp b/src/ui/text.cpp new file mode 100644 index 0000000..278949f --- /dev/null +++ b/src/ui/text.cpp @@ -0,0 +1,196 @@ +#include +#include +#include +#include + +namespace faset::ui { +namespace { +bool continuation(unsigned char c) { + return (c & 0xc0) == 0x80; +} +std::size_t previous(std::string_view text, std::size_t at) { + if (!at) + return 0; + --at; + while (at && continuation(static_cast(text[at]))) + --at; + return at; +} +std::size_t next(std::string_view text, std::size_t at) { + if (at >= text.size()) + return text.size(); + ++at; + while (at < text.size() && continuation(static_cast(text[at]))) + ++at; + return at; +} +bool word(unsigned char c) { + return c >= 128 || std::isalnum(c) || c == '_'; +} +} // namespace +bool TextBuffer::valid_utf8(std::string_view text) { + for (std::size_t i = 0; i < text.size();) { + const auto lead = static_cast(text[i++]); + if (lead < 128) + continue; + unsigned cp = 0; + int n = 0; + unsigned minimum = 0; + if ((lead & 0xe0) == 0xc0) { + cp = lead & 31; + n = 1; + minimum = 128; + } else if ((lead & 0xf0) == 0xe0) { + cp = lead & 15; + n = 2; + minimum = 2048; + } else if ((lead & 0xf8) == 0xf0) { + cp = lead & 7; + n = 3; + minimum = 65536; + } else + return false; + if (i + static_cast(n) > text.size()) + return false; + while (n--) { + auto c = static_cast(text[i++]); + if (!continuation(c)) + return false; + cp = (cp << 6) | (c & 63); + } + if (cp < minimum || cp > 0x10ffff || (cp >= 0xd800 && cp <= 0xdfff)) + return false; + } + return true; +} +TextBuffer::TextBuffer(std::string text) { + reset(std::move(text)); +} +void TextBuffer::reset(std::string text) { + if (!valid_utf8(text)) + throw std::invalid_argument("Invalid UTF-8 text"); + text_ = std::move(text); + cursor_ = anchor_ = text_.size(); + undo_.clear(); + redo_.clear(); +} +void TextBuffer::set_cursor(std::size_t byte, bool select) { + cursor_ = std::min(byte, text_.size()); + while (cursor_ && cursor_ < text_.size() && + continuation(static_cast(text_[cursor_]))) + --cursor_; + if (!select) + anchor_ = cursor_; +} +void TextBuffer::select_all() { + anchor_ = 0; + cursor_ = text_.size(); +} +std::string TextBuffer::selected_text() const { + return text_.substr(std::min(cursor_, anchor_), + std::max(cursor_, anchor_) - std::min(cursor_, anchor_)); +} +void TextBuffer::left(bool select, bool by_word) { + if (!select && has_selection()) { + set_cursor(std::min(cursor_, anchor_)); + return; + } + auto position = previous(text_, cursor_); + if (by_word) { + while (position && !word(static_cast(text_[position]))) + position = previous(text_, position); + while (position && word(static_cast(text_[previous(text_, position)]))) + position = previous(text_, position); + } + set_cursor(position, select); +} +void TextBuffer::right(bool select, bool by_word) { + if (!select && has_selection()) { + set_cursor(std::max(cursor_, anchor_)); + return; + } + auto position = next(text_, cursor_); + if (by_word) { + while (position < text_.size() && word(static_cast(text_[position]))) + position = next(text_, position); + while (position < text_.size() && !word(static_cast(text_[position]))) + position = next(text_, position); + } + set_cursor(position, select); +} +void TextBuffer::home(bool select) { + set_cursor(0, select); +} +void TextBuffer::end(bool select) { + set_cursor(text_.size(), select); +} +void TextBuffer::remember() { + undo_.push_back({text_, cursor_, anchor_}); + if (undo_.size() > 256) + undo_.erase(undo_.begin()); + redo_.clear(); +} +void TextBuffer::erase_selection() { + const auto begin = std::min(cursor_, anchor_), end = std::max(cursor_, anchor_); + text_.erase(begin, end - begin); + cursor_ = anchor_ = begin; +} +bool TextBuffer::insert(std::string_view utf8) { + if (!valid_utf8(utf8) || text_.size() + utf8.size() > 1024 * 1024) + return false; + if (utf8.empty() && !has_selection()) + return false; + remember(); + erase_selection(); + text_.insert(cursor_, utf8); + cursor_ += utf8.size(); + anchor_ = cursor_; + return true; +} +bool TextBuffer::backspace() { + if (!has_selection() && !cursor_) + return false; + remember(); + if (has_selection()) + erase_selection(); + else { + auto begin = previous(text_, cursor_); + text_.erase(begin, cursor_ - begin); + cursor_ = anchor_ = begin; + } + return true; +} +bool TextBuffer::delete_forward() { + if (!has_selection() && cursor_ == text_.size()) + return false; + remember(); + if (has_selection()) + erase_selection(); + else + text_.erase(cursor_, next(text_, cursor_) - cursor_); + anchor_ = cursor_; + return true; +} +bool TextBuffer::undo() { + if (undo_.empty()) + return false; + redo_.push_back({text_, cursor_, anchor_}); + auto old = std::move(undo_.back()); + undo_.pop_back(); + text_ = std::move(old.text); + cursor_ = old.cursor; + anchor_ = old.anchor; + return true; +} +bool TextBuffer::redo() { + if (redo_.empty()) + return false; + undo_.push_back({text_, cursor_, anchor_}); + auto old = std::move(redo_.back()); + redo_.pop_back(); + text_ = std::move(old.text); + cursor_ = old.cursor; + anchor_ = old.anchor; + return true; +} +} // namespace faset::ui diff --git a/src/ui/ui.cpp b/src/ui/ui.cpp new file mode 100644 index 0000000..ff57c77 --- /dev/null +++ b/src/ui/ui.cpp @@ -0,0 +1,1149 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +namespace faset::ui { +bool Rect::contains(float px, float py) const noexcept { + return px >= x && py >= y && px < x + width && py < y + height; +} +Rect Rect::intersection(const Rect& b) const noexcept { + const auto left = std::max(x, b.x), top = std::max(y, b.y); + return {left, top, std::max(0.f, std::min(x + width, b.x + b.width) - left), + std::max(0.f, std::min(y + height, b.y + b.height) - top)}; +} +namespace { +Color color(const Json& j, const char* key, Color fallback) { + if (!j.contains(key)) + return fallback; + auto value = j.at(key).get(); + for (float c : value) + if (!std::isfinite(c) || c < 0 || c > 1) + throw std::runtime_error("Theme colors require normalized RGBA"); + return value; +} +float positive(const Json& j, const char* key, float fallback) { + float value = j.value(key, fallback); + if (!std::isfinite(value) || value <= 0 || value > 256) + throw std::runtime_error("Invalid theme metric"); + return value; +} +std::string number(double value, int precision) { + std::ostringstream out; + out << std::fixed << std::setprecision(std::clamp(precision, 0, 9)) << value; + return out.str(); +} +bool field(const Widget& w) { + return w.kind == Kind::TextField || w.kind == Kind::NumberField; +} +bool focusable(const Widget& w) { + for (auto* parent = w.parent; parent; parent = parent->parent) + if (!parent->visible || !parent->enabled) + return false; + return w.visible && w.enabled && + (field(w) || w.kind == Kind::Button || w.kind == Kind::Checkbox || w.kind == Kind::Tab || + w.kind == Kind::TreeRow); +} +void collect_focus(Widget& w, std::vector& ids) { + if (!w.visible) + return; + if (focusable(w)) + ids.push_back(w.id); + for (auto& child : w.children) + collect_focus(*child, ids); +} +void fill(render::Snapshot& frame, Rect rect, Color color, const Rect& clip) { + rect = rect.intersection(clip); + if (rect.width > 0 && rect.height > 0) + frame.ui_quads.push_back( + {rect.x, rect.y, rect.width, rect.height, color, {}, {0, 0, 1, 1}}); +} +void outline(render::Snapshot& f, const Rect& r, Color c, const Rect& clip, float thickness = 1) { + fill(f, {r.x, r.y, r.width, thickness}, c, clip); + fill(f, {r.x, r.y + r.height - thickness, r.width, thickness}, c, clip); + fill(f, {r.x, r.y, thickness, r.height}, c, clip); + fill(f, {r.x + r.width - thickness, r.y, thickness, r.height}, c, clip); +} +Kind kind_from_string(const std::string& name) { + static const std::unordered_map kinds = {{"panel", Kind::Panel}, + {"row", Kind::Row}, + {"column", Kind::Column}, + {"label", Kind::Label}, + {"button", Kind::Button}, + {"tab", Kind::Tab}, + {"tree_row", Kind::TreeRow}, + {"text_field", Kind::TextField}, + {"number_field", Kind::NumberField}, + {"checkbox", Kind::Checkbox}, + {"divider", Kind::Divider}, + {"viewport", Kind::Viewport}}; + auto found = kinds.find(name); + if (found == kinds.end()) + throw std::runtime_error("Unknown widget kind: " + name); + return found->second; +} +Layout parse_layout(const Json& j, Layout l = {}) { + if (!j.is_object()) + throw std::runtime_error("Layout must be an object"); +#define UI_FLOAT(name) \ + l.name = j.value(#name, l.name); \ + if (!std::isfinite(l.name)) \ + throw std::runtime_error("Non-finite layout metric: " #name) + UI_FLOAT(width); + UI_FLOAT(height); + UI_FLOAT(flex); + UI_FLOAT(min_width); + UI_FLOAT(min_height); + UI_FLOAT(max_width); + UI_FLOAT(max_height); + UI_FLOAT(padding); + UI_FLOAT(gap); + UI_FLOAT(x); + UI_FLOAT(y); +#undef UI_FLOAT + l.absolute = j.value("absolute", l.absolute); + l.scroll = j.value("scroll", l.scroll); + l.clip = j.value("clip", l.clip); + if (l.flex < 0 || l.padding < 0 || l.gap < 0 || l.min_width < 0 || l.min_height < 0 || + l.max_width < l.min_width || l.max_height < l.min_height) + throw std::runtime_error("Invalid layout constraints"); + return l; +} +} // namespace +Theme Theme::from_json(const Json& j) { + Theme t; +#define UI_COLOR(name) t.name = color(j, #name, t.name) + UI_COLOR(background); + UI_COLOR(surface); + UI_COLOR(raised); + UI_COLOR(hover); + UI_COLOR(border); + UI_COLOR(text); + UI_COLOR(muted); + UI_COLOR(accent); + UI_COLOR(selection); + UI_COLOR(danger); +#undef UI_COLOR + t.font_size = positive(j, "font_size", t.font_size); + t.row_height = positive(j, "row_height", t.row_height); + t.padding = positive(j, "padding", t.padding); + t.gap = positive(j, "gap", t.gap); + return t; +} +Theme Theme::load(const std::filesystem::path& path) { + return from_json(faset::read_json(path)); +} +Json Theme::to_json() const { + return {{"background", background}, {"surface", surface}, + {"raised", raised}, {"hover", hover}, + {"border", border}, {"text", text}, + {"muted", muted}, {"accent", accent}, + {"selection", selection}, {"danger", danger}, + {"font_size", font_size}, {"row_height", row_height}, + {"padding", padding}, {"gap", gap}}; +} +Widget& Widget::add(Kind type, const std::string& stable_id, const std::string& label) { + for (auto& child : children) + if (child->id == stable_id) { + if (child->kind != type) + throw std::runtime_error("Widget ID reused with different kind: " + stable_id); + if (!label.empty()) + child->text = label; + return *child; + } + auto child = std::make_unique(); + child->kind = type; + child->id = stable_id; + child->text = label; + child->parent = this; + children.push_back(std::move(child)); + return *children.back(); +} +Widget* Widget::find(std::string_view wanted) { + if (id == wanted) + return this; + for (auto& child : children) + if (auto* result = child->find(wanted)) + return result; + return nullptr; +} +const Widget* Widget::find(std::string_view wanted) const { + if (id == wanted) + return this; + for (const auto& child : children) + if (auto* result = child->find(wanted)) + return result; + return nullptr; +} +void Widget::remove(std::string_view wanted) { + std::erase_if(children, [&](const auto& child) { return child->id == wanted; }); +} +void DockLayout::move(const std::string& panel, const std::string& area, std::size_t index) { + if (panel.empty() || area.empty()) + throw std::runtime_error("Dock IDs cannot be empty"); + for (auto& [name, panels] : areas_) { + (void)name; + std::erase(panels, panel); + } + auto& panels = areas_[area]; + panels.insert(panels.begin() + static_cast(std::min(index, panels.size())), + panel); +} +std::vector DockLayout::panels(const std::string& area) const { + auto found = areas_.find(area); + return found == areas_.end() ? std::vector{} : found->second; +} +void DockLayout::set_size(const std::string& panel, float size) { + if (!std::isfinite(size) || size < 24 || size > 10000) + throw std::runtime_error("Invalid dock panel size"); + sizes_[panel] = size; +} +float DockLayout::size(const std::string& panel, float fallback) const { + auto found = sizes_.find(panel); + return found == sizes_.end() ? fallback : found->second; +} +Json DockLayout::to_json() const { + return {{"version", 1}, {"areas", areas_}, {"sizes", sizes_}}; +} +void DockLayout::from_json(const Json& j) { + if (j.at("version") != 1) + throw std::runtime_error("Unsupported dock layout version"); + auto areas = j.at("areas").get(); + auto sizes = j.at("sizes").get(); + std::set seen; + for (const auto& [area, panels] : areas) { + if (area.empty()) + throw std::runtime_error("Empty dock area"); + for (const auto& panel : panels) + if (panel.empty() || !seen.insert(panel).second) + throw std::runtime_error("Duplicate dock panel"); + } + for (const auto& [id, size] : sizes) + if (id.empty() || !std::isfinite(size) || size < 24 || size > 10000) + throw std::runtime_error("Invalid dock size"); + areas_ = std::move(areas); + sizes_ = std::move(sizes); +} +void DockLayout::save(const std::filesystem::path& path) const { + faset::atomic_write_json(path, to_json()); +} +void DockLayout::load(const std::filesystem::path& path) { + from_json(faset::read_json(path)); +} + +struct Context::Impl { + Widget root; + Theme theme; + FontAtlas font; + float width = 0, height = 0, scale = 1, mouse_x = 0, mouse_y = 0; + std::string focused, hovered, captured; + struct Edit { + TextBuffer buffer; + std::string original, composition; + double original_value = 0; + float scroll = 0; + int composition_start = 0, composition_length = 0; + }; + std::unordered_map edits; + float down_x = 0, down_y = 0; + double down_value = 0; + bool dragging = false; + Json payload; + float before_size = 0, after_size = 0; + Layout before_layout, after_layout; + std::function clipboard_read; + std::function clipboard_write; + std::function ime_enabled; + std::function ime_rectangle; + DockLayout* docking = nullptr; + std::function docking_changed; + explicit Impl(const std::filesystem::path& file) : font(file) { + root.kind = Kind::Column; + root.id = "root"; + root.layout.gap = 0; + } + Widget* find(std::string_view id) { + return root.find(id); + } + float intrinsic(Widget& w, bool horizontal) { + const auto fixed = horizontal ? w.layout.width : w.layout.height; + if (fixed >= 0) + return fixed * scale; + if (w.kind == Kind::Divider) + return 5 * scale; + if (horizontal) { + if (w.kind == Kind::Label || w.kind == Kind::Button || w.kind == Kind::Tab) + return font.measure(w.text, theme.font_size * scale) + theme.padding * 2 * scale; + return 80 * scale; + } + if (w.kind == Kind::Panel || w.kind == Kind::Column || w.kind == Kind::Row) { + float total = 0; + std::size_t count = 0; + for (auto& child : w.children) + if (child->visible && !child->layout.absolute) { + const auto value = intrinsic(*child, false); + if (w.kind == Kind::Row) + total = std::max(total, value); + else + total += value; + ++count; + } + if (w.kind != Kind::Row && count) + total += float(count - 1) * w.layout.gap * scale; + return total + w.layout.padding * 2 * scale; + } + return theme.row_height * scale; + } + void arrange(Widget& w, Rect rect, Rect clip) { + w.rect = rect; + w.clip = w.layout.clip ? clip.intersection(rect) : clip; + if (!w.visible) + return; + const auto pad = w.layout.padding * scale; + Rect inner{rect.x + pad, rect.y + pad, std::max(0.f, rect.width - 2 * pad), + std::max(0.f, rect.height - 2 * pad)}; + const bool horizontal = w.kind == Kind::Row; + const float available = horizontal ? inner.width : inner.height; + std::vector flow; + float fixed = 0, flex = 0; + for (auto& child : w.children) + if (child->visible && !child->layout.absolute) { + flow.push_back(child.get()); + if (child->layout.flex > 0) { + flex += child->layout.flex; + fixed += + (horizontal ? child->layout.min_width : child->layout.min_height) * scale; + } else + fixed += intrinsic(*child, horizontal); + } + if (!flow.empty()) + fixed += float(flow.size() - 1) * w.layout.gap * scale; + const auto extra = std::max(0.f, available - fixed); + std::vector extents; + float content = 0; + for (auto* child : flow) { + auto extent = + child->layout.flex > 0 + ? (horizontal ? child->layout.min_width : child->layout.min_height) * scale + + extra * child->layout.flex / std::max(.001f, flex) + : intrinsic(*child, horizontal); + extent = std::clamp( + extent, (horizontal ? child->layout.min_width : child->layout.min_height) * scale, + (horizontal ? child->layout.max_width : child->layout.max_height) * scale); + extents.push_back(extent); + content += extent; + } + if (!flow.empty()) + content += float(flow.size() - 1) * w.layout.gap * scale; + w.content_height = horizontal ? inner.height : content; + w.scroll_y = std::clamp(w.scroll_y, 0.f, std::max(0.f, w.content_height - inner.height)); + float position = horizontal ? inner.x : inner.y - (w.layout.scroll ? w.scroll_y : 0); + for (std::size_t i = 0; i < flow.size(); ++i) { + auto& child = *flow[i]; + float cross = + horizontal ? (child.layout.height >= 0 ? child.layout.height * scale : inner.height) + : (child.layout.width >= 0 ? child.layout.width * scale : inner.width); + cross = std::clamp( + cross, (horizontal ? child.layout.min_height : child.layout.min_width) * scale, + (horizontal ? child.layout.max_height : child.layout.max_width) * scale); + Rect target = horizontal ? Rect{position, inner.y, extents[i], cross} + : Rect{inner.x, position, cross, extents[i]}; + arrange(child, target, w.clip.intersection(inner)); + position += extents[i] + w.layout.gap * scale; + } + for (auto& child : w.children) + if (child->visible && child->layout.absolute) + arrange(*child, + {inner.x + child->layout.x * scale, inner.y + child->layout.y * scale, + child->layout.width >= 0 ? child->layout.width * scale : inner.width, + child->layout.height >= 0 ? child->layout.height * scale + : intrinsic(*child, false)}, + w.clip.intersection(inner)); + } + Widget* hit(Widget& w, float x, float y) { + if (!w.visible || !w.clip.contains(x, y)) + return nullptr; + for (auto child = w.children.rbegin(); child != w.children.rend(); ++child) + if (auto* target = hit(**child, x, y)) + return target; + return w.rect.contains(x, y) ? &w : nullptr; + } + bool commit() { + if (focused.empty()) + return true; + auto* widget = find(focused); + auto found = edits.find(focused); + if (!widget || !field(*widget) || found == edits.end()) + return true; + auto& edit = found->second; + if (!edit.composition.empty()) + return false; + const bool changed = edit.buffer.text() != edit.original; + if (widget->kind == Kind::NumberField) { + try { + std::size_t end = 0; + const auto value = std::stod(edit.buffer.text(), &end); + if (end != edit.buffer.text().size() || !std::isfinite(value)) + throw std::runtime_error("number"); + widget->value = value; + } catch (...) { + widget->error = "Enter a finite number"; + return false; + } + } + widget->error.clear(); + widget->text = edit.buffer.text(); + edit.original = edit.buffer.text(); + edit.original_value = widget->value; + const auto cursor = edit.buffer.cursor(); + edit.buffer.reset(edit.original); + edit.buffer.set_cursor(cursor); + auto callback = widget->on_commit; + if (changed && callback) + callback(*widget); + return true; + } + void unfocus(bool save) { + if (save && !commit()) + return; + focused.clear(); + if (ime_enabled) + ime_enabled(false); + } + bool focus(const std::string& id) { + auto* widget = find(id); + if (!widget || !focusable(*widget)) + return false; + if (focused == id) + return true; + if (!commit()) + return false; + focused = id; + if (field(*widget)) { + auto& edit = edits[id]; + const auto text = widget->kind == Kind::NumberField + ? number(widget->value, widget->precision) + : widget->text; + edit.buffer.reset(text); + edit.original = text; + edit.original_value = widget->value; + edit.composition.clear(); + edit.scroll = 0; + if (widget->kind == Kind::NumberField) + edit.buffer.select_all(); + if (ime_enabled) + ime_enabled(true); + if (ime_rectangle) + ime_rectangle(widget->rect); + } else if (ime_enabled) + ime_enabled(false); + return true; + } + void preview() { + auto* widget = find(focused); + auto found = edits.find(focused); + if (!widget || found == edits.end()) + return; + widget->text = found->second.buffer.text(); + widget->error.clear(); + auto callback = widget->on_preview; + if (callback) + callback(*widget); + } + std::size_t text_position(const Widget& w, const Edit& e, float x) { + const auto local = x - w.rect.x - theme.padding * scale + e.scroll; + float previous_width = 0; + std::size_t previous_byte = 0; + for (std::size_t i = 0; i < e.buffer.text().size();) { + ++i; + while (i < e.buffer.text().size() && + (static_cast(e.buffer.text()[i]) & 0xc0) == 0x80) + ++i; + const auto width = font.measure(std::string_view(e.buffer.text()).substr(0, i), + theme.font_size * scale); + if (local < (previous_width + width) * .5f) + return previous_byte; + previous_width = width; + previous_byte = i; + } + return e.buffer.text().size(); + } + std::pair neighbors(Widget& divider) { + if (!divider.parent) + return {}; + auto& list = divider.parent->children; + for (std::size_t i = 1; i + 1 < list.size(); ++i) + if (list[i].get() == ÷r) + return {list[i - 1].get(), list[i + 1].get()}; + return {}; + } + void cancel_capture() { + if (auto* w = find(captured); w && w->kind == Kind::NumberField && dragging) { + w->value = down_value; + auto& edit = edits[w->id]; + edit.buffer.reset(number(w->value, w->precision)); + w->text = edit.buffer.text(); + auto callback = w->on_preview; + if (callback) + callback(*w); + } + if (auto* w = find(captured); w && w->kind == Kind::Divider && dragging) { + auto [before, after] = neighbors(*w); + if (before && after) { + before->layout = before_layout; + after->layout = after_layout; + arrange(root, {0, 0, width, height}, {0, 0, width, height}); + } + } + if (auto* w = find(captured); w && dragging) { + auto callback = w->on_cancel; + if (callback) + callback(*w); + } + captured.clear(); + payload = nullptr; + dragging = false; + } + void draw_widget(Widget& w, render::Snapshot& frame) { + if (!w.visible || w.clip.width <= 0 || w.clip.height <= 0) + return; + const bool hover = w.id == hovered, focus = w.id == focused; + auto ink = w.enabled ? theme.text : theme.muted; + const auto& rect = w.rect; + if (w.kind == Kind::Panel) { + fill(frame, rect, theme.surface, w.clip); + outline(frame, rect, theme.border, w.clip); + } else if (w.kind == Kind::Button) { + fill(frame, rect, hover && w.enabled ? theme.hover : theme.raised, w.clip); + outline(frame, rect, focus ? theme.accent : theme.border, w.clip); + } else if (w.kind == Kind::Tab || w.kind == Kind::TreeRow) { + if (w.selected || hover) + fill(frame, rect, w.selected ? theme.selection : theme.hover, w.clip); + if (w.selected) { + if (w.kind == Kind::Tab) + fill(frame, {rect.x, rect.y + rect.height - 2 * scale, rect.width, 2 * scale}, + theme.accent, w.clip); + else + fill(frame, {rect.x, rect.y, 2 * scale, rect.height}, theme.accent, w.clip); + } + if (focus) + outline(frame, rect, theme.accent, w.clip); + } else if (field(w)) { + fill(frame, rect, theme.background, w.clip); + outline(frame, rect, + !w.error.empty() ? theme.danger + : focus ? theme.accent + : theme.border, + w.clip); + } else if (w.kind == Kind::Divider) { + fill(frame, rect, hover || w.id == captured ? theme.accent : theme.background, w.clip); + } + float tx = rect.x + theme.padding * scale + w.indent * 14 * scale; + const auto font_size = theme.font_size * scale; + const auto ty = rect.y + std::max(0.f, (rect.height - font_size * 1.45f) * .5f); + if (w.kind == Kind::Checkbox) { + Rect box{tx, rect.y + (rect.height - 14 * scale) / 2, 14 * scale, 14 * scale}; + fill(frame, box, theme.background, w.clip); + outline(frame, box, focus ? theme.accent : theme.border, w.clip); + if (w.checked) + fill(frame, {box.x + 3 * scale, box.y + 3 * scale, 8 * scale, 8 * scale}, + theme.accent, w.clip); + tx += 23 * scale; + } + if (field(w) && focus && edits.contains(w.id)) { + auto& edit = edits[w.id]; + const auto available = std::max(1.f, rect.width - theme.padding * 2 * scale); + const auto selection_begin = std::min(edit.buffer.cursor(), edit.buffer.anchor()); + const auto selection_end = std::max(edit.buffer.cursor(), edit.buffer.anchor()); + auto composition_byte = [&](int codepoints) { + std::size_t byte = 0; + for (int i = 0; i < std::max(0, codepoints) && byte < edit.composition.size(); + ++i) { + ++byte; + while (byte < edit.composition.size() && + (static_cast(edit.composition[byte]) & 0xc0) == 0x80) + ++byte; + } + return byte; + }; + const auto prefix = edit.buffer.text().substr(0, selection_begin); + const auto composition_left = font.measure(prefix, font_size); + const auto composition_cursor = composition_byte(edit.composition_start); + const auto caret = + edit.composition.empty() + ? font.measure( + std::string_view(edit.buffer.text()).substr(0, edit.buffer.cursor()), + font_size) + : composition_left + + font.measure( + std::string_view(edit.composition).substr(0, composition_cursor), + font_size); + if (caret - edit.scroll > available - 2 * scale) + edit.scroll = caret - available + 2 * scale; + if (caret < edit.scroll) + edit.scroll = caret; + edit.scroll = std::max(0.f, edit.scroll); + const Rect text_clip = + w.clip.intersection({rect.x + 3 * scale, rect.y + 2 * scale, rect.width - 6 * scale, + rect.height - 4 * scale}); + tx -= edit.scroll; + if (edit.buffer.has_selection() && edit.composition.empty()) { + const auto begin = std::min(edit.buffer.cursor(), edit.buffer.anchor()), + end = std::max(edit.buffer.cursor(), edit.buffer.anchor()); + const auto left = font.measure( + std::string_view(edit.buffer.text()).substr(0, begin), font_size), + right = font.measure(std::string_view(edit.buffer.text()).substr(0, end), + font_size); + fill(frame, {tx + left, rect.y + 4 * scale, right - left, rect.height - 8 * scale}, + theme.selection, text_clip); + } + if (edit.composition.empty()) { + font.draw(frame, edit.buffer.text(), tx, ty, font_size, ink, text_clip); + } else { + const auto composition_width = font.measure(edit.composition, font_size); + const auto selection_width = font.measure( + std::string_view(edit.composition) + .substr(composition_cursor, + composition_byte(edit.composition_start + + std::max(0, edit.composition_length)) - + composition_cursor), + font_size); + if (selection_width > 0) + fill(frame, + {tx + caret, rect.y + 4 * scale, selection_width, rect.height - 8 * scale}, + theme.selection, text_clip); + font.draw(frame, prefix, tx, ty, font_size, ink, text_clip); + font.draw(frame, edit.composition, tx + composition_left, ty, font_size, + theme.accent, text_clip); + font.draw(frame, std::string_view(edit.buffer.text()).substr(selection_end), + tx + composition_left + composition_width, ty, font_size, ink, text_clip); + fill(frame, + {tx + composition_left, rect.y + rect.height - 4 * scale, composition_width, + scale}, + theme.accent, text_clip); + } + fill(frame, {tx + caret, rect.y + 5 * scale, scale, rect.height - 10 * scale}, + theme.accent, text_clip); + } else if (w.kind != Kind::Divider && w.kind != Kind::Viewport && !w.text.empty()) + font.draw(frame, w.kind == Kind::NumberField ? number(w.value, w.precision) : w.text, + tx, ty, font_size, ink, + w.clip.intersection( + {rect.x + 2 * scale, rect.y, rect.width - 4 * scale, rect.height})); + else if (w.kind == Kind::NumberField) + font.draw(frame, number(w.value, w.precision), tx, ty, font_size, ink, w.clip); + for (auto& child : w.children) + draw_widget(*child, frame); + if (w.layout.scroll && w.content_height > rect.height) { + const float track = rect.height - 8 * scale, + thumb = std::max(16 * scale, track * rect.height / w.content_height), + offset = (track - thumb) * w.scroll_y / + std::max(1.f, w.content_height - rect.height); + fill(frame, + {rect.x + rect.width - 5 * scale, rect.y + 4 * scale + offset, 3 * scale, thumb}, + theme.border, w.clip); + } + } +}; + +Context::Context(const std::filesystem::path& font) : impl_(std::make_unique(font)) {} +Context::~Context() = default; +Widget& Context::root() { + return impl_->root; +} +Widget* Context::find(std::string_view id) { + return impl_->find(id); +} +void Context::set_theme(Theme theme) { + impl_->theme = theme; +} +const Theme& Context::theme() const { + return impl_->theme; +} +FontAtlas& Context::font() { + return impl_->font; +} +void Context::apply_layout(const Json& document) { + const auto& definition = document.contains("root") ? document.at("root") : document; + std::set ids; + std::function validate = [&](const Json& j) { + const auto id = j.at("id").get(); + if (id.empty() || !ids.insert(id).second) + throw std::runtime_error("Duplicate layout widget ID"); + if (j.contains("kind")) { + const auto type = kind_from_string(j.at("kind")); + if (auto* existing = find(id); existing && existing->kind != type) + throw std::runtime_error("Hot layout cannot replace widget kind"); + } + if (j.contains("layout")) + parse_layout(j.at("layout")); + if (j.contains("children")) + for (const auto& child : j.at("children")) + validate(child); + }; + validate(definition); + std::function apply = [&](Widget& w, const Json& j) { + if (j.contains("text")) + update_text(w.id, j.at("text")); + if (j.contains("layout")) + w.layout = parse_layout(j.at("layout"), w.layout); + if (j.contains("children")) + for (const auto& child : j.at("children")) { + const auto id = child.at("id").get(); + auto& target = + w.add(child.contains("kind") ? kind_from_string(child.at("kind")) + : (w.find(id) ? w.find(id)->kind : Kind::Panel), + id); + apply(target, child); + } + }; + if (definition.at("id") != root().id) + throw std::runtime_error("Layout root ID must match retained root"); + apply(root(), definition); +} +void Context::layout(float width, float height, float scale) { + impl_->width = std::max(0.f, width); + impl_->height = std::max(0.f, height); + impl_->scale = std::clamp(scale, .5f, 4.f); + std::set ids; + std::function check = [&](Widget& w) { + if (w.id.empty() || !ids.insert(w.id).second) + throw std::runtime_error("Retained widget IDs must be unique"); + for (auto& child : w.children) { + child->parent = &w; + check(*child); + } + }; + check(root()); + impl_->arrange(root(), {0, 0, impl_->width, impl_->height}, + {0, 0, impl_->width, impl_->height}); + std::erase_if(impl_->edits, [&](const auto& entry) { return !ids.contains(entry.first); }); + auto* focused = impl_->find(impl_->focused); + if (!focused || !focusable(*focused)) + impl_->unfocus(false); + else if (field(*focused) && impl_->ime_rectangle) + impl_->ime_rectangle(focused->rect); +} +void Context::draw(render::Snapshot& snapshot) { + impl_->draw_widget(root(), snapshot); + if (!impl_->payload.is_null()) { + const Rect viewport{0, 0, impl_->width, impl_->height}; + const auto text = + impl_->payload.value("label", impl_->payload.value("panel", std::string("Move"))); + const auto width = + impl_->font.measure(text, impl_->theme.font_size * impl_->scale) + 20 * impl_->scale; + const Rect rect{impl_->mouse_x + 12 * impl_->scale, impl_->mouse_y + 12 * impl_->scale, + width, 28 * impl_->scale}; + fill(snapshot, rect, impl_->theme.raised, viewport); + outline(snapshot, rect, impl_->theme.accent, viewport); + impl_->font.draw(snapshot, text, rect.x + 8 * impl_->scale, rect.y + 3 * impl_->scale, + impl_->theme.font_size * impl_->scale, impl_->theme.text, viewport); + } +} +bool Context::update_text(const std::string& id, const std::string& value, bool force) { + auto* w = find(id); + if (!w) + return false; + if (!TextBuffer::valid_utf8(value)) + return false; + if (impl_->focused == id && impl_->edits.contains(id)) { + auto& edit = impl_->edits[id]; + if (!force && (edit.buffer.text() != edit.original || !edit.composition.empty())) + return false; + const auto cursor = edit.buffer.cursor(); + edit.buffer.reset(value); + edit.buffer.set_cursor(cursor); + edit.original = value; + edit.composition.clear(); + } + w->text = value; + return true; +} +bool Context::update_number(const std::string& id, double value, bool force) { + auto* widget = find(id); + if (!widget || widget->kind != Kind::NumberField || !std::isfinite(value)) + return false; + if (!update_text(id, number(value, widget->precision), force)) + return false; + widget->value = value; + if (impl_->focused == id && impl_->edits.contains(id)) + impl_->edits[id].original_value = value; + return true; +} +bool Context::focus(const std::string& id) { + return impl_->focus(id); +} +const std::string& Context::focused_id() const { + return impl_->focused; +} +void Context::clear_focus(bool commit) { + impl_->unfocus(commit); +} +bool Context::editing() const { + const auto* w = impl_->find(impl_->focused); + return w && field(*w); +} +void Context::set_clipboard(std::function read, + std::function write) { + impl_->clipboard_read = std::move(read); + impl_->clipboard_write = std::move(write); +} +void Context::set_ime(std::function enabled, std::function rectangle) { + impl_->ime_enabled = std::move(enabled); + impl_->ime_rectangle = std::move(rectangle); +} +void Context::set_docking(DockLayout* docking, std::function changed) { + impl_->docking = docking; + impl_->docking_changed = std::move(changed); +} + +bool Context::handle(const render::Event& event) { + auto& p = *impl_; + using Type = render::Event::Type; + if (event.type == Type::FocusLost) { + p.cancel_capture(); + if (auto found = p.edits.find(p.focused); found != p.edits.end()) + found->second.composition.clear(); + p.unfocus(true); + return false; + } + if (event.type == Type::MouseMove || event.type == Type::MouseDown || + event.type == Type::MouseUp) { + p.mouse_x = event.x; + p.mouse_y = event.y; + auto* hit = p.hit(p.root, event.x, event.y); + p.hovered = hit ? hit->id : ""; + } + if (event.type == Type::Wheel) { + auto* w = p.hit(p.root, p.mouse_x, p.mouse_y); + for (; w; w = w->parent) + if (w->layout.scroll) { + w->scroll_y = + std::clamp(w->scroll_y - event.y * p.theme.row_height * 3 * p.scale, 0.f, + std::max(0.f, w->content_height - w->rect.height + + 2 * w->layout.padding * p.scale)); + layout(p.width, p.height, p.scale); + return true; + } + return false; + } + if (event.type == Type::MouseDown && event.button == 1) { + auto* w = p.hit(p.root, event.x, event.y); + if (!w || w->kind == Kind::Viewport) { + p.unfocus(true); + return false; + } + if (!w->enabled) + return true; + if (focusable(*w)) { + if (!p.focus(w->id)) + return true; + } else { + if (!p.commit()) + return true; + p.unfocus(false); + } + p.captured = w->id; + p.down_x = event.x; + p.down_y = event.y; + p.down_value = w->value; + p.dragging = false; + p.payload = nullptr; + if (w->kind == Kind::TextField) { + auto& edit = p.edits[w->id]; + edit.buffer.set_cursor(p.text_position(*w, edit, event.x), event.shift); + } + if (w->kind == Kind::Divider) { + auto [before, after] = p.neighbors(*w); + if (before && after) { + const bool horizontal = w->parent->kind == Kind::Row; + p.before_size = (horizontal ? before->rect.width : before->rect.height) / p.scale; + p.after_size = (horizontal ? after->rect.width : after->rect.height) / p.scale; + p.before_layout = before->layout; + p.after_layout = after->layout; + } + } + return true; + } + if (event.type == Type::MouseMove && !p.captured.empty()) { + auto* w = p.find(p.captured); + if (!w) { + p.cancel_capture(); + return false; + } + const auto distance = std::hypot(event.x - p.down_x, event.y - p.down_y); + if (w->kind == Kind::NumberField && distance > 3 * p.scale) { + p.dragging = true; + w->value = + p.down_value + (event.x - p.down_x) / p.scale * w->step * (event.shift ? .1 : 1.0); + auto& edit = p.edits[w->id]; + edit.buffer.reset(number(w->value, w->precision)); + w->text = edit.buffer.text(); + auto callback = w->on_preview; + if (callback) + callback(*w); + return true; + } + if (w->kind == Kind::TextField) { + auto& edit = p.edits[w->id]; + edit.buffer.set_cursor(p.text_position(*w, edit, event.x), true); + return true; + } + if (w->kind == Kind::Divider) { + auto [before, after] = p.neighbors(*w); + if (before && after) { + const bool horizontal = w->parent->kind == Kind::Row; + const auto delta = (horizontal ? event.x - p.down_x : event.y - p.down_y) / p.scale; + const auto minimum_before = std::max(24.f, horizontal ? before->layout.min_width + : before->layout.min_height), + minimum_after = std::max(24.f, horizontal ? after->layout.min_width + : after->layout.min_height); + const auto low = minimum_before - p.before_size, + high = p.after_size - minimum_after; + const auto amount = low <= high ? std::clamp(delta, low, high) : 0.f; + if (before->layout.flex <= 0) { + if (horizontal) + before->layout.width = p.before_size + amount; + else + before->layout.height = p.before_size + amount; + } + if (after->layout.flex <= 0) { + if (horizontal) + after->layout.width = p.after_size - amount; + else + after->layout.height = p.after_size - amount; + } + if (before->layout.flex > 0 && after->layout.flex > 0) { + before->layout.flex = p.before_size + amount; + after->layout.flex = p.after_size - amount; + } + p.dragging = std::abs(amount) > .01f; + w->value = p.before_size + amount; + auto callback = w->on_preview; + if (callback) + callback(*w); + layout(p.width, p.height, p.scale); + } + return true; + } + if (distance > 5 * p.scale) { + if (!w->dock_panel.empty()) { + p.payload = {{"kind", "dock_panel"}, {"panel", w->dock_panel}, {"label", w->text}}; + p.dragging = true; + } else if (!w->drag_payload.is_null()) { + p.payload = w->drag_payload; + p.dragging = true; + } + } + return true; + } + if (event.type == Type::MouseUp && event.button == 1 && !p.captured.empty()) { + const auto id = p.captured; + auto* w = p.find(id); + const auto dragging = p.dragging; + auto payload = p.payload; + p.captured.clear(); + p.payload = nullptr; + p.dragging = false; + if (!w) + return true; + if (!payload.is_null()) { + auto* target = p.hit(p.root, event.x, event.y); + for (; target; target = target->parent) { + if (p.docking && payload.value("kind", std::string()) == "dock_panel" && + !target->dock_area.empty()) { + auto order = p.docking->panels(target->dock_area); + auto found = std::find(order.begin(), order.end(), target->dock_panel); + p.docking->move(payload.at("panel"), target->dock_area, + static_cast(found - order.begin())); + if (p.docking_changed) + p.docking_changed(); + break; + } + if (target->on_drop) { + auto callback = target->on_drop; + callback(*target, payload); + break; + } + } + return true; + } + if (w->kind == Kind::NumberField && dragging) { + p.commit(); + return true; + } + if (w->kind == Kind::Divider && dragging) { + auto callback = w->on_commit; + if (callback) + callback(*w); + return true; + } + if (!w->rect.contains(event.x, event.y)) + return true; + if (w->kind == Kind::Checkbox) { + w->checked = !w->checked; + auto callback = w->on_commit; + if (callback) + callback(*w); + w = p.find(id); + if (!w) + return true; + } + if (w->kind == Kind::Button || w->kind == Kind::Tab || w->kind == Kind::TreeRow || + w->kind == Kind::Checkbox) { + auto callback = w->on_click; + if (callback) + callback(*w); + } + return true; + } + if (event.type == Type::KeyDown && event.key == "Escape") { + if (!p.captured.empty()) { + p.cancel_capture(); + return true; + } + if (auto* w = p.find(p.focused); w && field(*w)) { + auto& edit = p.edits[w->id]; + w->text = edit.original; + w->value = edit.original_value; + w->error.clear(); + edit.buffer.reset(edit.original); + edit.composition.clear(); + auto callback = w->on_cancel; + if (callback) + callback(*w); + p.unfocus(false); + return true; + } + return false; + } + if (event.type == Type::KeyDown && event.key == "Tab") { + std::vector ids; + collect_focus(p.root, ids); + if (ids.empty()) + return false; + auto current = std::find(ids.begin(), ids.end(), p.focused); + std::size_t index = + current == ids.end() ? 0 : static_cast(current - ids.begin()); + if (current != ids.end()) + index = event.shift ? (index + ids.size() - 1) % ids.size() : (index + 1) % ids.size(); + return p.focus(ids[index]); + } + auto* w = p.find(p.focused); + if (!w) + return false; + if (field(*w)) { + auto& edit = p.edits[w->id]; + if (event.type == Type::TextEditing) { + if (TextBuffer::valid_utf8(event.text)) { + edit.composition = event.text; + edit.composition_start = event.edit_start; + edit.composition_length = event.edit_length; + } + return true; + } + if (event.type == Type::TextInput) { + auto text = event.text; + std::replace(text.begin(), text.end(), '\n', ' '); + std::replace(text.begin(), text.end(), '\r', ' '); + edit.composition.clear(); + if (edit.buffer.insert(text)) + p.preview(); + return true; + } + if (event.type != Type::KeyDown) + return false; + if (event.control && (event.key == "A" || event.key == "a")) { + edit.buffer.select_all(); + return true; + } + if (event.control && + (event.key == "C" || event.key == "c" || event.key == "X" || event.key == "x")) { + if (p.clipboard_write && edit.buffer.has_selection()) + p.clipboard_write(edit.buffer.selected_text()); + if ((event.key == "X" || event.key == "x") && edit.buffer.has_selection()) { + edit.buffer.insert(""); + p.preview(); + } + return true; + } + if (event.control && (event.key == "V" || event.key == "v")) { + if (p.clipboard_read) { + auto text = p.clipboard_read(); + std::replace(text.begin(), text.end(), '\n', ' '); + std::replace(text.begin(), text.end(), '\r', ' '); + if (edit.buffer.insert(text)) + p.preview(); + } + return true; + } + if (event.control && (event.key == "Z" || event.key == "z")) { + const auto changed = event.shift ? edit.buffer.redo() : edit.buffer.undo(); + if (changed) + p.preview(); + return changed; + } + if (event.control && (event.key == "Y" || event.key == "y")) { + const auto changed = edit.buffer.redo(); + if (changed) + p.preview(); + return changed; + } + if (event.key == "Left") { + edit.buffer.left(event.shift, event.control); + return true; + } + if (event.key == "Right") { + edit.buffer.right(event.shift, event.control); + return true; + } + if (event.key == "Home") { + edit.buffer.home(event.shift); + return true; + } + if (event.key == "End") { + edit.buffer.end(event.shift); + return true; + } + if (event.key == "Backspace") { + if (edit.buffer.backspace()) + p.preview(); + return true; + } + if (event.key == "Delete") { + if (edit.buffer.delete_forward()) + p.preview(); + return true; + } + if (event.key == "Return" || event.key == "Enter") { + if (p.commit()) { + auto* current = p.find(p.focused); + if (current && current->kind == Kind::NumberField) + p.edits[current->id].buffer.select_all(); + } + return true; + } + return false; + } + if (event.type == Type::KeyDown && (event.key == "Return" || event.key == "Space")) { + const auto id = w->id; + if (w->kind == Kind::Checkbox) { + w->checked = !w->checked; + auto callback = w->on_commit; + if (callback) + callback(*w); + w = p.find(id); + } + if (w) { + auto callback = w->on_click; + if (callback) + callback(*w); + } + return true; + } + return false; +} +} // namespace faset::ui diff --git a/tests/assets_pipeline.cpp b/tests/assets_pipeline.cpp index b66f866..7f122aa 100644 --- a/tests/assets_pipeline.cpp +++ b/tests/assets_pipeline.cpp @@ -1,73 +1,277 @@ -#include -#include #include #include +#include +#include #include #include #include using namespace faset::assets; -namespace fs=std::filesystem; +namespace fs = std::filesystem; namespace { -void require(bool value,const std::string& message){if(!value)throw std::runtime_error(message);} -void u32(std::vector& data,std::uint32_t value){for(int i=0;i<4;++i)data.push_back(static_cast(value>>(8*i)));} -void save(const fs::path& file,const std::vector& data){std::ofstream out(file,std::ios::binary);out.write(reinterpret_cast(data.data()),static_cast(data.size()));} -void save(const fs::path& file,const std::string& text){std::ofstream(file,std::ios::binary)< geometry(float x){std::vector bin;for(float f:{x,0.f,0.f,1.f,0.f,0.f,0.f,1.f,0.f})u32(bin,std::bit_cast(f));for(unsigned char c:{0,0,1,0,2,0})bin.push_back(c);return bin;} -Json document(const std::string& name,bool stable,bool second,float x=0) { - Json node{{"name",name},{"mesh",0}};if(stable)node["extras"]={{"faset_id","node-door"}}; - Json j={{"asset",{{"version","2.0"}}},{"scene",0},{"scenes",Json::array({{{"nodes",Json::array({0})}}})},{"nodes",Json::array({node})},{"buffers",Json::array({{{"byteLength",42}}})},{"bufferViews",Json::array({{{"buffer",0},{"byteOffset",0},{"byteLength",36},{"target",34962}},{{"buffer",0},{"byteOffset",36},{"byteLength",6},{"target",34963}}})},{"accessors",Json::array({{{"bufferView",0},{"componentType",5126},{"count",3},{"type","VEC3"},{"min",{std::min(0.f,x),0,0}},{"max",{std::max(1.f,x),1,0}}},{{"bufferView",1},{"componentType",5123},{"count",3},{"type","SCALAR"}}})},{"meshes",Json::array({{{"name","Triangle"},{"extras",{{"faset_id","mesh-triangle"}}},{"primitives",Json::array({{{"attributes",{{"POSITION",0}}},{"indices",1},{"material",0}}})}}})},{"materials",Json::array({{{"name","Red"},{"pbrMetallicRoughness",{{"baseColorFactor",{1.0,0.2,0.1,1.0}},{"metallicFactor",0.2},{"roughnessFactor",0.6}}}}})}}; - if(second){j["nodes"].push_back({{"name","Handle"},{"mesh",0},{"extras",{{"faset_id","node-handle"}}}});j["scenes"][0]["nodes"].push_back(1);} +void require(bool value, const std::string& message) { + if (!value) + throw std::runtime_error(message); +} +void u32(std::vector& data, std::uint32_t value) { + for (int i = 0; i < 4; ++i) + data.push_back(static_cast(value >> (8 * i))); +} +void save(const fs::path& file, const std::vector& data) { + std::ofstream out(file, std::ios::binary); + out.write(reinterpret_cast(data.data()), + static_cast(data.size())); +} +void save(const fs::path& file, const std::string& text) { + std::ofstream(file, std::ios::binary) << text; +} +std::vector geometry(float x) { + std::vector bin; + for (float f : {x, 0.f, 0.f, 1.f, 0.f, 0.f, 0.f, 1.f, 0.f}) + u32(bin, std::bit_cast(f)); + for (unsigned char c : {0, 0, 1, 0, 2, 0}) + bin.push_back(c); + return bin; +} +Json document(const std::string& name, bool stable, bool second, float x = 0) { + Json node{{"name", name}, {"mesh", 0}}; + if (stable) + node["extras"] = {{"faset_id", "node-door"}}; + Json j = { + {"asset", {{"version", "2.0"}}}, + {"scene", 0}, + {"scenes", Json::array({{{"nodes", Json::array({0})}}})}, + {"nodes", Json::array({node})}, + {"buffers", Json::array({{{"byteLength", 42}}})}, + {"bufferViews", + Json::array({{{"buffer", 0}, {"byteOffset", 0}, {"byteLength", 36}, {"target", 34962}}, + {{"buffer", 0}, {"byteOffset", 36}, {"byteLength", 6}, {"target", 34963}}})}, + {"accessors", + Json::array( + {{{"bufferView", 0}, + {"componentType", 5126}, + {"count", 3}, + {"type", "VEC3"}, + {"min", {std::min(0.f, x), 0, 0}}, + {"max", {std::max(1.f, x), 1, 0}}}, + {{"bufferView", 1}, {"componentType", 5123}, {"count", 3}, {"type", "SCALAR"}}})}, + {"meshes", Json::array({{{"name", "Triangle"}, + {"extras", {{"faset_id", "mesh-triangle"}}}, + {"primitives", Json::array({{{"attributes", {{"POSITION", 0}}}, + {"indices", 1}, + {"material", 0}}})}}})}, + {"materials", Json::array({{{"name", "Red"}, + {"pbrMetallicRoughness", + {{"baseColorFactor", {1.0, 0.2, 0.1, 1.0}}, + {"metallicFactor", 0.2}, + {"roughnessFactor", 0.6}}}}})}}; + if (second) { + j["nodes"].push_back( + {{"name", "Handle"}, {"mesh", 0}, {"extras", {{"faset_id", "node-handle"}}}}); + j["scenes"][0]["nodes"].push_back(1); + } return j; } -void glb(const fs::path& path,const std::string& name="Door",bool stable=true,bool second=false,float x=0) { - auto json=document(name,stable,second,x).dump();while(json.size()%4)json+=' '; - auto binary=geometry(x);while(binary.size()%4)binary.push_back(0); - std::vector result;u32(result,0x46546c67);u32(result,2);u32(result,static_cast(12+8+json.size()+8+binary.size()));u32(result,static_cast(json.size()));u32(result,0x4e4f534a);result.insert(result.end(),json.begin(),json.end());u32(result,static_cast(binary.size()));u32(result,0x004e4942);result.insert(result.end(),binary.begin(),binary.end());save(path,result); +void glb(const fs::path& path, const std::string& name = "Door", bool stable = true, + bool second = false, float x = 0) { + auto json = document(name, stable, second, x).dump(); + while (json.size() % 4) + json += ' '; + auto binary = geometry(x); + while (binary.size() % 4) + binary.push_back(0); + std::vector result; + u32(result, 0x46546c67); + u32(result, 2); + u32(result, static_cast(12 + 8 + json.size() + 8 + binary.size())); + u32(result, static_cast(json.size())); + u32(result, 0x4e4f534a); + result.insert(result.end(), json.begin(), json.end()); + u32(result, static_cast(binary.size())); + u32(result, 0x004e4942); + result.insert(result.end(), binary.begin(), binary.end()); + save(path, result); } -void success(const ImportResult& result){if(!result.ok()){std::string text="Import failed: ";for(const auto& d:result.diagnostics)text+=d+"; ";throw std::runtime_error(text);}} +void success(const ImportResult& result) { + if (!result.ok()) { + std::string text = "Import failed: "; + for (const auto& d : result.diagnostics) + text += d + "; "; + throw std::runtime_error(text); + } } +} // namespace int main() { - const auto root=fs::temp_directory_path()/("faset-assets-test-"+std::to_string(std::chrono::steady_clock::now().time_since_epoch().count())); + const auto root = fs::temp_directory_path() / + ("faset-assets-test-" + + std::to_string(std::chrono::steady_clock::now().time_since_epoch().count())); fs::create_directories(root); try { - AssetPipeline pipeline(root/"cache");const auto source=root/"door.glb";glb(source); - auto first=pipeline.import_asset({source});success(first);require(!first.asset_id.empty(),"persistent identity missing"); - auto asset=pipeline.load_asset(first.asset_id);require(asset.meshes.size()==1&&asset.nodes.size()==1,"mesh/node extraction");require(asset.meshes[0].primitives[0].indices==std::vector({0,1,2}),"index extraction");require(asset.meshes[0].primitives[0].vertices[0].normal[2]==1,"generated normal");require(asset.materials[0].base_color[1]>.19f&&asset.materials[0].metallic==.2f,"PBR extraction"); - const auto node_id=asset.nodes[0].id; - const Json custom{{node_id,{{"gameplay",{{"locked",true}}},{"physics",{{"mass",12}}},{"material","custom-brass"}}}}; - pipeline.set_overrides(first.asset_id,custom); - auto unchanged=pipeline.import_asset({source});success(unchanged);require(unchanged.cache_hit&&unchanged.generation==first.generation,"content cache hit"); - glb(source,"Renamed panel",true,false,.25f);auto modified=pipeline.import_asset({source});success(modified);require(modified.asset_id==first.asset_id&&modified.generation!=first.generation,"stable asset identity and changed generation"); - asset=pipeline.load_asset(first.asset_id);require(asset.nodes[0].id==node_id&&asset.nodes[0].name=="Renamed panel","faset_id survives rename");require(asset.meshes[0].primitives[0].vertices[0].position[0]==.25f,"new binary geometry loaded");require(pipeline.overrides(first.asset_id)==custom,"reimport erased authoring overrides"); - glb(source,"Renamed panel",true,true,.25f);auto added=pipeline.import_asset({source});success(added); - glb(source,"Renamed panel",true,false,.25f);auto removed=pipeline.import_asset({source});require(removed.status==ImportStatus::conflict&&!removed.removed_output_ids.empty(),"deletion must conflict");require(pipeline.load_asset(first.asset_id).generation==added.generation,"conflict replaced active generation");require(pipeline.overrides(first.asset_id)==custom,"conflict erased overrides"); - ImportRequest resolve{source};resolve.allow_removed_outputs=true;auto resolved=pipeline.import_asset(resolve);success(resolved);require(pipeline.load_asset(first.asset_id).nodes.size()==1,"explicit deletion resolution"); - const auto active=resolved.generation; - save(source,std::string("not a GLB"));auto failed=pipeline.import_asset({source});require(failed.status==ImportStatus::failed,"invalid source accepted");require(pipeline.load_asset(first.asset_id).generation==active,"failed import replaced active"); - glb(source,"Renamed panel",true,false,.5f);ImportJob* job_ptr=nullptr;ImportJob job([&](const ImportProgress& p){if(p.fraction>=.9f)job_ptr->cancel();});job_ptr=&job; - auto cancelled=pipeline.import_asset({source},job);require(cancelled.status==ImportStatus::cancelled,"cancel before commit failed");require(pipeline.load_asset(first.asset_id).generation==active,"cancel replaced active"); - ImportRequest changed_settings{source};changed_settings.settings={{"target","test-profile"}};auto settings=pipeline.import_asset(changed_settings);success(settings);require(settings.generation!=active,"recipe omitted from cache key"); - const auto plain=root/"ordinary.glb";glb(plain,"Ordinary",false);auto standard=pipeline.import_asset({plain});success(standard);require(!pipeline.load_asset(standard.asset_id).nodes[0].stable_source_id,"ordinary GLB wrongly marked stable source"); - glb(plain,"Renamed without ID",false);require(pipeline.import_asset({plain}).status==ImportStatus::conflict,"ambiguous rename silently matched"); - auto duplicate=document("Duplicate",true,true);duplicate["nodes"][1]["extras"]["faset_id"]="node-door";duplicate["buffers"][0]["uri"]="mesh.bin";save(root/"mesh.bin",geometry(0));save(root/"duplicate.gltf",duplicate.dump());require(pipeline.import_asset({root/"duplicate.gltf"}).status==ImportStatus::failed,"duplicate source ID accepted"); - auto external=document("External",true,false);external["buffers"][0]["uri"]="mesh.bin";external["images"]=Json::array({{{"uri","pixel.png"},{"mimeType","image/png"}}});external["textures"]=Json::array({{{"source",0}}});external["materials"][0]["pbrMetallicRoughness"]["baseColorTexture"]={{"index",0}}; + AssetPipeline pipeline(root / "cache"); + const auto source = root / "door.glb"; + glb(source); + auto first = pipeline.import_asset({source}); + success(first); + require(!first.asset_id.empty(), "persistent identity missing"); + auto asset = pipeline.load_asset(first.asset_id); + require(asset.meshes.size() == 1 && asset.nodes.size() == 1, "mesh/node extraction"); + require(asset.meshes[0].primitives[0].indices == std::vector({0, 1, 2}), + "index extraction"); + require(asset.meshes[0].primitives[0].vertices[0].normal[2] == 1, "generated normal"); + require(asset.materials[0].base_color[1] > .19f && asset.materials[0].metallic == .2f, + "PBR extraction"); + const auto node_id = asset.nodes[0].id; + const Json custom{{node_id, + {{"gameplay", {{"locked", true}}}, + {"physics", {{"mass", 12}}}, + {"material", "custom-brass"}}}}; + pipeline.set_overrides(first.asset_id, custom); + auto unchanged = pipeline.import_asset({source}); + success(unchanged); + require(unchanged.cache_hit && unchanged.generation == first.generation, + "content cache hit"); + glb(source, "Renamed panel", true, false, .25f); + auto modified = pipeline.import_asset({source}); + success(modified); + require(modified.asset_id == first.asset_id && modified.generation != first.generation, + "stable asset identity and changed generation"); + asset = pipeline.load_asset(first.asset_id); + require(asset.nodes[0].id == node_id && asset.nodes[0].name == "Renamed panel", + "faset_id survives rename"); + require(asset.meshes[0].primitives[0].vertices[0].position[0] == .25f, + "new binary geometry loaded"); + require(pipeline.overrides(first.asset_id) == custom, + "reimport erased authoring overrides"); + glb(source, "Renamed panel", true, true, .25f); + auto added = pipeline.import_asset({source}); + success(added); + glb(source, "Renamed panel", true, false, .25f); + auto removed = pipeline.import_asset({source}); + require(removed.status == ImportStatus::conflict && !removed.removed_output_ids.empty(), + "deletion must conflict"); + require(pipeline.load_asset(first.asset_id).generation == added.generation, + "conflict replaced active generation"); + require(pipeline.overrides(first.asset_id) == custom, "conflict erased overrides"); + ImportRequest resolve{source}; + resolve.allow_removed_outputs = true; + auto resolved = pipeline.import_asset(resolve); + success(resolved); + require(pipeline.load_asset(first.asset_id).nodes.size() == 1, + "explicit deletion resolution"); + const auto active = resolved.generation; + save(source, std::string("not a GLB")); + auto failed = pipeline.import_asset({source}); + require(failed.status == ImportStatus::failed, "invalid source accepted"); + require(pipeline.load_asset(first.asset_id).generation == active, + "failed import replaced active"); + glb(source, "Renamed panel", true, false, .5f); + ImportJob* job_ptr = nullptr; + ImportJob job([&](const ImportProgress& p) { + if (p.fraction >= .9f) + job_ptr->cancel(); + }); + job_ptr = &job; + auto cancelled = pipeline.import_asset({source}, job); + require(cancelled.status == ImportStatus::cancelled, "cancel before commit failed"); + require(pipeline.load_asset(first.asset_id).generation == active, "cancel replaced active"); + ImportRequest changed_settings{source}; + changed_settings.settings = {{"target", "test-profile"}}; + auto settings = pipeline.import_asset(changed_settings); + success(settings); + require(settings.generation != active, "recipe omitted from cache key"); + const auto plain = root / "ordinary.glb"; + glb(plain, "Ordinary", false); + auto standard = pipeline.import_asset({plain}); + success(standard); + require(!pipeline.load_asset(standard.asset_id).nodes[0].stable_source_id, + "ordinary GLB wrongly marked stable source"); + glb(plain, "Renamed without ID", false); + require(pipeline.import_asset({plain}).status == ImportStatus::conflict, + "ambiguous rename silently matched"); + auto duplicate = document("Duplicate", true, true); + duplicate["nodes"][1]["extras"]["faset_id"] = "node-door"; + duplicate["buffers"][0]["uri"] = "mesh.bin"; + save(root / "mesh.bin", geometry(0)); + save(root / "duplicate.gltf", duplicate.dump()); + require(pipeline.import_asset({root / "duplicate.gltf"}).status == ImportStatus::failed, + "duplicate source ID accepted"); + auto external = document("External", true, false); + external["buffers"][0]["uri"] = "mesh.bin"; + external["images"] = Json::array({{{"uri", "pixel.png"}, {"mimeType", "image/png"}}}); + external["textures"] = Json::array({{{"source", 0}}}); + external["materials"][0]["pbrMetallicRoughness"]["baseColorTexture"] = {{"index", 0}}; // Real 1x1 PNG payload, transparent pixel; importer owns encoded bytes. - const std::vector png={137,80,78,71,13,10,26,10,0,0,0,13,73,72,68,82,0,0,0,1,0,0,0,1,8,6,0,0,0,31,21,196,137,0,0,0,11,73,68,65,84,120,156,99,96,0,2,0,0,5,0,1,165,246,69,64,0,0,0,0,73,69,78,68,174,66,96,130}; - save(root/"pixel.png",png);save(root/"external.gltf",external.dump());auto ext=pipeline.import_asset({root/"external.gltf"});success(ext);auto ext_asset=pipeline.load_asset(ext.asset_id);require(ext_asset.textures.size()==1&&ext_asset.textures[0].bytes.size()==png.size(),"external image not extracted");require(ext_asset.materials[0].base_color_texture==0,"material texture reference lost"); - save(root/"mesh.bin",geometry(.3f));auto dependent=pipeline.import_asset({root/"external.gltf"});success(dependent);require(dependent.generation!=ext.generation,"buffer dependency not invalidated"); + const std::vector png = { + 137, 80, 78, 71, 13, 10, 26, 10, 0, 0, 0, 13, 73, 72, 68, 82, 0, + 0, 0, 1, 0, 0, 0, 1, 8, 6, 0, 0, 0, 31, 21, 196, 137, 0, + 0, 0, 11, 73, 68, 65, 84, 120, 156, 99, 96, 0, 2, 0, 0, 5, 0, + 1, 165, 246, 69, 64, 0, 0, 0, 0, 73, 69, 78, 68, 174, 66, 96, 130}; + save(root / "pixel.png", png); + save(root / "external.gltf", external.dump()); + auto ext = pipeline.import_asset({root / "external.gltf"}); + success(ext); + auto ext_asset = pipeline.load_asset(ext.asset_id); + require(ext_asset.textures.size() == 1 && ext_asset.textures[0].bytes.size() == png.size(), + "external image not extracted"); + require(ext_asset.materials[0].base_color_texture == 0, "material texture reference lost"); + save(root / "mesh.bin", geometry(.3f)); + auto dependent = pipeline.import_asset({root / "external.gltf"}); + success(dependent); + require(dependent.generation != ext.generation, "buffer dependency not invalidated"); // A Blender bundle keeps its logical source stable while immutable payload paths change. - const auto bundle_dir=root/"bundle";fs::create_directories(bundle_dir/"payload"); - glb(bundle_dir/"payload"/"first.glb","Bundle",true,false); - Json bundle{{"schema_version",1},{"asset_id","bundle-asset"},{"files",Json::array({{{"path","payload/first.glb"},{"sha256",faset::sha256_file(bundle_dir/"payload"/"first.glb")}}})}}; - save(bundle_dir/"manifest.json",bundle.dump());auto bundle_first=pipeline.import_asset({bundle_dir/"manifest.json"});success(bundle_first);require(bundle_first.asset_id=="bundle-asset","bundle identity lost"); - glb(bundle_dir/"payload"/"second.glb","Bundle renamed",true,false,.4f);bundle["files"][0]={{"path","payload/second.glb"},{"sha256",faset::sha256_file(bundle_dir/"payload"/"second.glb")}}; - save(bundle_dir/"manifest.json",bundle.dump());auto bundle_second=pipeline.import_asset({bundle_dir/"manifest.json"});success(bundle_second);require(bundle_second.asset_id==bundle_first.asset_id&&bundle_second.generation!=bundle_first.generation,"bundle reimport identity/generation"); - bundle["files"][0]["sha256"]=std::string(64,'0');save(bundle_dir/"manifest.json",bundle.dump());require(pipeline.import_asset({bundle_dir/"manifest.json"}).status==ImportStatus::failed,"bundle checksum ignored");require(pipeline.load_asset("bundle-asset").generation==bundle_second.generation,"bad bundle replaced active"); + const auto bundle_dir = root / "bundle"; + fs::create_directories(bundle_dir / "payload"); + glb(bundle_dir / "payload" / "first.glb", "Bundle", true, false); + Json bundle{{"schema_version", 1}, + {"asset_id", "bundle-asset"}, + {"files", Json::array({{{"path", "payload/first.glb"}, + {"sha256", faset::sha256_file(bundle_dir / "payload" / + "first.glb")}}})}}; + save(bundle_dir / "manifest.json", bundle.dump()); + auto bundle_first = pipeline.import_asset({bundle_dir / "manifest.json"}); + success(bundle_first); + require(bundle_first.asset_id == "bundle-asset", "bundle identity lost"); + glb(bundle_dir / "payload" / "second.glb", "Bundle renamed", true, false, .4f); + bundle["files"][0] = { + {"path", "payload/second.glb"}, + {"sha256", faset::sha256_file(bundle_dir / "payload" / "second.glb")}}; + save(bundle_dir / "manifest.json", bundle.dump()); + auto bundle_second = pipeline.import_asset({bundle_dir / "manifest.json"}); + success(bundle_second); + require(bundle_second.asset_id == bundle_first.asset_id && + bundle_second.generation != bundle_first.generation, + "bundle reimport identity/generation"); + bundle["files"][0]["sha256"] = std::string(64, '0'); + save(bundle_dir / "manifest.json", bundle.dump()); + require(pipeline.import_asset({bundle_dir / "manifest.json"}).status == + ImportStatus::failed, + "bundle checksum ignored"); + require(pipeline.load_asset("bundle-asset").generation == bundle_second.generation, + "bad bundle replaced active"); // Changing a dependency after it was snapshotted cannot publish mixed content. - const auto dependency_active=pipeline.load_asset(ext.asset_id).generation; - ImportJob mutate([&](const ImportProgress& progress){if(progress.fraction==.5f)save(root/"mesh.bin",geometry(.7f));}); - require(pipeline.import_asset({root/"external.gltf"},mutate).status==ImportStatus::failed,"concurrent dependency edit accepted");require(pipeline.load_asset(ext.asset_id).generation==dependency_active,"concurrent edit changed active"); - fs::remove_all(root/"cache");auto restored=pipeline.import_asset({source});success(restored);require(restored.asset_id==first.asset_id,"cleared cache changed AssetId");require(restored.manifest["settings"]==changed_settings.settings,"persisted recipe lost");require(pipeline.overrides(first.asset_id)==custom,"cleared cache lost authoring overrides"); - fs::remove_all(root);std::cout<<"assets: geometry/PBR/texture, GLB/glTF, cache, rename, deletion, overrides, failure, cancellation OK\n";return 0; - } catch(const std::exception& e){std::cerr< #include +#include #include #include -#define CHECK(x) do {if(!(x))throw std::runtime_error("Check failed at line "+std::to_string(__LINE__)+": " #x);}while(false) -template void fails(Fn fn,const std::string& code) {try{fn();}catch(const faset::Error& error){CHECK(error.code()==code);return;}throw std::runtime_error("Expected error "+code);} -int main() { - using namespace faset;using namespace faset::authoring; - const auto root=std::filesystem::temp_directory_path()/("faset-authoring-"+new_id()); +#define CHECK(x) \ + do { \ + if (!(x)) \ + throw std::runtime_error("Check failed at line " + std::to_string(__LINE__) + \ + ": " #x); \ + } while (false) +template void fails(Fn fn, const std::string& code) { try { - auto schemas=builtin_schemas();AuthoringService service(root,schemas); - auto created=service.create("Courtyard",3);const std::string id=created["id"]; - auto first=make_entity(schemas,"Door");const std::string entity_id=first["id"],transform_id=first["components"][0]["id"]; - Json commands=Json::array({{{"op","entity.create"},{"entity",first}}}); - const auto after=service.transact(id,0,commands,"request-1");CHECK(after["revision"]==1);CHECK(after["scene"]["entities"].size()==1); - CHECK(service.transact(id,0,commands,"request-1")==after); - fails([&]{service.transact(id,0,commands);},"revision.conflict"); - fails([&]{service.transact(id,1,commands,"request-1");},"idempotency.conflict"); - auto bad=Json::array({{{"op","entity.rename"},{"entity",entity_id},{"name","Should not survive"}},{{"op","component.set"},{"entity",entity_id},{"component",transform_id},{"field","position"},{"value","not a vector"}}}); - fails([&]{service.transact(id,1,bad);},"validation.field_type");CHECK(service.query(id)==after); - auto edited=service.transact(id,1,Json::array({{{"op","component.set"},{"entity",entity_id},{"component",transform_id},{"field","position"},{"value",{4,0,2}}}})); - CHECK(edited["revision"]==2);CHECK(service.undo(id,2)["scene"]==after["scene"]);CHECK(service.redo(id,3)["scene"]==edited["scene"]); - CHECK(service.save(id,"Scenes/courtyard.scene.json")["dirty"]==false); - service.transact(id,4,Json::array({{{"op","entity.rename"},{"entity",entity_id},{"name","Дверь 世界"}}})); - AuthoringService restarted(root,schemas);const auto recovered=restarted.open("Scenes/courtyard.scene.json",true);CHECK(recovered["scene"]["entities"][0]["name"]=="Дверь 世界");CHECK(recovered["dirty"]==true); - atomic_write(root/"Scenes/courtyard.scene.json",read_text(root/"Scenes/courtyard.scene.json")+"\n"); - fails([&]{restarted.save(id);},"save.disk_conflict"); + fn(); + } catch (const faset::Error& error) { + CHECK(error.code() == code); + return; + } + throw std::runtime_error("Expected error " + code); +} +int main() { + using namespace faset; + using namespace faset::authoring; + const auto root = std::filesystem::temp_directory_path() / ("faset-authoring-" + new_id()); + try { + auto schemas = builtin_schemas(); + AuthoringService service(root, schemas); + auto created = service.create("Courtyard", 3); + const std::string id = created["id"]; + auto first = make_entity(schemas, "Door"); + const std::string entity_id = first["id"], transform_id = first["components"][0]["id"]; + Json commands = Json::array({{{"op", "entity.create"}, {"entity", first}}}); + const auto after = service.transact(id, 0, commands, "request-1"); + CHECK(after["revision"] == 1); + CHECK(after["scene"]["entities"].size() == 1); + CHECK(service.transact(id, 0, commands, "request-1") == after); + fails([&] { service.transact(id, 0, commands); }, "revision.conflict"); + fails([&] { service.transact(id, 1, commands, "request-1"); }, "idempotency.conflict"); + auto bad = Json::array( + {{{"op", "entity.rename"}, {"entity", entity_id}, {"name", "Should not survive"}}, + {{"op", "component.set"}, + {"entity", entity_id}, + {"component", transform_id}, + {"field", "position"}, + {"value", "not a vector"}}}); + fails([&] { service.transact(id, 1, bad); }, "validation.field_type"); + CHECK(service.query(id) == after); + auto edited = service.transact(id, 1, + Json::array({{{"op", "component.set"}, + {"entity", entity_id}, + {"component", transform_id}, + {"field", "position"}, + {"value", {4, 0, 2}}}})); + CHECK(edited["revision"] == 2); + CHECK(service.undo(id, 2)["scene"] == after["scene"]); + CHECK(service.redo(id, 3)["scene"] == edited["scene"]); + CHECK(service.save(id, "Scenes/courtyard.scene.json")["dirty"] == false); + service.transact( + id, 4, + Json::array( + {{{"op", "entity.rename"}, {"entity", entity_id}, {"name", "Дверь 世界"}}})); + AuthoringService restarted(root, schemas); + const auto recovered = restarted.open("Scenes/courtyard.scene.json", true); + CHECK(recovered["scene"]["entities"][0]["name"] == "Дверь 世界"); + CHECK(recovered["dirty"] == true); + AuthoringService opened_then_recovered(root, schemas); + opened_then_recovered.open("Scenes/courtyard.scene.json"); + fails([&] { opened_then_recovered.recover(id); }, "recovery.revision_required"); + CHECK(opened_then_recovered.recover(id, 0)["scene"]["entities"][0]["name"] == "Дверь 世界"); + auto fresh = service.create("Never saved", 2); + const std::string fresh_id = fresh.at("id"); + service.transact(fresh_id, 0, + Json::array({{{"op", "entity.create"}, {"name", "Recovered sprite"}}})); + AuthoringService recover_new(root, schemas); + const auto restored_new = recover_new.recover(fresh_id); + CHECK(restored_new["dirty"] == true && restored_new["path"] == ""); + CHECK(restored_new["scene"]["entities"].size() == 1); + fails([&] { recover_new.recover("../../outside"); }, "id.invalid"); + atomic_write(root / "Scenes/courtyard.scene.json", + read_text(root / "Scenes/courtyard.scene.json") + "\n"); + fails([&] { restarted.save(id); }, "save.disk_conflict"); // Parent cycles are rejected atomically; names never provide identity. - fails([&]{service.transact(id,5,Json::array({{{"op","entity.reparent"},{"entity",entity_id},{"parent",entity_id}}}));},"entity.cycle"); - CHECK(service.query(id)["revision"]==5); + fails( + [&] { + service.transact(id, 5, + Json::array({{{"op", "entity.reparent"}, + {"entity", entity_id}, + {"parent", entity_id}}})); + }, + "entity.cycle"); + CHECK(service.query(id)["revision"] == 5); // Unavailable extension data is retained, including fields unknown to this SDK. - auto unknown=make_entity(schemas,"Plugin object");unknown["components"].push_back({{"id",new_id()},{"type","plugin.future"},{"version",5},{"fields",{{"unknown",Json::array({1,2,3})}}}}); - service.transact(id,5,Json::array({{{"op","entity.create"},{"entity",unknown}}}));CHECK(service.query(id)["scene"]["entities"][1]==unknown); + auto unknown = make_entity(schemas, "Plugin object"); + unknown["components"].push_back({{"id", new_id()}, + {"type", "plugin.future"}, + {"version", 5}, + {"fields", {{"unknown", Json::array({1, 2, 3})}}}}); + service.transact(id, 5, Json::array({{{"op", "entity.create"}, {"entity", unknown}}})); + CHECK(service.query(id)["scene"]["entities"][1] == unknown); // Nested template addresses remain valid after source rename and source reparent. - auto source=make_scene("Door template");source["entities"].push_back(first); - auto middle=make_scene("Nested");middle["instances"].push_back({{"id","nested"},{"source","door"}}); - auto outer=make_scene("Level"); - Json address={{"path",Json::array({"nested"})},{"object",entity_id},{"component",transform_id},{"field","position"}}; - outer["instances"].push_back({{"id","one"},{"source","middle"},{"overrides",Json::array({{{"address",address},{"value",{8,0,0}}}})}}); - outer["instances"].push_back({{"id","two"},{"source","middle"}}); - auto loader=[&](const std::string& name){return name=="door"?source:middle;}; - auto resolved=resolve_templates(outer,schemas,loader);CHECK(resolved.conflicts.empty());CHECK(resolved.scene["entities"].size()==2); - CHECK(resolved.scene["entities"][0]["components"][0]["fields"]["position"]==Json::array({8,0,0})); - CHECK(resolved.scene["entities"][1]["components"][0]["fields"]["position"]==Json::array({0,0,0})); - const auto stable=resolved.scene["entities"][0]["id"];source["entities"][0]["name"]="Renamed"; - CHECK(resolve_templates(outer,schemas,loader).scene["entities"][0]["id"]==stable); - source["entities"]=Json::array();CHECK(resolve_templates(outer,schemas,loader).conflicts.size()==1);CHECK(outer["instances"][0]["overrides"].size()==1); - // Stable FieldId survives a label rename; incompatible migrations require an explicit decision. - SchemaRegistry newer;newer.register_schema({{"id","sample.type"},{"name","Sample"},{"version",2},{"fields",{{"speed",{{"id","speed"},{"name","Movement speed"},{"type","number"},{"default",2}}},{"enabled",{{"type","boolean"},{"default",true}}}}}}); - newer.add_migration("sample.type",1,{{"speed",{{"scale",0.01}}}}); - const auto migrated=newer.migrate_component({{"id",new_id()},{"type","sample.type"},{"version",1},{"fields",{{"speed",300},{"unrecognized","preserve"}}}}); - CHECK(migrated["fields"]["speed"]==3.0);CHECK(migrated["fields"]["enabled"]==true);CHECK(migrated["fields"]["unrecognized"]=="preserve"); - std::filesystem::remove_all(root);std::cout<<"Authoring transactions, conflict/retry, Undo, recovery, unknown fields, nested IDs and migrations passed\n";return 0; - } catch(const std::exception& error) {std::filesystem::remove_all(root);std::cerr<() - 2.0) < 1e-6); + CHECK(std::abs(position[1].get()) < 1e-6); + reparent_entity(hierarchy, child["id"], nullptr, true); + position = hierarchy["entities"][1]["components"][0]["fields"]["position"]; + CHECK(std::abs(position[0].get() - 10) < 1e-6); + CHECK(std::abs(position[1].get() - 4) < 1e-6); + std::filesystem::remove_all(root); + std::cout << "Authoring transactions, conflict/retry, Undo, recovery, unknown fields, " + "nested IDs and migrations passed\n"; + return 0; + } catch (const std::exception& error) { + std::filesystem::remove_all(root); + std::cerr << error.what() << '\n'; + return 1; + } } diff --git a/tests/blender/generate_fixture.py b/tests/blender/generate_fixture.py new file mode 100644 index 0000000..d58da8e --- /dev/null +++ b/tests/blender/generate_fixture.py @@ -0,0 +1,28 @@ +import bpy, sys, pathlib, shutil, json +root=pathlib.Path(sys.argv[sys.argv.index('--')+1]) +output=pathlib.Path(sys.argv[sys.argv.index('--')+2]) +sys.path.insert(0,str(root/'tools')) +import blender_addon +blender_addon.register() +bpy.ops.object.select_all(action='SELECT') +bpy.ops.object.delete(use_global=False) +bpy.ops.mesh.primitive_cube_add(location=(0,0,1)) +obj=bpy.context.object;obj.name='Door panel' +obj['faset_id']='1c4b69fb-1219-4430-b046-8185eb265a0f' +obj.data['faset_id']='2072eb21-2558-41ee-a843-82e676e6a44e' +mat=bpy.data.materials.new('Brass');mat.diffuse_color=(0.8,0.5,0.12,1);mat['faset_id']='31dc2a5b-3d1c-41b8-b4ef-ddc626087458';obj.data.materials.append(mat) +bpy.context.scene['faset_asset_id']='54c039e4-c19f-4365-a9f8-a38416ec6e3f' +bpy.context.scene.frame_set(17,subframe=.25) +for stage in ('initial','renamed','removed'): + directory=output/stage;directory.mkdir(parents=True,exist_ok=True) + if stage=='renamed': + obj.name='Renamed Door';obj.data.vertices[0].co.x-=.2 + if stage=='removed': + bpy.data.objects.remove(obj,do_unlink=True) + result=bpy.ops.export_scene.faset_bundle(filepath=str(directory/'manifest.json')) + assert 'FINISHED' in result,result + assert bpy.context.scene.frame_current==17 and bpy.context.scene.frame_subframe==.25 + if stage!='removed': + assert bpy.context.view_layer.objects.active==obj and obj.select_get() + bpy.ops.wm.save_as_mainfile(filepath=str(directory/'source.blend')) +print('FASET_BLENDER_ROUNDTRIP_EXPORT_OK') diff --git a/tests/build_service_tests.cpp b/tests/build_service_tests.cpp new file mode 100644 index 0000000..304aef9 --- /dev/null +++ b/tests/build_service_tests.cpp @@ -0,0 +1,289 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifndef _WIN32 +#include +#endif +using namespace faset; +namespace fs = std::filesystem; +void require(bool value, const char* message) { + if (!value) + throw std::runtime_error(message); +} +std::string collect(Process& process) { + std::string text; + while (true) { + auto poll = process.poll(); + text += poll.output; + if (!poll.running) { + require(poll.exit_code == 0, "Child process failed"); + return text; + } + std::this_thread::sleep_for(std::chrono::milliseconds(5)); + } +} +Json scene(int dimension) { + return {{"format", "faset.scene"}, {"version", 1}, {"id", "scene-test"}, + {"name", "Build test"}, {"dimension", dimension}, {"entities", Json::array()}, + {"instances", Json::array()}}; +} +int integration(const fs::path& root) { + fs::create_directories(root); + editor::BuildConfig config; + config.project_root = root / "project"; + config.engine_root = FASET_ENGINE_SOURCE; + config.build_directory = root / "native-build"; + config.cache_root = root / "project" / ".faset" / "cache"; + editor::BuildService service(config); + service.scaffold("Export integration", 3); + // This dedicated integration fixture is reset before testing incremental user edits. + atomic_write(config.project_root / "Scripts" / "Gameplay.cpp", + read_text(config.engine_root / "tools" / "project_templates" / "Gameplay.cpp")); + auto wait = [&](const std::string& id) { + std::string stage; + while (true) { + auto job = service.job(id); + if (job.stage != stage) { + stage = job.stage; + std::cout << job.stage << std::endl; + } + if (job.finished()) { + if (job.state != "succeeded") { + std::cerr << job.error << '\n' << job.log; + throw std::runtime_error("Integration job failed"); + } + return job; + } + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + } + }; + const auto assets = config.project_root / "Assets"; + std::string binary; + for (float value : {-1.f, 0.f, 0.f, 1.f, 0.f, 0.f, 0.f, 2.f, 0.f}) { + auto bits = std::bit_cast(value); + for (int i = 0; i < 4; ++i) + binary.push_back(static_cast(bits >> (8 * i))); + } + atomic_write(assets / "triangle.bin", binary); + Json gltf = { + {"asset", {{"version", "2.0"}}}, + {"scene", 0}, + {"scenes", Json::array({{{"nodes", {0}}}})}, + {"nodes", Json::array({{{"mesh", 0}, {"extras", {{"faset_id", "triangle-node"}}}}})}, + {"buffers", Json::array({{{"uri", "triangle.bin"}, {"byteLength", 36}}})}, + {"bufferViews", Json::array({{{"buffer", 0}, {"byteLength", 36}}})}, + {"accessors", Json::array({{{"bufferView", 0}, + {"componentType", 5126}, + {"count", 3}, + {"type", "VEC3"}, + {"min", {-1, 0, 0}}, + {"max", {1, 2, 0}}}})}, + {"meshes", + Json::array({{{"primitives", Json::array({{{"attributes", {{"POSITION", 0}}}}})}}})}}; + atomic_write_json(assets / "triangle.gltf", gltf); + assets::AssetPipeline importer(config.cache_root); + auto imported = importer.import_asset({assets / "triangle.gltf"}); + require(imported.ok(), "Integration asset import"); + for (int dimension : {2, 3}) { + auto document = scene(dimension); + auto component = [](std::string type, Json fields) { + return Json{ + {"id", type}, {"type", type}, {"version", 1}, {"fields", std::move(fields)}}; + }; + Json components = Json::array( + {component("faset.transform", + {{"position", {0, 0, 0}}, {"rotation", {0, 0, 0}}, {"scale", {1, 1, 1}}})}); + if (dimension == 2) + components.push_back( + component("faset.sprite", {{"size", {2, 2}}, {"color", {.2, .7, .9, 1}}})); + else + components.push_back(component( + "faset.mesh", {{"asset", imported.asset_id + "#" + + importer.load_asset(imported.asset_id).nodes.at(0).id}, + {"color", {.3, .8, .5, 1}}})); + document["entities"].push_back({{"id", "object"}, + {"name", "Object"}, + {"parent", nullptr}, + {"components", components}}); + auto result = + wait(service.start_export(document, root / ("export-" + std::to_string(dimension)))); + const auto directory = fs::path(result.result.at("directory").get()); + require(result.result.at("configuration") == "Release", + "Exports default to the Release profile"); + require(fs::path(result.result.at("build_directory").get()) == + config.build_directory / "Release", + "Export has a separate CMake directory"); + require(read_json(directory / "manifest.json").at("configuration") == "Release", + "Export manifest records the actual profile"); + Process player({{result.result.at("executable").get(), "--headless", + "--frames", "3", "--capture", (directory / "verification.ppm").string()}, + directory, + {}}); + std::cout << collect(player); + require(fs::file_size(directory / "verification.ppm") > 1000, + "Exported game rendered a frame"); + atomic_write_json(root / ("result-" + std::to_string(dimension) + ".json"), result.result); + } + auto source = read_text(config.project_root / "Scripts" / "Gameplay.cpp"); + auto position = source.find("Character"); + require(position != std::string::npos, "Template schema fixture"); + source.replace(position, 9, "Custom Character"); + atomic_write(config.project_root / "Scripts" / "Gameplay.cpp", source); + auto release_cache = read_text(config.build_directory / "Release" / "CMakeCache.txt"); + auto rebuilt = wait(service.start_build()); + require(rebuilt.result.at("configuration") == "Debug", "Development builds remain Debug"); + require(fs::path(rebuilt.result.at("build_directory").get()) == + config.build_directory / "Debug", + "Development CMake directory is isolated"); + require(read_text(config.build_directory / "Release" / "CMakeCache.txt") == release_cache, + "Development build preserves the Release cache"); + auto schema = read_json(rebuilt.result.at("schema").get()); + bool updated{}; + for (const auto& type : schema.at("types")) + if (type.value("name", "") == "Custom Character") + updated = true; + require(updated, "Incremental C++ build produced new schema"); + auto last = read_text(config.cache_root / "last_build.json"); + atomic_write(config.project_root / "Scripts" / "Gameplay.cpp", + source + "\n#error intentional_build_failure\n"); + auto failed = service.wait(service.start_build()); + require(failed.state == "failed", "Invalid user C++ must fail build"); + require(read_text(config.cache_root / "last_build.json") == last, + "Failed compile preserved last good build"); + atomic_write(config.project_root / "Scripts" / "Gameplay.cpp", source); + std::cout << "Real 2D/3D exports, imported mesh packaging, native launches, incremental C++ " + "schema and failed-build recovery passed\n"; + return 0; +} +int main(int argc, char** argv) { + if (argc > 1 && std::string(argv[1]) == "--child") { + Json args = Json::array(); + for (int i = 2; i < argc; ++i) + args.push_back(argv[i]); + std::cout << Json{{"args", args}, + {"cwd", fs::current_path().string()}, + {"env", std::getenv("FASET_PROCESS_TEST") + ? std::getenv("FASET_PROCESS_TEST") + : ""}} + .dump() + << std::endl; + std::cerr << "stderr-sentinel\n"; + std::cout << std::string(100000, 'x') << std::endl; + return 0; + } + if (argc > 1 && std::string(argv[1]) == "--sleep") { +#ifndef _WIN32 + std::signal(SIGTERM, SIG_IGN); +#endif + std::cout << "ready\n" << std::flush; + std::this_thread::sleep_for(std::chrono::seconds(30)); + return 0; + } + if (argc == 3 && std::string(argv[1]) == "--integration") { + try { + return integration(fs::absolute(argv[2])); + } catch (const std::exception& error) { + std::cerr << error.what() << '\n'; + return 1; + } + } + fs::path temporary = fs::temp_directory_path() / ("Faset build test " + new_id()); + try { + fs::create_directories(temporary); + auto executable = fs::absolute(argv[0]); + Process child({{executable.string(), "--child", "space argument", "quote\"backslash\\", + "$(touch not-executed); & |", ""}, + temporary, + {{"FASET_PROCESS_TEST", "value with spaces"}}}); + auto text = collect(child); + auto result = Json::parse(text.substr(0, text.find('\n'))); + require(result["args"] == Json::array({"space argument", "quote\"backslash\\", + "$(touch not-executed); & |", ""}), + "Arguments must remain literal"); + require(result["env"] == "value with spaces", "Child environment override"); + require(fs::equivalent(result["cwd"].get(), temporary), + "Child working directory"); + require(text.find("stderr-sentinel") != std::string::npos && text.size() > 100000, + "Combined pipe output drained fully"); + require(!fs::exists(temporary / "not-executed"), "No shell execution"); + Process sleeper({{executable.string(), "--sleep"}, temporary, {}}); + bool ready{}; + while (!ready) { + auto p = sleeper.poll(); + ready = p.output.find("ready") != std::string::npos; + require(p.running, "Sleeper exited early"); + std::this_thread::sleep_for(std::chrono::milliseconds(5)); + } + auto start = std::chrono::steady_clock::now(); + sleeper.cancel(); + require(!sleeper.poll().running, "Cancellation must reap the process"); + require(std::chrono::steady_clock::now() - start < std::chrono::seconds(3), + "Cancellation must finish promptly"); + editor::BuildConfig config; + config.project_root = temporary / "project"; + config.engine_root = FASET_ENGINE_SOURCE; + editor::BuildService service(config); + service.scaffold("Test project", 2); + atomic_write(config.project_root / "Scripts" / "Gameplay.cpp", "// User code\n"); + service.scaffold("Another name", 3); + require(read_text(config.project_root / "Scripts" / "Gameplay.cpp") == "// User code\n", + "Scaffold preserves existing source"); + auto id = service.start_cook(scene(2)); + auto cooked = service.wait(id); + require(cooked.state == "succeeded", "Cook job succeeds"); + auto bytes = read_text(cooked.result.at("scene").get()); + require(bytes.substr(0, 8) == "FASETSCN" && bytes.size() > 20, "Cooked envelope magic"); + std::uint32_t version{}; + std::uint64_t size{}; + for (unsigned i = 0; i < 4; ++i) + version |= std::uint32_t(static_cast(bytes[8 + i])) << (8 * i); + for (unsigned i = 0; i < 8; ++i) + size |= std::uint64_t(static_cast(bytes[12 + i])) << (8 * i); + require(version == 1 && size == bytes.size() - 20, "Cooked envelope version and size"); + require(Json::from_cbor(bytes.begin() + 20, bytes.end()) == scene(2), + "Cooked scene preserves all values"); + auto previous = read_text(service.config().cache_root / "last_cook.json"); + auto broken = scene(3); + broken["version"] = 999; + auto bad = service.wait(service.start_cook(broken)); + require(bad.state == "failed", "Unsupported scene version rejected"); + require(read_text(service.config().cache_root / "last_cook.json") == previous, + "Failed cook preserves last good generation"); + broken = scene(3); + broken["entities"].push_back( + {{"id", "entity"}, + {"components", + Json::array({{{"type", "faset.mesh"}, {"fields", {{"asset", "missing-asset"}}}}})}}); + auto missing = service.wait(service.start_cook(broken)); + require(missing.state == "failed", "Missing asset blocks publication"); + require(read_text(service.config().cache_root / "last_cook.json") == previous, + "Missing asset preserves last good generation"); + broken = scene(3); + broken["entities"].push_back({{"id", "entity"}, + {"components", Json::array({{{"type", "faset.unknown"}, + {"version", 1}, + {"fields", Json::object()}}})}}); + auto unknown = service.wait(service.start_cook(broken)); + require(unknown.state == "failed" && + unknown.error.find("unresolved component") != std::string::npos, + "Unknown component type blocks cooking"); + require(read_text(service.config().cache_root / "last_cook.json") == previous, + "Unknown schema preserves last good generation"); + std::cout << "Literal process arguments, pipes, cancellation, scaffold and atomic cook " + "contracts passed\n"; + fs::remove_all(temporary); + return 0; + } catch (const std::exception& error) { + std::cerr << error.what() << '\n'; + std::error_code ignored; + fs::remove_all(temporary, ignored); + return 1; + } +} diff --git a/tests/core_tests.cpp b/tests/core_tests.cpp index 5143ebf..ed3b618 100644 --- a/tests/core_tests.cpp +++ b/tests/core_tests.cpp @@ -1,27 +1,59 @@ +#include #include #include -#include #include #include -#define CHECK(x) do { if(!(x)) throw std::runtime_error("Check failed: " #x); } while(false) +#define CHECK(x) \ + do { \ + if (!(x)) \ + throw std::runtime_error("Check failed: " #x); \ + } while (false) int main() { - const auto directory=std::filesystem::temp_directory_path()/("faset-core-"+faset::new_id()); + const auto directory = + std::filesystem::temp_directory_path() / ("faset-core-" + faset::new_id()); try { - CHECK(faset::sha256("")=="e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"); - CHECK(faset::sha256("abc")=="ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad"); - CHECK(faset::sha256(std::string(1000000,'a'))=="cdc76e5c9914fb9281a1c7e284d73e67f1809a48a497200e046d39ccc7112cd0"); + CHECK(faset::sha256("") == + "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"); + CHECK(faset::sha256("abc") == + "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad"); + CHECK(faset::sha256(std::string(1000000, 'a')) == + "cdc76e5c9914fb9281a1c7e284d73e67f1809a48a497200e046d39ccc7112cd0"); std::set ids; - for(int i=0;i<1000;++i) { const auto id=faset::new_id();CHECK(id.size()==36);CHECK(id[14]=='4');CHECK(ids.insert(id).second); } - faset::atomic_write(directory/"state.json","{\"value\":1}"); - faset::atomic_write_json(directory/"state.json",{{"value",2},{"text","Привет 世界"}}); - CHECK(faset::read_json(directory/"state.json").at("value")==2); - CHECK(faset::sha256_file(directory/"state.json")==faset::sha256(faset::read_text(directory/"state.json"))); - CHECK(std::filesystem::equivalent(faset::project_path(directory,"assets/../state.json"),directory/"state.json")); - bool rejected=false;try { faset::project_path(directory,"../escape"); } catch(const faset::Error&) {rejected=true;} CHECK(rejected); - rejected=false;try { faset::project_path(directory,directory/"state.json"); } catch(const faset::Error&) {rejected=true;} CHECK(rejected); + for (int i = 0; i < 1000; ++i) { + const auto id = faset::new_id(); + CHECK(id.size() == 36); + CHECK(id[14] == '4'); + CHECK(ids.insert(id).second); + } + faset::atomic_write(directory / "state.json", "{\"value\":1}"); + faset::atomic_write_json(directory / "state.json", {{"value", 2}, {"text", "Привет 世界"}}); + CHECK(faset::read_json(directory / "state.json").at("value") == 2); + CHECK(faset::sha256_file(directory / "state.json") == + faset::sha256(faset::read_text(directory / "state.json"))); + CHECK(std::filesystem::equivalent(faset::project_path(directory, "assets/../state.json"), + directory / "state.json")); + bool rejected = false; + try { + faset::project_path(directory, "../escape"); + } catch (const faset::Error&) { + rejected = true; + } + CHECK(rejected); + rejected = false; + try { + faset::project_path(directory, directory / "state.json"); + } catch (const faset::Error&) { + rejected = true; + } + CHECK(rejected); std::filesystem::remove_all(directory); - std::cout<<"Core: SHA-256 vectors, persistent IDs, durable replace, Unicode, path boundaries passed\n"; + std::cout << "Core: SHA-256 vectors, persistent IDs, durable replace, Unicode, path " + "boundaries passed\n"; return 0; - } catch(const std::exception& error) {std::filesystem::remove_all(directory);std::cerr< +#include +#include +#include +using namespace faset; +void check(bool value, const char* message) { + if (!value) + throw std::runtime_error(message); +} +render::Event key(std::string value, bool control = false, bool shift = false) { + render::Event e; + e.type = render::Event::Type::KeyDown; + e.key = std::move(value); + e.control = control; + e.shift = shift; + return e; +} +void click(editor::EditorUI& ui, const std::string& id) { + const auto* widget = ui.widgets().find(id); + check(widget != nullptr, "Missing widget"); + const auto rect = widget->rect.intersection(widget->clip); + check(rect.width > 0 && rect.height > 0, "Widget clipped"); + render::Event down; + down.type = render::Event::Type::MouseDown; + down.button = 1; + down.x = rect.x + rect.width * .5f; + down.y = rect.y + rect.height * .5f; + auto up = down; + up.type = render::Event::Type::MouseUp; + ui.frame({down, up}); +} +void text(editor::EditorUI& ui, const std::string& id, const std::string& value, + bool commit = true) { + click(ui, id); + render::Event e; + e.type = render::Event::Type::TextInput; + e.text = value; + std::vector events{key("A", true), e}; + if (commit) + events.push_back(key("Return")); + ui.frame(events); +} +int main() { + auto root = std::filesystem::temp_directory_path() / ("faset-ui-authoring-" + new_id()); + try { + std::filesystem::create_directories(root); + atomic_write_json(root / "project.faset.json", {{"format", "faset.project"}, + {"version", 1}, + {"name", "UI integration test"}, + {"dimension", 3}}); +#if defined(FASET_TEST_PLUGIN_DIRECTORY) + std::filesystem::create_directories(root / "Plugins"); + for (const auto& file : std::filesystem::directory_iterator(FASET_TEST_PLUGIN_DIRECTORY)) + if (file.is_regular_file()) + std::filesystem::copy_file(file.path(), root / "Plugins" / file.path().filename()); +#endif + editor::Session session({root, FASET_TEST_ENGINE, root}); + render::Renderer renderer({1280, 800, "Faset editor test", true, true}); + editor::EditorUI ui(session, renderer, + std::filesystem::path(FASET_TEST_ENGINE) / "assets/fonts/NotoSans.ttf", + std::filesystem::path(FASET_TEST_ENGINE) / "assets/ui/dark.json"); + ui.frame({}); + click(ui, "add-cube"); + auto state = session.authoring().query(ui.current_document()); + check(state["scene"]["entities"].size() == 1, "Add cube button must author entity"); + const auto eid = state["scene"]["entities"][0]["id"].get(); + check(ui.selected_entity() == eid, "New entity selected"); + text(ui, "object-name", "Дверь"); + state = session.authoring().query(ui.current_document()); + check(state["scene"]["entities"][0]["name"] == "Дверь", "Inspector Unicode rename"); + const auto cid = state["scene"]["entities"][0]["components"][0]["id"].get(); + const auto position = "field-" + cid + "-position-0"; + text(ui, position, "3.5"); + state = session.authoring().query(ui.current_document()); + check(state["scene"]["entities"][0]["components"][0]["fields"]["position"][0] == 3.5, + "Inspector typed field transaction"); + click(ui, "undo"); + state = session.authoring().query(ui.current_document()); + check(state["scene"]["entities"][0]["components"][0]["fields"]["position"][0] == 0, + "Toolbar Undo uses authoring history"); + click(ui, "redo"); + state = session.authoring().query(ui.current_document()); + check(state["scene"]["entities"][0]["components"][0]["fields"]["position"][0] == 3.5, + "Toolbar Redo"); + // A concurrent MCP edit cannot be overwritten by an unfinished inspector + // edit. + text(ui, "object-name", "Unsaved local name", false); + state = session.authoring().query(ui.current_document()); + session.authoring().transact( + ui.current_document(), state.at("revision"), + Json::array({{{"op", "entity.rename"}, {"entity", eid}, {"name", "External rename"}}})); + ui.frame({key("Return")}); + state = session.authoring().query(ui.current_document()); + check(state["scene"]["entities"][0]["name"] == "External rename", + "Revision conflict preserves external edit"); + click(ui, "scene-root"); + check(ui.selected_entity().empty(), "Scene root deselects object"); + click(ui, "entity-" + eid); + check(ui.selected_entity() == eid, "Scene tree selection"); + const auto initial_revision = state.at("revision").get(); + auto* field = ui.widgets().find(position); + const auto r = field->rect; + render::Event down; + down.type = render::Event::Type::MouseDown; + down.button = 1; + down.x = r.x + 20; + down.y = r.y + 12; + auto move = down; + move.type = render::Event::Type::MouseMove; + move.x += 20; + auto move2 = move; + move2.x += 20; + auto up = move2; + up.type = render::Event::Type::MouseUp; + ui.frame({down, move, move2, up}); + state = session.authoring().query(ui.current_document()); + check(state["revision"] == initial_revision + 1, + "Numeric drag commits exactly one transaction"); + // Selecting and manipulating the actual rendered geometry uses viewport + // events. + auto screen = [&](render::Vec3 position) { + const auto& snap = ui.snapshot(); + const auto& m = snap.view_projection; + const auto w = m[3] * position[0] + m[7] * position[1] + m[11] * position[2] + m[15]; + const auto nx = + (m[0] * position[0] + m[4] * position[1] + m[8] * position[2] + m[12]) / w; + const auto ny = + (m[1] * position[0] + m[5] * position[1] + m[9] * position[2] + m[13]) / w; + return render::Vec2{snap.scene_rect[0] + (nx + 1) * snap.scene_rect[2] * .5f, + snap.scene_rect[1] + (ny + 1) * snap.scene_rect[3] * .5f}; + }; + const auto x = + state["scene"]["entities"][0]["components"][0]["fields"]["position"][0].get(); + ui.select_entity(""); + ui.frame({}); + auto center = screen({x, 0, 0}); + down.x = center[0]; + down.y = center[1]; + up = down; + up.type = render::Event::Type::MouseUp; + ui.frame({down, up}); + check(ui.selected_entity() == eid, "Viewport ray must select visible cooked geometry"); + auto tip = screen({x + 1.44f, 0, 0}); + down.x = (center[0] + tip[0]) * .5f; + down.y = (center[1] + tip[1]) * .5f; + move = down; + move.type = render::Event::Type::MouseMove; + move.x += 20; + up = move; + up.type = render::Event::Type::MouseUp; + const auto before_gizmo = state.at("revision").get(); + ui.frame({down}); + ui.frame({move}); + check(session.authoring().query(ui.current_document())["revision"] == before_gizmo, + "Gizmo preview must not mutate authoring"); + ui.frame({up}); + state = session.authoring().query(ui.current_document()); + check(state["revision"] == before_gizmo + 1, "Gizmo release commits one transaction"); + click(ui, "undo"); + state = session.authoring().query(ui.current_document()); + check(std::abs(state["scene"]["entities"][0]["components"][0]["fields"]["position"][0] + .get() - + x) < .001f, + "Gizmo undo restores transform"); +#if defined(FASET_TEST_PLUGIN_DIRECTORY) + session.authoring().register_schemas(Json::parse( + R"([{"id":"example.beacon","name":"Beacon","version":1,"fields":{"speed":{"id":"speed","name":"Rotation speed","type":"number","default":1.0}}}])")); + ui.frame({}); + check(!session.plugin_panels().empty(), "Actual native plugin panel must load"); + const auto before_plugin = state["scene"]["entities"].size(); + click(ui, "tab-plugin-example.beacon.tools"); + click(ui, "plugin-action-example.beacon.tools"); + state = session.authoring().query(ui.current_document()); + check(state["scene"]["entities"].size() == before_plugin + 1, + "Plugin panel action must author Beacon through Commands"); + click(ui, "tab-assets"); +#endif + renderer.render(ui.snapshot()); + renderer.capture(root / "editor-ui.ppm"); + check(renderer.stats().validation_errors == 0, "Vulkan validation errors"); + std::cout << "Editor UI: actual events create/select/rename/typed " + "fields/Undo/Redo/conflict/one drag transaction passed. " + "Screenshot: " + << (root / "editor-ui.ppm") << '\n'; + return 0; + } catch (const std::exception& e) { + std::cerr << e.what() << '\n'; + return 1; + } +} diff --git a/tests/mcp_stdio_test.py b/tests/mcp_stdio_test.py new file mode 100644 index 0000000..f7cc9cb --- /dev/null +++ b/tests/mcp_stdio_test.py @@ -0,0 +1,84 @@ +"""Exercise the real headless Editor over newline-delimited MCP, without a GPU.""" +import json +import pathlib +import queue +import subprocess +import sys +import tempfile +import threading + + +def run(executable, project): + process = subprocess.Popen([executable, "--project", str(project), "--mcp"], + stdin=subprocess.PIPE, stdout=subprocess.PIPE, + stderr=subprocess.PIPE, text=True, encoding="utf-8") + output = queue.Queue() + def reader(): + for line in process.stdout: + output.put(json.loads(line)) # Any non-JSON stdout fails the test. + output.put(None) + threading.Thread(target=reader, daemon=True).start() + sequence = 0 + def request(method, params=None): + nonlocal sequence + sequence += 1 + message = {"jsonrpc": "2.0", "id": sequence, "method": method} + if params is not None: + message["params"] = params + process.stdin.write(json.dumps(message) + "\n") + process.stdin.flush() + result = output.get(timeout=20) + assert result and result["id"] == sequence, result + return result + def call(name, arguments=None, error=False): + response = request("tools/call", {"name": name, "arguments": arguments or {}})["result"] + assert response["isError"] == error, response + return response["structuredContent"] + try: + initialized = request("initialize", {"protocolVersion": "2025-06-18", "capabilities": {}, + "clientInfo": {"name": "faset-integration-test", "version": "1"}}) + assert initialized["result"]["serverInfo"]["name"] == "faset-editor" + process.stdin.write('{"jsonrpc":"2.0","method":"notifications/initialized"}\n') + process.stdin.flush() + names = {tool["name"] for tool in request("tools/list")["result"]["tools"]} + assert {"faset_scene_edit", "faset_export", "faset_job_cancel", "faset_plugins"} <= names + assert "faset_runtime_query" not in names and "faset_editor_capture" not in names + if (project / "Scenes/main.scene.json").exists(): + opened = call("faset_document_open", {"path": "Scenes/main.scene.json"}) + assert opened["scene"]["entities"][0]["name"] == "Door 世界" + return + scene = call("faset_document_create", {"name": "MCP integration", "dimension": 3}) + identity = scene["id"] + edit = {"document": identity, "revision": 0, + "operations": [{"op": "entity.create", "name": "Door 世界"}], + "idempotency_key": "create-door"} + changed = call("faset_scene_edit", edit) + assert call("faset_scene_edit", edit) == changed + conflict = dict(edit) + del conflict["idempotency_key"] + assert call("faset_scene_edit", conflict, True)["error"]["code"] == "revision.conflict" + undone = call("faset_undo", {"document": identity, "revision": 1}) + assert undone["scene"]["entities"] == [] + redone = call("faset_redo", {"document": identity, "revision": 2}) + assert redone["scene"] == changed["scene"] + saved = call("faset_document_save", {"document": identity, "path": "Scenes/main.scene.json"}) + assert not saved["dirty"] + call("faset_document_open", {"path": "../outside.json"}, True) + assert request("resources/read", {"uri": "faset://documents"})["result"]["contents"] + assert request("faset_runtime_query")["error"]["code"] == -32601 + finally: + process.stdin.close() + try: + code = process.wait(timeout=20) + except subprocess.TimeoutExpired: + process.kill() + process.wait() + raise + errors = process.stderr.read() + assert code == 0, errors + + +with tempfile.TemporaryDirectory(prefix="faset-mcp-stdio-") as temporary: + run(sys.argv[1], pathlib.Path(temporary)) + run(sys.argv[1], pathlib.Path(temporary)) +print("Real MCP stdio lifecycle, clean stdout, revision conflict, retry, Undo/Redo, disk reopen and process shutdown passed") diff --git a/tests/mcp_tests.cpp b/tests/mcp_tests.cpp new file mode 100644 index 0000000..e960f70 --- /dev/null +++ b/tests/mcp_tests.cpp @@ -0,0 +1,76 @@ +#include +#include +#include + +#define CHECK(x) \ + do { \ + if (!(x)) \ + throw std::runtime_error("Check failed at " + std::to_string(__LINE__) + ": " #x); \ + } while (false) +int main() { + using namespace faset; + using namespace faset::editor; + const auto root = std::filesystem::temp_directory_path() / ("faset-mcp-" + new_id()); + try { + authoring::AuthoringService service(root); + Commands commands(service); + McpServer server(commands); + auto request = [&](std::string method, Json params = Json::object()) { + auto result = server.handle( + {{"jsonrpc", "2.0"}, {"id", 1}, {"method", method}, {"params", params}}); + CHECK(result.has_value()); + return *result; + }; + CHECK(request("tools/list")["error"]["code"] == -32002); + CHECK(request("initialize", + {{"protocolVersion", "2025-06-18"}, + {"capabilities", Json::object()}, + {"clientInfo", + {{"name", "test"}, {"version", "1"}}}})["result"]["protocolVersion"] == + "2025-06-18"); + CHECK(!server.handle({{"jsonrpc", "2.0"}, {"method", "notifications/initialized"}})); + const auto listed = request("tools/list")["result"]["tools"]; + CHECK(listed.size() >= 10); + for (const auto& tool : listed) { + const std::string name = tool["name"]; + CHECK(name.find("runtime") == std::string::npos); + CHECK(tool["inputSchema"]["additionalProperties"] == false); + } + auto call = [&](std::string name, Json arguments = Json::object()) { + return request("tools/call", {{"name", name}, {"arguments", arguments}})["result"]; + }; + const auto created = + call("faset_document_create", {{"name", "MCP scene"}, {"dimension", 2}}); + CHECK(created["isError"] == false); + const std::string id = created["structuredContent"]["id"]; + Json args = {{"document", id}, + {"revision", 0}, + {"operations", Json::array({{{"op", "entity.create"}, {"name", "Player"}}})}, + {"idempotency_key", "first"}}; + const auto first = call("faset_scene_edit", args); + CHECK(first["isError"] == false); + CHECK(call("faset_scene_edit", args) == first); + args.erase("idempotency_key"); + CHECK(call("faset_scene_edit", args)["structuredContent"]["error"]["code"] == + "revision.conflict"); + CHECK(service.query(id)["scene"] == first["structuredContent"]["scene"]); + CHECK(call("faset_scene_edit", {{"document", id}, + {"revision", -1}, + {"operations", args["operations"]}})["isError"] == true); + CHECK(call("faset_document_open", + {{"path", "../outside.json"}})["structuredContent"]["error"]["code"] == + "path.outside_project"); + CHECK(call("faset_runtime_query")["isError"] == true); + CHECK(request("resources/read", {{"uri", "faset://schema"}}).contains("result")); + CHECK(request("not/a/method")["error"]["code"] == -32601); + CHECK(server.handle(Json::array())->at("error").at("code") == -32600); + std::filesystem::remove_all(root); + std::cout << "MCP lifecycle, shared authoring, retries/conflicts, tool schemas and " + "editor-only boundary passed\n"; + return 0; + } catch (const std::exception& error) { + std::filesystem::remove_all(root); + std::cerr << error.what() << '\n'; + return 1; + } +} diff --git a/tests/plugin_tests.cpp b/tests/plugin_tests.cpp new file mode 100644 index 0000000..6481d0f --- /dev/null +++ b/tests/plugin_tests.cpp @@ -0,0 +1,87 @@ +#include "../examples/extensions/beacon/Beacon.hpp" +#include +#include +#include +#define CHECK(x) \ + do { \ + if (!(x)) \ + throw std::runtime_error("Check failed: " #x); \ + } while (false) +int main() { + using namespace faset; + using namespace faset::editor; + const auto root = std::filesystem::temp_directory_path() / ("faset-plugins-" + new_id()); + try { + std::filesystem::create_directories(root); + const auto folder = root / "Plugins"; + std::filesystem::copy(FASET_TEST_PLUGIN_DIRECTORY, folder, + std::filesystem::copy_options::recursive); + authoring::AuthoringService authoring(root); + authoring.register_schemas(Json::array({beacon::schema()})); + Commands commands(authoring); + const auto document = authoring.create("Extension test"); + const auto id = document.at("id"); + { + PluginManager plugins(commands, [](auto) {}); + plugins.load(folder); + CHECK(plugins.status().size() == 1); + CHECK(plugins.status()[0]["state"] == "loaded"); + CHECK(plugins.panels().size() == 1); + const auto edited = commands.call("plugin_example_beacon_create", {{"document", id}}); + CHECK(edited["revision"] == 1); + CHECK(edited["scene"]["entities"][0]["components"][2]["type"] == "example.beacon"); + authoring.undo(id, 1); + CHECK(authoring.query(id)["scene"]["entities"].empty()); + authoring.redo(id, 2); + authoring.save(id, "Scenes/plugin.scene.json"); + // The extension's runtime component runs without loading its Editor DLL/SO. + runtime::Runtime world; + beacon::register_behavior(world); + world.load(edited.at("scene")); + world.advance(1.0 / 60); + CHECK(world.transform(world.find(edited["scene"]["entities"][0]["id"])).rotation[1] > + 0); + } + for (const auto& command : commands.list()) + CHECK(command["name"] != "plugin_example_beacon_create"); + authoring::AuthoringService absent(root); + CHECK(absent.open("Scenes/plugin.scene.json")["scene"]["entities"][0]["components"][2] + ["fields"]["speed"] == 1.0); + const auto file = folder / "beacon.faset-plugin.json"; + const auto original = read_json(file); + auto wrong = original; + wrong["build_fingerprint"] = "wrong-build"; + atomic_write_json(file, wrong); + { + PluginManager plugins(commands, [](auto) {}); + plugins.load(folder); + CHECK(plugins.status()[0]["state"] == "failed"); + CHECK(plugins.panels().empty()); + } + auto cycle = original; + cycle["dependencies"] = Json::array({{{"id", "example.beacon"}, {"version", "1.0.0"}}}); + atomic_write_json(file, cycle); + { + PluginManager plugins(commands, [](auto) {}); + plugins.load(folder); + CHECK(plugins.status()[0]["state"] == "failed"); + CHECK(plugins.panels().empty()); + } + auto missing = original; + missing["dependencies"] = Json::array({{{"id", "missing"}, {"version", "1.0.0"}}}); + atomic_write_json(file, missing); + { + PluginManager plugins(commands, [](auto) {}); + plugins.load(folder); + CHECK(plugins.status()[0]["state"] == "failed"); + } + std::filesystem::remove_all(root); + std::cout << "Native plugin ABI, ownership, commands, runtime component, missing package " + "preservation and dependency validation passed\n"; + return 0; + } catch (const std::exception& error) { + std::filesystem::remove_all(root); + std::cerr << error.what() << '\n'; + return 1; + } +} diff --git a/tests/render_tests.cpp b/tests/render_tests.cpp index 8457eb3..389c038 100644 --- a/tests/render_tests.cpp +++ b/tests/render_tests.cpp @@ -1,26 +1,132 @@ -#include -#include #include +#include +#include #include #include using namespace faset::render; -void require(bool test,const char* message){if(!test)throw std::runtime_error(message);} -int main(int argc,char** argv){try{ - if(argc>1&&std::string(argv[1])=="--unit"){ - int count{};RenderGraph invalid;invalid.add("consumer",{"missing"},{},[&]{++count;});bool caught{};try{invalid.execute();}catch(const std::runtime_error&){caught=true;}require(caught&&count==0,"Graph must validate before side effects");RenderGraph graph;graph.import("external");graph.add("first",{"external"},{"color"},[&]{require(count==0,"Pass order");++count;});graph.add("second",{"color"},{},[&]{++count;});graph.execute();require(count==2,"Pass execution count");auto t=transform({2,3,4},{},{2,3,4});require(t[12]==2&&t[13]==3&&t[14]==4,"Transform translation");auto m=multiply(identity,t);require(m==t,"Matrix multiplication identity");require(cube_mesh()->indices.size()==36,"Cube triangle topology");std::cout<<"Render graph and math contracts passed\n";return 0; +void require(bool test, const char* message) { + if (!test) + throw std::runtime_error(message); +} +int main(int argc, char** argv) { + try { + if (argc > 1 && std::string(argv[1]) == "--unit") { + int count{}; + RenderGraph invalid; + invalid.add("consumer", {"missing"}, {}, [&] { ++count; }); + bool caught{}; + try { + invalid.execute(); + } catch (const std::runtime_error&) { + caught = true; + } + require(caught && count == 0, "Graph must validate before side effects"); + RenderGraph graph; + graph.import("external"); + graph.add("first", {"external"}, {"color"}, [&] { + require(count == 0, "Pass order"); + ++count; + }); + graph.add("second", {"color"}, {}, [&] { ++count; }); + graph.execute(); + require(count == 2, "Pass execution count"); + auto t = transform({2, 3, 4}, {}, {2, 3, 4}); + require(t[12] == 2 && t[13] == 3 && t[14] == 4, "Transform translation"); + auto m = multiply(identity, t); + require(m == t, "Matrix multiplication identity"); + require(cube_mesh()->indices.size() == 36, "Cube triangle topology"); + std::cout << "Render graph and math contracts passed\n"; + return 0; + } + bool visible = argc > 1 && std::string(argv[1]) == "--visible"; + Renderer renderer({320, 240, "Faset render validation", !visible, true}); + Snapshot scene; + scene.eye = {4, 3, 5}; + scene.view_projection = + multiply(perspective(.85f, 320.f / 240.f, .1f, 100), look_at(scene.eye, {0, 0, 0})); + scene.draws.push_back( + {cube_mesh(), transform({0, 0, 0}), {.2f, .65f, .95f, 1}, .4f, .15f, true}); + scene.draws.push_back({cube_mesh(), + transform({0, -1, 0}, {}, {10, 1, 10}), + {.45f, .48f, .5f, 1}, + .8f, + 0, + true}); + scene.ui_quads.push_back({8, 8, 70, 16, {.8f, .1f, .15f, 1}}); + auto texture = std::make_shared(); + texture->width = texture->height = 1; + texture->rgba = {20, 220, 40, 255}; + scene.ui_quads.push_back({260, 8, 40, 20, {1, 1, 1, 1}, texture}); + renderer.render(scene); + require(renderer.stats().validation_errors == 0, "Vulkan validation reported an error"); + auto pixels = renderer.pixels(); + require(pixels.size() == 320 * 240 * 4, "Readback dimensions"); + auto index = (10 * 320 + 10) * 4; + require(pixels[index] > 190 && pixels[index + 1] < 50, "Colored UI pixel"); + index = (10 * 320 + 270) * 4; + require(pixels[index] < 30 && pixels[index + 1] > 200, "Textured UI pixel"); + texture->srgb = true; + ++texture->revision; + renderer.render(scene); + auto srgb_pixels = renderer.pixels(); + require(std::abs(int(srgb_pixels[index + 1]) - 220) <= 1, + "Unlit sRGB texture retains its display-space color"); + texture->srgb = false; + ++texture->revision; + auto baked_scene = scene; + auto baked_mesh = std::make_shared(*cube_mesh()); + for (auto& vertex : baked_mesh->vertices) { + vertex.position[0] *= 10; + vertex.position[2] *= 10; + } + baked_scene.draws[1].mesh = baked_mesh; + baked_scene.draws[1].model = transform({0, -1, 0}); + renderer.render(baked_scene); + auto baked_pixels = renderer.pixels(); + std::size_t normal_difference{}; + for (std::size_t i = 0; i < pixels.size(); ++i) + if (std::abs(int(pixels[i]) - int(baked_pixels[i])) > 2) + ++normal_difference; + require(normal_difference < 10, + "Nonuniformly scaled normals must match baked geometry lighting"); + auto shadowed = pixels; + if (argc > 2) + renderer.capture(std::string(argv[2]) + ".shadowed.ppm"); + for (auto& draw : scene.draws) + draw.cast_shadow = false; + renderer.render(scene); + pixels = renderer.pixels(); + std::size_t shadow_difference{}; + for (std::size_t i = 0; i < pixels.size(); i += 4) + if (pixels[i] > shadowed[i] + 8) + ++shadow_difference; + if (shadow_difference <= 20) { + std::cerr << "Shadow difference pixels: " << shadow_difference << "\n"; + if (argc > 2) + renderer.capture(std::string(argv[2]) + ".unshadowed.ppm"); + } + require(shadow_difference > 20, "Directional shadow must darken rendered surface pixels"); + for (auto& draw : scene.draws) + draw.cast_shadow = true; + std::string reload_error; + require(renderer.reload_shaders(reload_error), "Compatible shader pipeline reload"); + texture->rgba = {40, 30, 230, 255}; + ++texture->revision; + renderer.render(scene); + pixels = renderer.pixels(); + require(pixels[index + 2] > 220, "Texture revision upload"); + if (argc > 2) + renderer.capture(argv[2]); + renderer.resize(400, 300); + renderer.poll_events(); + renderer.render(scene); + require(renderer.width() == 400 && renderer.height() == 300, "Render target resize"); + require(renderer.stats().validation_errors == 0, "Resize validation error"); + std::cout << "Vulkan frame, shadow/PBR, atlas upload, readback and resize passed on " + << renderer.stats().device << '\n'; + } catch (const std::exception& e) { + std::cerr << e.what() << '\n'; + return 1; } - bool visible=argc>1&&std::string(argv[1])=="--visible"; - Renderer renderer({320,240,"Faset render validation",!visible,true}); - Snapshot scene;scene.eye={4,3,5};scene.view_projection=multiply(perspective(.85f,320.f/240.f,.1f,100),look_at(scene.eye,{0,0,0}));scene.draws.push_back({cube_mesh(),transform({0,0,0}),{.2f,.65f,.95f,1},.4f,.15f,true});scene.draws.push_back({cube_mesh(),transform({0,-1,0},{},{8,.2f,8}),{.45f,.48f,.5f,1},.8f,0,true});scene.ui_quads.push_back({8,8,70,16,{.8f,.1f,.15f,1}}); - auto texture=std::make_shared();texture->width=texture->height=1;texture->rgba={20,220,40,255};scene.ui_quads.push_back({260,8,40,20,{1,1,1,1},texture}); - renderer.render(scene);require(renderer.stats().validation_errors==0,"Vulkan validation reported an error");auto pixels=renderer.pixels();require(pixels.size()==320*240*4,"Readback dimensions");auto index=(10*320+10)*4;require(pixels[index]>190&&pixels[index+1]<50,"Colored UI pixel");index=(10*320+270)*4;require(pixels[index]<30&&pixels[index+1]>200,"Textured UI pixel"); - auto shadowed=pixels; - if(argc>2)renderer.capture(std::string(argv[2])+".shadowed.ppm"); - for(auto& draw:scene.draws)draw.cast_shadow=false; - renderer.render(scene);pixels=renderer.pixels();std::size_t shadow_difference{};for(std::size_t i=0;ishadowed[i]+8)++shadow_difference;if(shadow_difference<=20){std::cerr<<"Shadow difference pixels: "<2)renderer.capture(std::string(argv[2])+".unshadowed.ppm");}require(shadow_difference>20,"Directional shadow must darken rendered surface pixels"); - for(auto& draw:scene.draws)draw.cast_shadow=true; - std::string reload_error;require(renderer.reload_shaders(reload_error),"Compatible shader pipeline reload"); - texture->rgba={40,30,230,255};++texture->revision;renderer.render(scene);pixels=renderer.pixels();require(pixels[index+2]>220,"Texture revision upload"); - if(argc>2)renderer.capture(argv[2]);renderer.resize(400,300);renderer.poll_events();renderer.render(scene);require(renderer.width()==400&&renderer.height()==300,"Render target resize");require(renderer.stats().validation_errors==0,"Resize validation error"); - std::cout<<"Vulkan frame, shadow/PBR, atlas upload, readback and resize passed on "< +#include +#include +#include +#include +#include +#include +#include + +using Json = nlohmann::json; +namespace { +void check(bool value, const char* message) { + if (!value) + throw std::runtime_error(message); +} +template void rejects(F&& function, const char* message) { + bool caught = false; + try { + function(); + } catch (const std::exception&) { + caught = true; + } + check(caught, message); +} +Json component(std::string type, Json fields) { + return {{"id", type}, {"type", type}, {"version", 1}, {"fields", fields}}; +} +Json entity(std::string id, Json parent, Json components) { + return {{"id", id}, {"name", id}, {"parent", parent}, {"components", components}}; +} +void run() { + const auto folder = + std::filesystem::temp_directory_path() / ("faset-player-test-" + faset::new_id()); + std::filesystem::create_directories(folder); + struct Cleanup { + std::filesystem::path path; + ~Cleanup() { + std::error_code error; + std::filesystem::remove_all(path, error); + } + } cleanup{folder}; + Json scene{ + {"format", "faset.scene"}, + {"version", 1}, + {"id", "test"}, + {"name", "Test"}, + {"dimension", 3}, + {"instances", Json::array()}, + {"entities", + Json::array( + {entity("parent", nullptr, + Json::array({component("faset.transform", {{"position", {1, 2, 3}}})})), + entity("child", "parent", + Json::array({component("faset.transform", {{"position", {2, 0, 0}}}), + component("faset.mesh", {{"asset", "builtin:cube"}})}))})}}; + faset::atomic_write_json(folder / "scene.json", scene); + check(faset::player::readScene(folder / "scene.json") == scene, "JSON scene roundtrip"); + const auto cbor = Json::to_cbor(scene); + std::string cooked = "FASETSCN"; + for (int i = 0; i < 4; ++i) + cooked.push_back(static_cast(std::uint32_t{1} >> (8 * i))); + for (int i = 0; i < 8; ++i) + cooked.push_back(static_cast(std::uint64_t(cbor.size()) >> (8 * i))); + cooked.append(reinterpret_cast(cbor.data()), cbor.size()); + faset::atomic_write(folder / "scene.fscene", cooked); + check(faset::player::readScene(folder / "scene.fscene") == scene, + "CBOR cooked scene roundtrip"); + auto truncated = cooked.substr(0, cooked.size() - 1); + faset::atomic_write(folder / "truncated.fscene", truncated); + rejects([&] { faset::player::readScene(folder / "truncated.fscene"); }, + "reject cooked size mismatch"); + auto version = cooked; + version[8] = 2; + faset::atomic_write(folder / "version.fscene", version); + rejects([&] { faset::player::readScene(folder / "version.fscene"); }, "reject cooked version"); + faset::player::SceneView view(folder); + auto snapshot = view.build(scene, 16.f / 9.f); + check(snapshot.draws.size() == 1, "SceneView builtin mesh"); + check(snapshot.draws[0].model[12] == 3 && snapshot.draws[0].model[13] == 2 && + snapshot.draws[0].model[14] == 3, + "hierarchy local transforms composed"); + faset::runtime::Runtime world; + world.load(scene); + auto pose = world.transform(world.find("child")); + pose.position[0] = 5; + world.setTransform(world.find("child"), pose); + snapshot = view.build(world.snapshotJson(), 1); + check(snapshot.draws[0].model[12] == 6, + "runtime presentation overrides original authoring pose"); + auto bad = scene; + bad["entities"][0]["parent"] = "child"; + rejects([&] { view.build(bad, 1); }, "view rejects hierarchy cycle"); + bad = scene; + bad["entities"][1]["components"][1]["fields"]["asset"] = "missing-asset"; + view.build(bad, 1); + check(!view.diagnostics().empty() && view.diagnostics()[0].starts_with("error:"), + "missing asset is diagnostic, not silent success"); + auto camera = faset::player::CameraSettings{}; + camera.eye = camera.target; + rejects([&] { view.build(scene, 1, camera); }, "reject degenerate camera"); + auto two = scene; + two["dimension"] = 2; + two["entities"] = Json::array( + {entity("high", nullptr, + Json::array({component("faset.sprite", {{"layer", 10}, {"color", {1, 0, 0, 1}}})})), + entity( + "low", nullptr, + Json::array({component("faset.sprite", {{"layer", 0}, {"color", {0, 1, 0, 1}}})}))}); + snapshot = view.build(two, 1); + check(snapshot.sprites.size() == 2 && snapshot.sprites[0].color[1] == 1, + "2D sprites sorted by layer"); + + // Import a real textured glTF fixture, then consume only its cooked generation. + std::string geometry; + auto word = [&](std::uint32_t v) { + for (int i = 0; i < 4; ++i) + geometry.push_back(static_cast(v >> (8 * i))); + }; + for (float value : {0.f, 0.f, 0.f, 1.f, 0.f, 0.f, 0.f, 1.f, 0.f}) + word(std::bit_cast(value)); + for (char value : {0, 0, 1, 0, 2, 0}) + geometry.push_back(value); + faset::atomic_write(folder / "geometry.bin", geometry); + const std::vector png{ + 137, 80, 78, 71, 13, 10, 26, 10, 0, 0, 0, 13, 73, 72, 68, 82, 0, 0, + 0, 1, 0, 0, 0, 1, 8, 6, 0, 0, 0, 31, 21, 196, 137, 0, 0, 0, + 13, 73, 68, 65, 84, 120, 156, 99, 248, 16, 32, 242, 31, 0, 5, 220, 2, 84, + 184, 210, 98, 74, 0, 0, 0, 0, 73, 69, 78, 68, 174, 66, 96, 130}; + faset::atomic_write(folder / "pixel.png", + std::string_view(reinterpret_cast(png.data()), png.size())); + Json gltf = { + {"asset", {{"version", "2.0"}}}, + {"scene", 0}, + {"scenes", Json::array({{{"nodes", Json::array({0})}}})}, + {"nodes", Json::array({{{"mesh", 0}, {"translation", {2, 0, 0}}}})}, + {"buffers", Json::array({{{"uri", "geometry.bin"}, {"byteLength", 42}}})}, + {"bufferViews", Json::array({{{"buffer", 0}, {"byteOffset", 0}, {"byteLength", 36}}, + {{"buffer", 0}, {"byteOffset", 36}, {"byteLength", 6}}})}, + {"accessors", + Json::array( + {{{"bufferView", 0}, + {"componentType", 5126}, + {"count", 3}, + {"type", "VEC3"}, + {"min", {0, 0, 0}}, + {"max", {1, 1, 0}}}, + {{"bufferView", 1}, {"componentType", 5123}, {"count", 3}, {"type", "SCALAR"}}})}, + {"meshes", Json::array({{{"primitives", Json::array({{{"attributes", {{"POSITION", 0}}}, + {"indices", 1}, + {"material", 0}}})}}})}, + {"materials", Json::array({{{"pbrMetallicRoughness", + {{"baseColorFactor", {1, 1, 1, 1}}, + {"baseColorTexture", {{"index", 0}}}, + {"metallicFactor", 0}, + {"roughnessFactor", 0.5}}}}})}, + {"images", Json::array({{{"uri", "pixel.png"}}})}, + {"textures", Json::array({{{"source", 0}}})}}; + faset::atomic_write_json(folder / "triangle.gltf", gltf); + faset::assets::AssetPipeline pipeline(folder); + auto imported = pipeline.import_asset({folder / "triangle.gltf"}); + check(imported.ok(), "real textured glTF fixture import"); + auto importedScene = scene; + importedScene["entities"][1]["components"][1]["fields"]["asset"] = imported.asset_id; + snapshot = view.build(importedScene, 1); + check(view.diagnostics().empty(), "valid cooked texture/material produces no error"); + check(snapshot.draws.size() == 1 && snapshot.draws[0].mesh->vertices.size() == 3, + "cooked mesh reaches render snapshot"); + check(snapshot.draws[0].model[12] == 5, "asset node transform composed with scene hierarchy"); + check(snapshot.draws[0].texture && snapshot.draws[0].texture->srgb && + snapshot.draws[0].texture->rgba == std::vector({240, 80, 20, 255}), + "PNG decoded into sRGB base-color texture"); +} +} // namespace +int main() { + try { + run(); + std::cout << "Player JSON/CBOR, hierarchy, runtime snapshot, camera, sprite ordering and " + "asset error contracts passed\n"; + return 0; + } catch (const std::exception& error) { + std::cerr << error.what() << '\n'; + return 1; + } +} diff --git a/tests/runtime_tests.cpp b/tests/runtime_tests.cpp index ac48c2f..5618e76 100644 --- a/tests/runtime_tests.cpp +++ b/tests/runtime_tests.cpp @@ -1,6 +1,6 @@ -#include #include "Gameplay.hpp" #include +#include #include #include #include @@ -8,82 +8,321 @@ #include using namespace faset::runtime; -using Json=nlohmann::json; +using Json = nlohmann::json; namespace { -void check(bool result,const char* text){if(!result)throw std::runtime_error(text);} -void near(float actual,float expected,float tolerance,const char* text){check(std::abs(actual-expected)void rejects(F&& fn,const char* message){bool caught=false;try{fn();}catch(const std::exception&){caught=true;}check(caught,message);} -Json component(std::string type,Json fields=Json::object()){return {{"id",type+"-id"},{"type",type},{"version",1},{"fields",fields}};} -Json entity(std::string id,float y=0){return {{"id",id},{"name",id},{"parent",nullptr},{"components",Json::array({component("faset.transform",{{"position",{0,y,0}}})})}};} -Json scene(int dim=2){return {{"format","faset.scene"},{"version",1},{"id","test-scene"},{"name","Test"},{"dimension",dim},{"entities",Json::array()},{"instances",Json::array()}};} -void physics(int dimension){ - Runtime world;auto doc=scene(dimension);auto floor=entity("ground",-0.5f);auto falling=entity("falling",4); - auto type=dimension==2?"faset.rigid_body_2d":"faset.rigid_body_3d"; - Json extents=dimension==2?Json{10,0.5}:Json{10,0.5,10}; - floor["components"].push_back(component(type,{{"body_type","static"},{"half_extents",extents}})); - falling["components"].push_back(component(type));doc["entities"]=Json::array({floor,falling});world.load(doc);auto h=world.find("falling"); - bool contact=false; - for(int i=0;i<240;++i){world.advance(1.0/60);for(const auto& event:world.collisions())contact=contact||event.began;} - near(world.transform(h).position[1],0.5f,0.09f,"body must fall and settle on actual solver floor");check(contact,"native contact event must be delivered"); - auto pose=world.transform(h);pose.position[1]=6;world.teleport(h,pose); - near(world.presentation(h).position[1],6,0.0001f,"teleport resets interpolation"); - rejects([&]{world.setTransform(h,pose);},"physics transform cannot be casually overwritten"); - world.applyImpulse(h,{0,2,0});check(world.velocity(h)[1]>0,"impulse changes solver velocity"); +void check(bool result, const char* text) { + if (!result) + throw std::runtime_error(text); } -void lifecycle(){ - Runtime world;std::vector events;bool spawned=false;float presented=-1;int pressedTicks=0; +void near(float actual, float expected, float tolerance, const char* text) { + check(std::abs(actual - expected) < tolerance, text); +} +template void rejects(F&& fn, const char* message) { + bool caught = false; + try { + fn(); + } catch (const std::exception&) { + caught = true; + } + check(caught, message); +} +Json component(std::string type, Json fields = Json::object()) { + return {{"id", type + "-id"}, {"type", type}, {"version", 1}, {"fields", fields}}; +} +Json entity(std::string id, float y = 0) { + return {{"id", id}, + {"name", id}, + {"parent", nullptr}, + {"components", Json::array({component("faset.transform", {{"position", {0, y, 0}}})})}}; +} +Json scene(int dim = 2) { + return {{"format", "faset.scene"}, {"version", 1}, + {"id", "test-scene"}, {"name", "Test"}, + {"dimension", dim}, {"entities", Json::array()}, + {"instances", Json::array()}}; +} +void physics(int dimension) { + Runtime world; + auto doc = scene(dimension); + auto floor = entity("ground", -0.5f); + auto falling = entity("falling", 4); + auto type = dimension == 2 ? "faset.rigid_body_2d" : "faset.rigid_body_3d"; + Json extents = dimension == 2 ? Json{10, 0.5} : Json{10, 0.5, 10}; + floor["components"].push_back( + component(type, {{"body_type", "static"}, {"half_extents", extents}})); + falling["components"].push_back(component(type)); + doc["entities"] = Json::array({floor, falling}); + world.load(doc); + auto h = world.find("falling"); + bool contact = false; + for (int i = 0; i < 240; ++i) { + world.advance(1.0 / 60); + for (const auto& event : world.collisions()) + contact = contact || event.began; + } + near(world.transform(h).position[1], 0.5f, 0.09f, + "body must fall and settle on actual solver floor"); + check(contact, "native contact event must be delivered"); + check(world.grounded(h), "settled body must have a supporting native contact"); + auto pose = world.transform(h); + pose.position[1] = 6; + world.teleport(h, pose); + near(world.presentation(h).position[1], 6, 0.0001f, "teleport resets interpolation"); + check(!world.grounded(h), "teleport off the floor removes grounded state"); + rejects([&] { world.setTransform(h, pose); }, + "physics transform cannot be casually overwritten"); + world.applyImpulse(h, {0, 2, 0}); + check(world.velocity(h)[1] > 0, "impulse changes solver velocity"); +} +void lifecycle() { + Runtime world; + std::vector events; + bool spawned = false; + float presented = -1; + int pressedTicks = 0; Behavior behavior; - behavior.onStart=[&](Runtime&,EntityHandle,double){events.push_back("start");}; - behavior.fixedUpdate=[&](Runtime& r,EntityHandle h,double){events.push_back("fixed");if(r.input().jumpPressed)++pressedTicks;auto t=r.transform(h);t.position[0]+=1;r.setTransform(h,t);if(!spawned){r.spawn(entity("spawned"));spawned=true;}}; - behavior.update=[&](Runtime&,EntityHandle,double){events.push_back("update");}; - behavior.lateUpdate=[&](Runtime& r,EntityHandle h,double){events.push_back("late");presented=r.presentation(h).position[0];}; - behavior.onDestroy=[&](Runtime& r,EntityHandle h,double){check(r.valid(h),"OnDestroy still sees a valid handle");events.push_back("destroy");}; - world.registerBehavior("test.behavior",behavior);auto doc=scene();auto object=entity("main");object["components"].push_back(component("test.behavior"));doc["entities"].push_back(object);world.load(doc); - check(events==std::vector{"start"},"load runs OnStart once"); - world.advance(1.0/120,{0,0,true,false});check(!world.find("spawned"),"zero-tick frame applies no structural commands"); - world.advance(1.0/60);check(!world.find("spawned"),"FixedUpdate spawn must wait until next tick");near(presented,0.5f,0.001f,"LateUpdate receives interpolated transform");check(pressedTicks==1,"input edge preserved across zero-tick frame"); - world.advance(3.0/60);check(bool(world.find("spawned")),"spawn appears next tick");check(pressedTicks==1,"edge not repeated in catchup ticks"); - auto old=world.find("main");world.destroy(old);check(world.valid(old),"destroy deferred");world.singleStep();check(!world.valid(old),"handle invalid after removal"); - check(events.back()=="destroy","destroy lifecycle runs exactly at barrier"); - world.spawn(entity("replacement"));world.singleStep();check(!world.valid(old),"reused slot never revives a stale handle"); - auto replacement=world.find("replacement");world.load(doc);check(!world.valid(replacement),"load creates a new session"); + behavior.onStart = [&](Runtime&, EntityHandle, double) { events.push_back("start"); }; + behavior.fixedUpdate = [&](Runtime& r, EntityHandle h, double) { + events.push_back("fixed"); + if (r.input().jumpPressed) + ++pressedTicks; + auto t = r.transform(h); + t.position[0] += 1; + r.setTransform(h, t); + if (!spawned) { + r.spawn(entity("spawned")); + spawned = true; + } + }; + behavior.update = [&](Runtime&, EntityHandle, double) { events.push_back("update"); }; + behavior.lateUpdate = [&](Runtime& r, EntityHandle h, double) { + events.push_back("late"); + presented = r.presentation(h).position[0]; + }; + behavior.onDestroy = [&](Runtime& r, EntityHandle h, double) { + check(r.valid(h), "OnDestroy still sees a valid handle"); + events.push_back("destroy"); + }; + world.registerBehavior("test.behavior", behavior); + auto doc = scene(); + auto object = entity("main"); + object["components"].push_back(component("test.behavior")); + doc["entities"].push_back(object); + world.load(doc); + check(events == std::vector{"start"}, "load runs OnStart once"); + world.advance(1.0 / 120, {0, 0, true, false}); + check(!world.find("spawned"), "zero-tick frame applies no structural commands"); + world.advance(1.0 / 60); + check(!world.find("spawned"), "FixedUpdate spawn must wait until next tick"); + near(presented, 0.5f, 0.001f, "LateUpdate receives interpolated transform"); + check(pressedTicks == 1, "input edge preserved across zero-tick frame"); + world.advance(3.0 / 60); + check(bool(world.find("spawned")), "spawn appears next tick"); + check(pressedTicks == 1, "edge not repeated in catchup ticks"); + auto old = world.find("main"); + world.destroy(old); + check(world.valid(old), "destroy deferred"); + world.singleStep(); + check(!world.valid(old), "handle invalid after removal"); + check(events.back() == "destroy", "destroy lifecycle runs exactly at barrier"); + world.spawn(entity("replacement")); + world.singleStep(); + check(!world.valid(old), "reused slot never revives a stale handle"); + auto replacement = world.find("replacement"); + world.load(doc); + check(!world.valid(replacement), "load creates a new session"); // Ensure captured state remains alive while Runtime's destructor calls OnDestroy. world.clear(); } -void clockAndValidation(){ - Runtime world;auto doc=scene();doc["entities"].push_back(entity("object"));world.load(doc); - auto stats=world.advance(1.0);check(stats.fixedTicks==4,"catchup bounded to four ticks");check(stats.droppedTime>0.9,"excess time reported");check(stats.interpolationAlpha>=0&&stats.interpolationAlpha<1,"interpolation fraction bounded"); - auto tick=stats.tick;world.setPaused(true);world.advance(100);check(world.snapshot().tick==tick,"pause does not accumulate");world.singleStep();check(world.snapshot().tick==tick+1,"single-step advances exactly once");world.setPaused(false);check(world.advance(0).fixedTicks==0,"resume does not catch up pause"); - auto old=world.find("object");auto invalid=doc;invalid["entities"][0]["parent"]="object";rejects([&]{world.load(invalid);},"reject hierarchy cycle");check(world.valid(old),"invalid load preserves old world"); - invalid=doc;invalid["entities"][0]["components"].push_back(component("faset.rigid_body_3d"));rejects([&]{world.load(invalid);},"reject physics dimension mismatch"); - rejects([&]{world.advance(-1);},"reject negative time"); - world.addComponent(old,component("faset.sprite"));check(!world.snapshot().entities[0].sprite,"component addition deferred");world.singleStep();check(world.snapshot().entities[0].sprite.has_value(),"component added at barrier");world.removeComponent(old,"faset.sprite");world.singleStep();check(!world.snapshot().entities[0].sprite,"component removed at barrier"); - Runtime other;other.load(doc);check(!other.valid(old),"handle cannot cross worlds"); - auto schema=faset::gameplay::schema();check(schema.size()==2,"sample has explicit metadata without world"); +void clockAndValidation() { + Runtime world; + auto doc = scene(); + doc["entities"].push_back(entity("object")); + world.load(doc); + auto stats = world.advance(1.0); + check(stats.fixedTicks == 4, "catchup bounded to four ticks"); + check(stats.droppedTime > 0.9, "excess time reported"); + check(stats.interpolationAlpha >= 0 && stats.interpolationAlpha < 1, + "interpolation fraction bounded"); + auto tick = stats.tick; + world.setPaused(true); + world.advance(100); + check(world.snapshot().tick == tick, "pause does not accumulate"); + world.singleStep(); + check(world.snapshot().tick == tick + 1, "single-step advances exactly once"); + world.setPaused(false); + check(world.advance(0).fixedTicks == 0, "resume does not catch up pause"); + auto old = world.find("object"); + auto invalid = doc; + invalid["entities"][0]["parent"] = "object"; + rejects([&] { world.load(invalid); }, "reject hierarchy cycle"); + check(world.valid(old), "invalid load preserves old world"); + invalid = doc; + invalid["entities"][0]["components"].push_back(component("faset.rigid_body_3d")); + rejects([&] { world.load(invalid); }, "reject physics dimension mismatch"); + rejects([&] { world.advance(-1); }, "reject negative time"); + world.addComponent(old, component("faset.sprite")); + check(!world.snapshot().entities[0].sprite, "component addition deferred"); + world.singleStep(); + check(world.snapshot().entities[0].sprite.has_value(), "component added at barrier"); + world.removeComponent(old, "faset.sprite"); + world.singleStep(); + check(!world.snapshot().entities[0].sprite, "component removed at barrier"); + Runtime other; + other.load(doc); + check(!other.valid(old), "handle cannot cross worlds"); + auto schema = faset::gameplay::schema(); + check(schema.size() == 2, "sample has explicit metadata without world"); } -void structuralFailuresAndCallbacks(){ - Runtime world;auto doc=scene();doc["entities"].push_back(entity("object"));world.load(doc);auto h=world.find("object"); - world.addComponent(h,component("faset.sprite",{{"size",{-1,2}}}));world.singleStep();check(!world.snapshot().entities[0].sprite,"invalid deferred component leaves entity unchanged");check(!world.diagnostics().empty(),"invalid deferred command reports diagnostic"); - auto zero=world.transform(h);zero.scale[0]=0;world.setTransform(h,zero);world.addComponent(h,component("faset.rigid_body_2d"));world.singleStep();rejects([&]{world.fields(h,"faset.rigid_body_2d");},"invalid runtime collider scale must not half-add component"); - zero.scale[0]=1;world.setTransform(h,zero);world.addComponent(h,component("faset.rigid_body_2d"));world.singleStep();check(world.velocity(h)[1]<0,"deferred body runs actual physics"); - world.removeComponent(h,"faset.rigid_body_2d");world.singleStep();rejects([&]{world.velocity(h);},"removed physics adapter no longer accessible"); - world.destroy(h);world.destroy(h);world.singleStep();check(!world.valid(h),"repeated deferred destroy is safe"); - rejects([&]{world.advance(std::numeric_limits::quiet_NaN());},"nonfinite time rejected"); - rejects([&]{world.advance(0,{std::numeric_limits::infinity(),0,false,false});},"nonfinite input rejected"); - Runtime callbacks;std::vector order; - Behavior b;b.onStart=[&](Runtime& r,EntityHandle,double){order.push_back("start");rejects([&]{r.singleStep();},"OnStart cannot recursively advance");}; - b.fixedUpdate=[&](Runtime&,EntityHandle,double){order.push_back("fixed");throw std::runtime_error("intentional callback failure");}; - b.update=[&](Runtime&,EntityHandle,double){order.push_back("update");}; - b.lateUpdate=[&](Runtime& r,EntityHandle h,double){order.push_back("late");auto p=r.presentation(h);p.position[2]=9;r.setPresentation(h,p);}; - callbacks.registerBehavior("test",b);auto object=entity("callbacks");object["components"].push_back(component("test"));doc["entities"]=Json::array({object});callbacks.load(doc);callbacks.singleStep(); - check(order==std::vector{"start","fixed","update","late"},"callback failure does not skip remaining phases");check(callbacks.diagnostics().size()==1,"callback exception diagnostic");near(callbacks.snapshot().entities[0].transform.position[2],9,0.001f,"LateUpdate changes final presentation only");near(callbacks.transform(callbacks.find("callbacks")).position[2],0,0.001f,"presentation does not overwrite simulation");callbacks.clear(); +void structuralFailuresAndCallbacks() { + Runtime world; + auto doc = scene(); + doc["entities"].push_back(entity("object")); + world.load(doc); + auto h = world.find("object"); + world.addComponent(h, component("faset.sprite", {{"size", {-1, 2}}})); + world.singleStep(); + check(!world.snapshot().entities[0].sprite, + "invalid deferred component leaves entity unchanged"); + check(!world.diagnostics().empty(), "invalid deferred command reports diagnostic"); + auto zero = world.transform(h); + zero.scale[0] = 0; + world.setTransform(h, zero); + world.addComponent(h, component("faset.rigid_body_2d")); + world.singleStep(); + rejects([&] { world.fields(h, "faset.rigid_body_2d"); }, + "invalid runtime collider scale must not half-add component"); + zero.scale[0] = 1; + world.setTransform(h, zero); + world.addComponent(h, component("faset.rigid_body_2d")); + world.singleStep(); + check(world.velocity(h)[1] < 0, "deferred body runs actual physics"); + world.removeComponent(h, "faset.rigid_body_2d"); + world.singleStep(); + rejects([&] { world.velocity(h); }, "removed physics adapter no longer accessible"); + world.destroy(h); + world.destroy(h); + world.singleStep(); + check(!world.valid(h), "repeated deferred destroy is safe"); + rejects([&] { world.advance(std::numeric_limits::quiet_NaN()); }, + "nonfinite time rejected"); + rejects([&] { world.advance(0, {std::numeric_limits::infinity(), 0, false, false}); }, + "nonfinite input rejected"); + Runtime callbacks; + std::vector order; + Behavior b; + b.onStart = [&](Runtime& r, EntityHandle, double) { + order.push_back("start"); + rejects([&] { r.singleStep(); }, "OnStart cannot recursively advance"); + }; + b.fixedUpdate = [&](Runtime&, EntityHandle, double) { + order.push_back("fixed"); + throw std::runtime_error("intentional callback failure"); + }; + b.update = [&](Runtime&, EntityHandle, double) { order.push_back("update"); }; + b.lateUpdate = [&](Runtime& r, EntityHandle h, double) { + order.push_back("late"); + auto p = r.presentation(h); + p.position[2] = 9; + r.setPresentation(h, p); + }; + callbacks.registerBehavior("test", b); + auto object = entity("callbacks"); + object["components"].push_back(component("test")); + doc["entities"] = Json::array({object}); + callbacks.load(doc); + callbacks.singleStep(); + check(order == std::vector{"start", "fixed", "update", "late"}, + "callback failure does not skip remaining phases"); + check(callbacks.diagnostics().size() == 1, "callback exception diagnostic"); + near(callbacks.snapshot().entities[0].transform.position[2], 9, 0.001f, + "LateUpdate changes final presentation only"); + near(callbacks.transform(callbacks.find("callbacks")).position[2], 0, 0.001f, + "presentation does not overwrite simulation"); + callbacks.clear(); } -void sampleGameplay(){ - Runtime world;faset::gameplay::registerGameplay(world);auto doc=scene(3);auto door=entity("door");door["components"].push_back(component("gameplay.door",{{"speed",2.0}}));doc["entities"]=Json::array({door});world.load(doc); - world.advance(1.0/60,{0,0,false,true});for(int i=0;i<59;++i)world.advance(1.0/60); - near(world.transform(world.find("door")).rotation[1],1.5707963f,0.001f,"sample door opens through real static gameplay callback"); - world.advance(1.0/60,{0,0,false,true});for(int i=0;i<59;++i)world.advance(1.0/60); - near(world.transform(world.find("door")).rotation[1],0,0.001f,"sample door toggles closed"); +void sampleGameplay() { + Runtime world; + faset::gameplay::registerGameplay(world); + auto doc = scene(3); + auto door = entity("door"); + door["components"].push_back(component("gameplay.door", {{"speed", 2.0}})); + doc["entities"] = Json::array({door}); + world.load(doc); + world.advance(1.0 / 60, {0, 0, false, true}); + for (int i = 0; i < 59; ++i) + world.advance(1.0 / 60); + near(world.transform(world.find("door")).rotation[1], 1.5707963f, 0.001f, + "sample door opens through real static gameplay callback"); + world.advance(1.0 / 60, {0, 0, false, true}); + for (int i = 0; i < 59; ++i) + world.advance(1.0 / 60); + near(world.transform(world.find("door")).rotation[1], 0, 0.001f, "sample door toggles closed"); } +void groundedJump() { + Runtime world; + faset::gameplay::registerGameplay(world); + auto doc = scene(2); + auto ground = entity("ground", -0.5f); + ground["components"].push_back( + component("faset.rigid_body_2d", {{"body_type", "static"}, {"half_extents", {10, .5}}})); + auto character = entity("character", 0.5f); + character["components"].push_back(component("faset.rigid_body_2d")); + character["components"].push_back(component("gameplay.character")); + doc["entities"] = Json::array({ground, character}); + world.load(doc); + auto h = world.find("character"); + for (int i = 0; i < 10; ++i) + world.advance(1.0 / 60); + check(world.grounded(h), "character starts supported"); + world.advance(1.0 / 60, {0, 0, true, false}); + check(world.velocity(h)[1] > 4, "grounded jump sets upward velocity"); + for (int i = 0; i < 90 && world.velocity(h)[1] > 0.1f; ++i) + world.advance(1.0 / 60); + check(!world.grounded(h), "apex is not grounded"); + auto before = world.velocity(h)[1]; + world.advance(1.0 / 60, {0, 0, true, false}); + check(world.velocity(h)[1] < before, "jump at apex must not create a second impulse"); + for (int i = 0; i < 180; ++i) + world.advance(1.0 / 60); + check(world.grounded(h), "character regains ground after landing"); + Runtime wall; + auto wallScene = scene(2); + auto obstacle = entity("wall"); + obstacle["components"].push_back( + component("faset.rigid_body_2d", {{"body_type", "static"}, {"half_extents", {.5, 5}}})); + auto body = entity("side"); + body["components"][0]["fields"]["position"] = {1, 0, 0}; + body["components"].push_back(component("faset.rigid_body_2d", {{"gravity_scale", 0}})); + wallScene["entities"] = Json::array({obstacle, body}); + wall.load(wallScene); + for (int i = 0; i < 5; ++i) + wall.advance(1.0 / 60); + check(!wall.grounded(wall.find("side")), "wall contact is not a supporting floor contact"); +} +} // namespace +int main() { + try { + auto run = [](const char* name, auto fn) { + try { + fn(); + std::cout << name << " passed\n"; + } catch (const std::exception& error) { + throw std::runtime_error(std::string(name) + ": " + error.what()); + } + }; + run("Box2D", [] { physics(2); }); + run("Box3D", [] { physics(3); }); + run("Lifecycle", lifecycle); + run("Clock/validation", clockAndValidation); + run("Structural failures", structuralFailuresAndCallbacks); + run("Sample gameplay", sampleGameplay); + run("Grounded jump", groundedJump); + std::cout << "runtime contracts passed: actual Box2D/Box3D collisions, lifecycle, handles, " + "interpolation, deferred mutation, catchup, pause, validation, gameplay\n"; + return 0; + } catch (const std::exception& ex) { + std::cerr << ex.what() << '\n'; + return 1; + } } -int main(){try{auto run=[](const char* name,auto fn){try{fn();std::cout< +#include +#include +#include +#include +#include + +namespace { +void check(bool value, const char* message) { + if (!value) + throw std::runtime_error(message); +} +void near(float a, float b, const char* message) { + check(std::abs(a - b) < 0.002f, message); +} +} // namespace +int main() { + try { + nlohmann::json scene; + std::ifstream input(FASET_TUTORIAL_SCENE); + input >> scene; + std::set stableIds; + for (const auto& entity : scene.at("entities")) { + check(stableIds.insert(entity.at("id").get()).second, + "entity stable ID must be globally unique"); + for (const auto& component : entity.at("components")) + check(stableIds.insert(component.at("id").get()).second, + "component stable ID must be globally unique for Editor authoring"); + } + const auto types = faset::gameplay::schema(); + check(types.is_array() && !types.empty(), "tutorial must export real component schemas"); + for (const auto& type : types) + for (const auto& [id, field] : type.at("fields").items()) + check(field.at("id") == id && field.contains("default"), + "schema FieldId/default contract"); + faset::runtime::Runtime world; + faset::gameplay::registerGameplay(world); + world.load(scene); + const std::string tutorial = FASET_TUTORIAL_NAME; + if (tutorial == "moving") { + for (int i = 0; i < 60; ++i) + world.advance(1.0 / 60); + near(world.transform(world.find("actor")).position[0], 2, + "60 Hz motion covers two metres per second"); + world.load(scene); + for (int i = 0; i < 30; ++i) + world.advance(1.0 / 30); + near(world.transform(world.find("actor")).position[0], 2, + "30 Hz motion covers the same distance"); + } else if (tutorial == "following") { + world.advance(1.5 / 60); + near(world.presentation(world.find("actor")).position[0], 1.0f / 60, + "presentation halfway between completed fixed poses"); + near(world.presentation(world.find("camera")).position[0], + world.presentation(world.find("actor")).position[0], + "LateUpdate follows interpolated target"); + near(world.transform(world.find("camera")).position[0], 0, + "following does not change simulation transform"); + const auto target = world.find("actor"); + world.destroy(target); + world.singleStep(); + check(!world.valid(target), "target handle invalid after destruction"); + } else if (tutorial == "spawning") { + check(!world.find("temporary-box"), "OnStart spawn deferred until first tick"); + world.singleStep(); + auto spawned = world.find("temporary-box"); + check(world.valid(spawned), "child created at first barrier"); + for (int i = 0; i < 90; ++i) + world.singleStep(); + check(!world.valid(spawned) && !world.find("temporary-box"), + "lifetime removes temporary entity"); + world.load(scene); + world.singleStep(); + check(world.valid(world.find("temporary-box")) && !world.valid(spawned), + "module state and handles work across scene restart"); + } else if (tutorial == "physics") { + auto self = world.find("actor"); + for (int i = 0; i < 10; ++i) + world.advance(1.0 / 60); + check(world.grounded(self), "controller starts on floor"); + world.advance(1.0 / 60, {1, 0, true, false}); + check(world.velocity(self)[0] > 3.5f && world.velocity(self)[1] > 4, + "input applies velocity and grounded jump"); + for (int i = 0; i < 90 && world.velocity(self)[1] > 0.1f; ++i) + world.advance(1.0 / 60); + check(!world.grounded(self), "apex has no ground contact"); + const float before = world.velocity(self)[1]; + world.advance(1.0 / 60, {0, 0, true, false}); + check(world.velocity(self)[1] < before, "controller refuses air jump"); + for (int i = 0; i < 180; ++i) + world.advance(1.0 / 60); + check(world.grounded(self), "controller lands again"); + } else + throw std::runtime_error("Unknown compiled tutorial"); + check(world.diagnostics().empty(), "tutorial callbacks must not silently report errors"); + std::cout << tutorial << " tutorial compiled and passed\n"; + return 0; + } catch (const std::exception& error) { + std::cerr << error.what() << '\n'; + return 1; + } +} diff --git a/tests/ui_render_test.cpp b/tests/ui_render_test.cpp new file mode 100644 index 0000000..69a4900 --- /dev/null +++ b/tests/ui_render_test.cpp @@ -0,0 +1,115 @@ +#include +#include +#include +using namespace faset; +int main(int argc, char** argv) { + try { + render::Renderer renderer({1280, 800, "Faset UI reference implementation", true, true}); + ui::Context ui(FASET_TEST_FONT); + ui.set_theme(ui::Theme::load(FASET_UI_THEME)); + ui.apply_layout( + read_json(std::filesystem::path(FASET_UI_THEME).parent_path() / "editor-layout.json")); + auto& menu = ui.find("menubar")->add(ui::Kind::Row, "menuitems"); + for (const auto& name : {"Faset", "File", "Edit", "Scene", "View", "Help"}) + menu.add(ui::Kind::Button, "menu-" + std::string(name), name).layout.width = 65; + auto& tools = ui.find("toolbar")->add(ui::Kind::Row, "tools"); + for (const auto& name : + {"Workshop", "Courtyard", "Save", "Undo", "Redo", "Play", "Stop", "Build"}) + tools.add(ui::Kind::Button, "tool-" + std::string(name), name).layout.width = 80; + auto& scene = *ui.find("scene_panel"); + scene.add(ui::Kind::Tab, "scene-tab", "Scene").selected = true; + auto& tree = scene.add(ui::Kind::Column, "scene-tree"); + tree.layout.flex = 1; + tree.layout.scroll = true; + tree.layout.gap = 0; + for (const auto& name : + {"Courtyard", "Camera", "Sun", "Ground", "Player", "Door", "Crates"}) { + auto& row = tree.add(ui::Kind::TreeRow, "object-" + std::string(name), name); + row.indent = std::string(name) == "Courtyard" ? 0 : 1; + row.selected = std::string(name) == "Door"; + } + auto& inspector = *ui.find("inspector_panel"); + inspector.add(ui::Kind::Tab, "inspector-tab", "Inspector").selected = true; + auto& body = inspector.add(ui::Kind::Column, "properties"); + body.layout.padding = 10; + body.layout.scroll = true; + body.layout.flex = 1; + body.layout.gap = 8; + body.add(ui::Kind::TextField, "object-name", "Door"); + body.add(ui::Kind::Label, "transform-title", "Transform"); + for (const auto& name : {"Position", "Rotation", "Scale"}) { + auto& row = body.add(ui::Kind::Row, "property-" + std::string(name)); + row.layout.height = 30; + row.add(ui::Kind::Label, "label-" + std::string(name), name).layout.width = 64; + for (int axis = 0; axis < 3; ++axis) { + auto& field = + row.add(ui::Kind::NumberField, std::string(name) + std::to_string(axis)); + field.layout.flex = 1; + field.layout.min_width = 40; + field.value = std::string(name) == "Scale" ? 1 : 0; + } + } + body.add(ui::Kind::Label, "mesh-title", "Mesh"); + body.add(ui::Kind::Button, "mesh-asset", "Door.glb"); + body.add(ui::Kind::Label, "body-title", "Rigid Body"); + auto& check = body.add(ui::Kind::Checkbox, "static", "Static"); + check.checked = true; + body.add(ui::Kind::Label, "controller-title", "Door Controller (C++)"); + auto& speed = body.add(ui::Kind::NumberField, "speed"); + speed.value = 2; + body.add(ui::Kind::Button, "add-component", "Add Component"); + body.add(ui::Kind::Label, "unicode-check", "Cyrillic: Дверь, сцена"); + auto& bottom = *ui.find("bottom_panel"); + auto& tabs = bottom.add(ui::Kind::Row, "asset-tabs"); + tabs.layout.height = 30; + tabs.add(ui::Kind::Tab, "assets-tab", "Assets").selected = true; + tabs.add(ui::Kind::Tab, "console-tab", "Console"); + auto& search = bottom.add(ui::Kind::Row, "asset-search"); + search.layout.height = 30; + search.add(ui::Kind::Label, "breadcrumb", "Assets / Models").layout.flex = 1; + search.add(ui::Kind::TextField, "search", "Search assets...").layout.width = 260; + for (const auto& name : {"Door.glb", "Crate.glb", "Ground.material", "Courtyard.scene"}) { + auto& row = bottom.add(ui::Kind::TreeRow, "asset-" + std::string(name), name); + row.layout.height = 26; + row.indent = 1; + } + ui.find("statusbar") + ->add(ui::Kind::Label, "status", + "Ready Vulkan 1.3 | C++ " + "gameplay | Local project"); + ui.layout(1280, 800); + render::Snapshot snapshot; + const auto rect = ui.find("viewport")->rect; + snapshot.scene_rect = {rect.x, rect.y, rect.width, rect.height}; + snapshot.eye = {5, 4, 7}; + snapshot.view_projection = + render::multiply(render::perspective(.75f, rect.width / rect.height, .1f, 100), + render::look_at(snapshot.eye, {0, 1, 0})); + render::DrawItem ground; + ground.mesh = render::cube_mesh(); + ground.model = render::transform({0, -.25f, 0}, {}, {8, .5f, 8}); + ground.color = {.25f, .29f, .32f, 1}; + snapshot.draws.push_back(ground); + render::DrawItem door; + door.mesh = render::cube_mesh(); + door.model = render::transform({0, 1.25f, 0}, {}, {1.6f, 2.5f, .3f}); + door.color = {.46f, .28f, .13f, 1}; + snapshot.draws.push_back(door); + render::DrawItem crate; + crate.mesh = render::cube_mesh(); + crate.model = render::transform({-2, .6f, 1}, {0, .2f, 0}, {1.2f, 1.2f, 1.2f}); + crate.color = {.38f, .25f, .14f, 1}; + snapshot.draws.push_back(crate); + ui.draw(snapshot); + renderer.render(snapshot); + renderer.capture(argc > 1 ? argv[1] : "ui-test.ppm"); + if (renderer.stats().validation_errors) + throw std::runtime_error("Vulkan validation reported UI rendering errors"); + std::cout << "UI glyph atlas and retained panels rendered on " << renderer.stats().device + << '\n'; + return 0; + } catch (const std::exception& e) { + std::cerr << e.what() << '\n'; + return 1; + } +} diff --git a/tests/ui_tests.cpp b/tests/ui_tests.cpp new file mode 100644 index 0000000..3d4b2cf --- /dev/null +++ b/tests/ui_tests.cpp @@ -0,0 +1,239 @@ +#include +#include +#include +#include +using namespace faset; +namespace { +void check(bool value, const char* message) { + if (!value) + throw std::runtime_error(message); +} +render::Event key(std::string name, bool control = false, bool shift = false) { + render::Event e; + e.type = render::Event::Type::KeyDown; + e.key = std::move(name); + e.control = control; + e.shift = shift; + return e; +} +render::Event text(std::string value) { + render::Event e; + e.type = render::Event::Type::TextInput; + e.text = std::move(value); + return e; +} +render::Event mouse(render::Event::Type type, float x, float y) { + render::Event e; + e.type = type; + e.x = x; + e.y = y; + e.button = 1; + return e; +} +void click(ui::Context& context, const ui::Widget& widget) { + const auto r = widget.rect; + context.handle(mouse(render::Event::Type::MouseDown, r.x + 5, r.y + 5)); + context.handle(mouse(render::Event::Type::MouseUp, r.x + 5, r.y + 5)); +} +} // namespace +int main() { + try { + ui::TextBuffer buffer("Привет"); + check(buffer.backspace() && buffer.text() == "Приве", "UTF-8 backspace split codepoint"); + check(buffer.undo() && buffer.text() == "Привет", "text undo"); + buffer.select_all(); + buffer.insert("Дверь"); + buffer.left(true); + check(buffer.selected_text() == "ь", "UTF-8 selection"); + buffer.insert("ца"); + check(buffer.text() == "Дверца", "selection replacement"); + check(!buffer.insert(std::string("\xc0\x80", 2)), "overlong UTF-8 accepted"); + buffer.home(); + buffer.delete_forward(); + check(buffer.text() == "верца", "UTF-8 delete"); + buffer.undo(); + check(buffer.text() == "Дверца", "undo delete"); + ui::Context context(FASET_TEST_FONT); + auto& root = context.root(); + root.layout.gap = 4; + auto& name = root.add(ui::Kind::TextField, "name", "Door"); + name.layout.height = 32; + int commits = 0; + name.on_commit = [&](ui::Widget&) { ++commits; }; + auto& number = root.add(ui::Kind::NumberField, "number"); + number.value = 4; + number.step = .5; + number.layout.height = 32; + int number_commits = 0, previews = 0; + number.on_commit = [&](ui::Widget&) { ++number_commits; }; + number.on_preview = [&](ui::Widget&) { ++previews; }; + auto& checkbox = root.add(ui::Kind::Checkbox, "enabled", "Enabled"); + int checks = 0; + checkbox.on_commit = [&](ui::Widget&) { ++checks; }; + auto& button = root.add(ui::Kind::Button, "save", "Save"); + int clicks = 0; + button.on_click = [&](ui::Widget&) { ++clicks; }; + context.layout(320, 240); + std::string clipboard; + context.set_clipboard([&] { return clipboard; }, + [&](const std::string& s) { clipboard = s; }); + bool ime = false; + int ime_rectangles = 0; + context.set_ime([&](bool enabled) { ime = enabled; }, + [&](ui::Rect r) { + check(r.width > 0, "IME area"); + ++ime_rectangles; + }); + check(context.focus("name") && ime, "field focus enables IME"); + context.handle(key("A", true)); + context.handle(text("Привет")); + check(!context.update_text("name", "External"), "document refresh erased dirty edit"); + context.handle(key("C", true)); + context.handle(key("A", true)); + context.handle(key("C", true)); + check(clipboard == "Привет", "clipboard copied wrong selection"); + clipboard = "Дверь"; + context.handle(key("V", true)); + check(name.text == "Дверь", "UTF-8 paste"); + context.handle(key("Z", true)); + check(name.text == "Привет", "local Ctrl-Z"); + context.handle(key("Return")); + check(commits == 1 && name.text == "Привет", "text commits once"); + context.handle(key("Return")); + check(commits == 1, "unchanged text recommitted"); + context.handle(key("End")); + render::Event composition; + composition.type = render::Event::Type::TextEditing; + composition.text = "й"; + composition.edit_length = 1; + context.handle(composition); + check(name.text == "Привет", "IME preedit changed document field"); + context.handle(text("й")); + context.handle(key("Return")); + check(name.text == "Приветй" && commits == 2, "IME commit"); + context.focus("number"); + const auto r = number.rect; + context.handle(mouse(render::Event::Type::MouseDown, r.x + 20, r.y + 12)); + context.handle(mouse(render::Event::Type::MouseMove, r.x + 40, r.y + 12)); + context.handle(mouse(render::Event::Type::MouseMove, r.x + 50, r.y + 12)); + context.handle(mouse(render::Event::Type::MouseUp, r.x + 50, r.y + 12)); + check(number.value == 19 && number_commits == 1 && previews == 2, + "numeric drag must commit once at release"); + context.focus("save"); + check(number_commits == 1, "blur duplicated drag commit"); + context.focus("number"); + context.handle(key("A", true)); + context.handle(text("NaN")); + context.handle(key("Return")); + check(number_commits == 1 && !number.error.empty(), "invalid numeric input committed"); + context.handle(key("Escape")); + check(number.value == 19, "cancel numeric input changed value"); + click(context, checkbox); + check(checkbox.checked && checks == 1, "checkbox commit"); + click(context, button); + check(clicks == 1, "button click"); + context.handle(key("Return")); + check(clicks == 2, "keyboard button activation"); + context.handle(key("Tab")); + check(context.focused_id() == "name", "focus wraps predictably"); + check(ime_rectangles > 0, "IME rectangle never sent"); + ui::Context split(FASET_TEST_FONT); + auto& row = split.root().add(ui::Kind::Row, "row"); + row.layout.flex = 1; + row.layout.gap = 0; + auto& left = row.add(ui::Kind::Panel, "left"); + left.layout.width = 100; + left.layout.min_width = 50; + auto& divider = row.add(ui::Kind::Divider, "divider"); + divider.layout.width = 5; + auto& right = row.add(ui::Kind::Panel, "right"); + right.layout.flex = 1; + right.layout.min_width = 50; + int resize_commit = 0; + divider.on_commit = [&](ui::Widget&) { ++resize_commit; }; + split.layout(300, 100); + const auto d = divider.rect; + split.handle(mouse(render::Event::Type::MouseDown, d.x + 2, 20)); + split.handle(mouse(render::Event::Type::MouseMove, d.x + 32, 20)); + split.handle(mouse(render::Event::Type::MouseUp, d.x + 32, 20)); + check(left.layout.width == 130 && right.rect.width == 165 && resize_commit == 1, + "divider resize"); + const auto moved_divider = divider.rect; + split.handle(mouse(render::Event::Type::MouseDown, moved_divider.x + 2, 20)); + split.handle(mouse(render::Event::Type::MouseMove, moved_divider.x + 42, 20)); + split.handle(key("Escape")); + check(left.layout.width == 130 && resize_commit == 1, + "Escape must restore divider without committing"); + int cancellations = 0; + number.on_cancel = [&](ui::Widget&) { ++cancellations; }; + context.handle(mouse(render::Event::Type::MouseDown, r.x + 10, r.y + 12)); + context.handle(mouse(render::Event::Type::MouseMove, r.x + 50, r.y + 12)); + context.handle(key("Escape")); + check(number.value == 19 && number_commits == 1 && cancellations == 1, + "Escape must cancel numeric drag"); + ui::Context scrolling(FASET_TEST_FONT); + auto& list = scrolling.root().add(ui::Kind::Panel, "list"); + list.layout.height = 80; + list.layout.scroll = true; + list.layout.gap = 0; + for (int i = 0; i < 10; ++i) + list.add(ui::Kind::Label, "row" + std::to_string(i), "Объект " + std::to_string(i)); + scrolling.layout(300, 200); + scrolling.handle(mouse(render::Event::Type::MouseMove, 30, 30)); + render::Event wheel; + wheel.type = render::Event::Type::Wheel; + wheel.y = -2; + check(scrolling.handle(wheel) && list.scroll_y > 0, "scroll event"); + render::Snapshot frame; + scrolling.draw(frame); + check(!frame.ui_quads.empty(), "retained UI emitted no quads"); + for (const auto& q : frame.ui_quads) + check(q.x >= 0 && q.y >= 0 && q.x + q.width <= 300.01f && q.y + q.height <= 80.01f, + "CPU clipping escaped scroll panel"); + check(scrolling.font().measure("Привет", 14) > 20, "Cyrillic shaping failed"); + ui::DockLayout docks; + docks.move("Scene", "left", 0); + docks.move("Assets", "left", 1); + docks.move("Assets", "left", 0); + docks.set_size("Scene", 224); + check(docks.panels("left") == std::vector({"Assets", "Scene"}), + "dock reordering"); + const auto state = docks.to_json(); + ui::DockLayout restored; + restored.from_json(state); + check(restored.to_json() == state, "dock serialization"); + auto invalid = state; + invalid["areas"]["right"] = {"Scene"}; + bool rejected = false; + try { + restored.from_json(invalid); + } catch (...) { + rejected = true; + } + check(rejected && restored.to_json() == state, "invalid dock load mutated existing layout"); + ui::Context declarative(FASET_TEST_FONT); + declarative.apply_layout({{"id", "root"}, + {"kind", "column"}, + {"children", ui::Json::array({{{"id", "run"}, + {"kind", "button"}, + {"text", "Play"}, + {"layout", {{"height", 30}}}}})}}); + int action = 0; + declarative.find("run")->on_click = [&](ui::Widget&) { ++action; }; + declarative.apply_layout({{"id", "root"}, + {"kind", "column"}, + {"children", ui::Json::array({{{"id", "run"}, + {"kind", "button"}, + {"text", "Run"}, + {"layout", {{"height", 34}}}}})}}); + declarative.layout(200, 100); + click(declarative, *declarative.find("run")); + check(action == 1 && declarative.find("run")->text == "Run", "layout reload lost callback"); + std::cout << "UI: UTF-8, shaping, text/IME/clipboard, focus, transactions, " + "layout, clipping, docking OK\n"; + return 0; + } catch (const std::exception& error) { + std::cerr << error.what() << '\n'; + return 1; + } +} diff --git a/tools/project_templates/Gameplay.cpp b/tools/project_templates/Gameplay.cpp new file mode 100644 index 0000000..40c568c --- /dev/null +++ b/tools/project_templates/Gameplay.cpp @@ -0,0 +1,71 @@ +#include "Gameplay.hpp" +#include +#include +#include + +namespace faset::gameplay { +void registerGameplay(runtime::Runtime& engine) { + runtime::Behavior character; + character.fixedUpdate = [](runtime::Runtime& world, runtime::EntityHandle self, double) { + const auto fields = world.fields(self, "gameplay.character"); + auto velocity = world.velocity(self); + const auto input = world.input(); + velocity[0] = input.horizontal * fields.value("speed", 4.0f); + // Support comes from native contact normals, not velocity at the jump apex. + if (input.jumpPressed && world.grounded(self)) + velocity[1] = fields.value("jump_speed", 5.0f); + world.setVelocity(self, velocity); + }; + engine.registerBehavior("gameplay.character", std::move(character)); + + runtime::Behavior door; + auto open = std::make_shared, bool>>(); + door.onStart = [open](runtime::Runtime&, runtime::EntityHandle self, double) { + (*open)[{self.session, self.slot}] = false; + }; + door.onDestroy = [open](runtime::Runtime&, runtime::EntityHandle self, double) { + open->erase({self.session, self.slot}); + }; + door.fixedUpdate = [open](runtime::Runtime& world, runtime::EntityHandle self, double dt) { + const auto fields = world.fields(self, "gameplay.door"); + auto pose = world.transform(self); + auto& opened = (*open)[{self.session, self.slot}]; + if (world.input().interactPressed) + opened = !opened; + const float target = + opened ? fields.value("open_angle", 1.5707963f) : fields.value("closed_angle", 0.0f); + const float distance = target - pose.rotation[1]; + const float amount = std::max(0.0f, fields.value("speed", 1.5f)) * static_cast(dt); + pose.rotation[1] += std::clamp(distance, -amount, amount); + world.setTransform(self, pose); + }; + engine.registerBehavior("gameplay.door", std::move(door)); +} + +nlohmann::json schema() { + // Explicit declarations shared by Player and SchemaExporter. This function + // constructs descriptions only: no Runtime, physics world or lifecycle. + return nlohmann::json::array( + {{{"id", "gameplay.character"}, + {"version", 1}, + {"name", "Character"}, + {"fields", + {{"speed", {{"id", "speed"}, {"type", "number"}, {"default", 4.0}, {"min", 0.0}}}, + {"jump_speed", + {{"id", "jump_speed"}, {"type", "number"}, {"default", 5.0}, {"min", 0.0}}}}}}, + {{"id", "gameplay.door"}, + {"version", 1}, + {"name", "Door"}, + {"fields", + {{"open_angle", + {{"id", "open_angle"}, {"type", "number"}, {"default", 1.5707963}, {"units", "rad"}}}, + {"closed_angle", + {{"id", "closed_angle"}, {"type", "number"}, {"default", 0.0}, {"units", "rad"}}}, + {"speed", + {{"id", "speed"}, + {"type", "number"}, + {"default", 1.5}, + {"min", 0.0}, + {"units", "rad/s"}}}}}}}); +} +} // namespace faset::gameplay diff --git a/tools/project_templates/Gameplay.hpp b/tools/project_templates/Gameplay.hpp new file mode 100644 index 0000000..536ab72 --- /dev/null +++ b/tools/project_templates/Gameplay.hpp @@ -0,0 +1,7 @@ +#pragma once +#include + +namespace faset::gameplay { +void registerGameplay(runtime::Runtime& runtime); +nlohmann::json schema(); +} // namespace faset::gameplay diff --git a/tools/verify_blender_roundtrip.py b/tools/verify_blender_roundtrip.py new file mode 100644 index 0000000..b12a6e4 --- /dev/null +++ b/tools/verify_blender_roundtrip.py @@ -0,0 +1,82 @@ +#!/usr/bin/env python3 +"""Run unmodified Blender and the real Editor importer; verify rename and failure recovery.""" +import argparse +import json +import pathlib +import shutil +import subprocess +import tempfile + +ROOT = pathlib.Path(__file__).resolve().parents[1] + + +def verify(blender, editor, output): + fixture = output / "fixture" + result = subprocess.run([str(blender), "--background", "--factory-startup", "--python-exit-code", "1", + "--python", str(ROOT / "tests/blender/generate_fixture.py"), "--", str(ROOT), str(fixture)], + check=True, capture_output=True, text=True) + (output / "blender.log").write_text(result.stdout + result.stderr) + assert "FASET_BLENDER_ROUNDTRIP_EXPORT_OK" in result.stdout + project = output / "project" + source = project / "Assets/door" + source.mkdir(parents=True, exist_ok=True) + def command(name, arguments): + process = subprocess.run([str(editor), "--project", str(project), "--command", + json.dumps({"name": name, "arguments": arguments}), "--wait"], capture_output=True, text=True) + assert process.stdout, process.stderr + return json.loads(process.stdout) + def import_stage(stage): + shutil.copytree(fixture / stage, source, dirs_exist_ok=True) + return command("faset_import", {"path": "Assets/door/manifest.json"}) + first = import_stage("initial") + assert first["state"] == "succeeded", first + identity = first["result"]["asset_id"] + manifest = first["result"]["manifest"] + # Keep an authoring scene with independently owned placement/material values. + document = command("faset_document_create", {"name": "Roundtrip", "dimension": 3}) + scene = document["scene"] + scene["entities"] = [{"id": "door", "name": "Gameplay door", "parent": None, "components": [ + {"id": "door-pose", "type": "faset.transform", "version": 1, + "fields": {"position": [4, 0, 2], "rotation": [0, 0, 0], "scale": [1, 1, 1]}}, + {"id": "door-mesh", "type": "faset.mesh", "version": 1, + "fields": {"asset": identity, "primitive": "asset", "color": [0.5, 0.8, 0.3, 1]}}]}] + scene_file = project / "roundtrip.scene.json" + scene_file.write_text(json.dumps(scene)) + before = scene_file.read_bytes() + renamed = import_stage("renamed") + assert renamed["state"] == "succeeded", renamed + assert renamed["result"]["asset_id"] == identity + assert renamed["result"]["generation"] != first["result"]["generation"] + def ids(value): + return sorted(value["outputs"]) + assert ids(manifest) == ids(renamed["result"]["manifest"]), (manifest, renamed) + active = command("faset_assets", {}) + removed = import_stage("removed") + assert removed["state"] == "conflict", removed + assert command("faset_assets", {}) == active + (source / "manifest.json").write_text('{"broken":true}') + failed = command("faset_import", {"path": "Assets/door/manifest.json"}) + assert failed["state"] == "failed", failed + assert command("faset_assets", {}) == active + assert scene_file.read_bytes() == before + report = {"blender": subprocess.check_output([str(blender), "--version"], text=True).splitlines()[0], + "asset_id": identity, "initial_generation": first["result"]["generation"], + "renamed_generation": renamed["result"]["generation"], + "stable_output_ids": True, "removed_output_conflict": True, + "failed_import_keeps_generation": True, "authoring_preserved": True} + (output / "report.json").write_text(json.dumps(report, indent=2) + "\n") + print(json.dumps(report, indent=2)) + + +if __name__ == "__main__": + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument("--blender", type=pathlib.Path, required=True) + parser.add_argument("--editor", type=pathlib.Path, required=True) + parser.add_argument("--output", type=pathlib.Path) + args = parser.parse_args() + if args.output: + args.output.resolve().mkdir(parents=True, exist_ok=True) + verify(args.blender.resolve(), args.editor.resolve(), args.output.resolve()) + else: + with tempfile.TemporaryDirectory(prefix="faset-blender-") as temporary: + verify(args.blender.resolve(), args.editor.resolve(), pathlib.Path(temporary))

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≷;WT-B3`GZ(GuW2=q&RRalA)x=c;Ntt6oW&PQ! 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