diff --git a/.DS_Store b/.DS_Store deleted file mode 100644 index 25e6cd131f..0000000000 Binary files a/.DS_Store and /dev/null differ diff --git a/.github/workflows/build-doxygen-docs.yml b/.github/workflows/build-doxygen-docs.yml index e3c070b8e5..b01236ccad 100644 --- a/.github/workflows/build-doxygen-docs.yml +++ b/.github/workflows/build-doxygen-docs.yml @@ -5,7 +5,6 @@ on: branches: [ main ] env: - # Customize the CMake build type here (Release, Debug, RelWithDebInfo, etc.) BUILD_TYPE: Release jobs: @@ -13,17 +12,17 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: submodules: recursive - name: Install dependencies run: | sudo apt-get update - sudo apt-get install xorg-dev libglu1-mesa-dev doxygen + sudo apt-get install xorg-dev libglu1-mesa-dev gcc-11 g++-11 doxygen - name: Set up Python - uses: actions/setup-python@v2 + uses: actions/setup-python@v5 with: python-version: '3.x' @@ -36,7 +35,6 @@ jobs: run: cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DBUILD_DOCUMENTATION=ON - name: Build - # Build your program with the given configuration run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}} --target generate-docs - name: Deploy diff --git a/.github/workflows/build-engine-linux.yml b/.github/workflows/build-engine-linux.yml index 6d9ef75be9..75052fbf93 100644 --- a/.github/workflows/build-engine-linux.yml +++ b/.github/workflows/build-engine-linux.yml @@ -18,7 +18,7 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: submodules: recursive @@ -33,7 +33,7 @@ jobs: run: | echo "timestamp=$(date +%s)" >> $GITHUB_OUTPUT - - uses: actions/cache@v3 + - uses: actions/cache@v4 with: path: ${{ env.CCACHE_DIR }} key: ccache-${{ env.CCACHE_COMPILERTYPE }}-${{ env.BUILD_TYPE }}-${{ github.ref }}-${{ steps.ccache_vars.outputs.timestamp }} diff --git a/.github/workflows/build-engine-macos.yml b/.github/workflows/build-engine-macos.yml index 7908aaca9f..3075b6f243 100644 --- a/.github/workflows/build-engine-macos.yml +++ b/.github/workflows/build-engine-macos.yml @@ -18,7 +18,7 @@ jobs: runs-on: macos-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: submodules: recursive @@ -33,7 +33,7 @@ jobs: run: | echo "timestamp=$(date +%s)" >> $GITHUB_OUTPUT - - uses: actions/cache@v3 + - uses: actions/cache@v4 with: path: ${{ env.CCACHE_DIR }} key: ccache-${{ env.CCACHE_COMPILERTYPE }}-${{ env.BUILD_TYPE }}-${{ github.ref }}-${{ steps.ccache_vars.outputs.timestamp }} diff --git a/.github/workflows/build-engine-windows.yml b/.github/workflows/build-engine-windows.yml index c88403772d..309a6e3772 100644 --- a/.github/workflows/build-engine-windows.yml +++ b/.github/workflows/build-engine-windows.yml @@ -19,12 +19,12 @@ jobs: runs-on: windows-2022 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: submodules: recursive - name: Set up Python - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: python-version: '3.x' @@ -39,7 +39,7 @@ jobs: run: | echo "timestamp=$(date +%s)" >> $GITHUB_OUTPUT - - uses: actions/cache@v3 + - uses: actions/cache@v4 with: path: ${{ env.CCACHE_DIR }} key: ccache-${{ env.CCACHE_COMPILERTYPE }}-${{ env.BUILD_TYPE }}-${{ github.ref }}-${{ steps.ccache_vars.outputs.timestamp }} diff --git a/.github/workflows/clang-format-check.yml b/.github/workflows/clang-format-check.yml index 7295b8fddb..19516a003c 100644 --- a/.github/workflows/clang-format-check.yml +++ b/.github/workflows/clang-format-check.yml @@ -9,7 +9,7 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: submodules: recursive fetch-depth: 2 diff --git a/.github/workflows/clang-tidy-lint.yml b/.github/workflows/clang-tidy-lint.yml index 874049a332..5b5636e85b 100644 --- a/.github/workflows/clang-tidy-lint.yml +++ b/.github/workflows/clang-tidy-lint.yml @@ -12,7 +12,7 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: submodules: recursive fetch-depth: 2 diff --git a/.github/workflows/conventional-commits.yml b/.github/workflows/conventional-commits.yml index 571937164d..c1c5958277 100644 --- a/.github/workflows/conventional-commits.yml +++ b/.github/workflows/conventional-commits.yml @@ -2,14 +2,14 @@ name: Conventional Commits on: pull_request: - branches: [ master ] + branches: [ main ] jobs: build: name: Conventional Commits runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - uses: webiny/action-conventional-commits@v1.1.0 with: diff --git a/.github/workflows/copy-labels.yml b/.github/workflows/copy-labels.yml index 69c8ea23ca..53d421ef26 100644 --- a/.github/workflows/copy-labels.yml +++ b/.github/workflows/copy-labels.yml @@ -1,4 +1,8 @@ -on: [pull_request] +name: 🏷️ Copy Labels + +on: + pull_request: + branches: [ main ] jobs: copy-labels: diff --git a/.github/workflows/create-coverage-report.yml b/.github/workflows/create-coverage-report.yml index 9040a9cf0c..8e3afd6970 100644 --- a/.github/workflows/create-coverage-report.yml +++ b/.github/workflows/create-coverage-report.yml @@ -1,34 +1,72 @@ name: 📃 Create Coverage Report -on: [push] +on: + push: + branches: [ main ] + pull_request: + branches: [ main ] + workflow_dispatch: env: BUILD_TYPE: Debug + CCACHE_BASEDIR: ${{ github.workspace }} + CCACHE_DIR: "${{ github.workspace }}/.ccache" + CCACHE_COMPILERTYPE: gcc jobs: build: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 with: submodules: recursive - name: Install dependencies run: | sudo apt-get update - sudo apt-get install xorg-dev libglu1-mesa-dev gcc-11 g++-11 lcov + sudo apt-get install xorg-dev libglu1-mesa-dev gcc-11 g++-11 ccache lcov + + - name: Get timestamp + shell: bash + id: ccache_vars + run: | + echo "timestamp=$(date +%s)" >> $GITHUB_OUTPUT + + - uses: actions/cache@v4 + with: + path: ${{ env.CCACHE_DIR }} + key: ccache-${{ env.CCACHE_COMPILERTYPE }}-${{ env.BUILD_TYPE }}-${{ github.ref }}-${{ steps.ccache_vars.outputs.timestamp }} + restore-keys: | + ccache-${{ env.CCACHE_COMPILERTYPE }}-${{ env.BUILD_TYPE }}-${{ github.ref }}- + ccache-${{ env.CCACHE_COMPILERTYPE }}-${{ env.BUILD_TYPE }}- + ccache-${{ env.CCACHE_COMPILERTYPE }}- + ccache- - name: Configure CMake - run: cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DENABLE_COVERAGE=ON -DBUILD_CORE_TESTS=ON -DUSE_CLANG_TIDY=OFF + run: cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DENABLE_COVERAGE=ON -DBUILD_CORE_TESTS=ON -DBUILD_ENGINE_TESTS=ON -DUSE_CLANG_TIDY=OFF shell: bash env: CC: gcc-11 CXX: g++-11 + - name: CCache Prolog + run: |- + ccache -s # Print current cache stats + ccache -z # Zero cache entry + - name: Build run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}} --target coverage + - name: CCache Epilog + run: | + ccache -s # Print current cache stats + - name: Upload - run: bash <(curl -s https://codecov.io/bash) -f ${{github.workspace}}/build/coverage.info - + uses: codecov/codecov-action@v4 + with: + directory: ${{github.workspace}}/build/ + fail_ci_if_error: true + files: ./coverage-core.info,./coverage-engine.info + token: ${{ secrets.CODECOV_TOKEN }} + verbose: true diff --git a/.github/workflows/preview-docs.yml b/.github/workflows/preview-docs.yml index d710f7a477..c0fc1b8311 100644 --- a/.github/workflows/preview-docs.yml +++ b/.github/workflows/preview-docs.yml @@ -2,11 +2,7 @@ name: 📖 Deploy Documentation Previews on: pull_request: - types: - - opened - - reopened - - synchronize - - closed + branches: [ main ] env: BUILD_TYPE: Release @@ -18,17 +14,17 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 with: submodules: recursive - name: Install dependencies run: | sudo apt-get update - sudo apt-get install xorg-dev libglu1-mesa-dev doxygen + sudo apt-get install xorg-dev libglu1-mesa-dev gcc-11 g++-11 doxygen - name: Set up Python - uses: actions/setup-python@v2 + uses: actions/setup-python@v5 with: python-version: '3.x' diff --git a/.gitignore b/.gitignore index 602cc3f566..25c997b0d0 100644 --- a/.gitignore +++ b/.gitignore @@ -402,3 +402,5 @@ imgui.ini # direnv - maybe .envrc is ok if 'use flake' doesn't break non nixos machines /.envrc /.direnv + +.DS_store \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 9e52ada8ae..a7bedfb771 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -27,15 +27,18 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Voxel palette editor plugin (#662). - Scene editor plugin (#265, #551). - Metrics panel plugin, which only shows FPS statistics for now (#275). +- Parent-child hierarchies to the transform plugin, at last (#334). ### Changed +- Also track test coverage of engine (#941) - Start using reflection on most of the ECS (#462). - Change the ECS to be archetype-based (#819) - Move the Cubos class to the core (#900). - Switch to new system syntax (#896). - Bump `glad` from `d08b1aa` to `73eaae0`. - Bump `json` from `v3.11.2` to `v3.11.3`. +- Change Gizmo plugin to use the Screen picker plugin (#870). ### Deprecated diff --git a/CMakeLists.txt b/CMakeLists.txt index c04077b1b2..d11844d267 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -18,14 +18,26 @@ if(ENABLE_COVERAGE) append_coverage_compiler_flags() setup_target_for_coverage_lcov( - NAME coverage + NAME coverage-core EXECUTABLE core/tests/cubos-core-tests DEPENDENCIES cubos-core-tests - EXCLUDE "core/lib/*" "core/tests/*" "tools/quadrados" "*-components.cpp" + EXCLUDE "core/lib/*" "core/tests/*" "engine/*" "lib/*" "tools/*" "*-components.cpp" LCOV_ARGS "--no-external" ) + + setup_target_for_coverage_lcov( + NAME coverage-engine + EXECUTABLE engine/tests/cubos-engine-tests + DEPENDENCIES cubos-engine-tests + + EXCLUDE "engine/lib/*" "engine/tests/*" "core/*" "lib/*" "tools/*" "*-components.cpp" + + LCOV_ARGS "--no-external" + ) + + add_custom_target(coverage DEPENDS coverage-core coverage-engine) endif() # Enable CCache diff --git a/core/CMakeLists.txt b/core/CMakeLists.txt index bcd7ad1a7f..607df96041 100644 --- a/core/CMakeLists.txt +++ b/core/CMakeLists.txt @@ -3,9 +3,11 @@ option(WITH_GLFW "With GLFW?" ON) option(WITH_OPENGL "With OpenGL?" ON) -if (WITH_GLFW) - option(GLFW_USE_SUBMODULE "Compile GLFW from source?" ON) -endif () + +if(WITH_GLFW) + option(GLFW_USE_SUBMODULE "Compile GLFW from source?" ON) +endif() + option(WITH_OPENAL "With OpenAL?" ON) option(GLM_USE_SUBMODULE "Compile GLM from source?" ON) @@ -19,159 +21,157 @@ message("# Building core samples: " ${BUILD_CORE_SAMPLES}) message("# Building core tests: " ${BUILD_CORE_TESTS}) # Set core source files - set(CUBOS_CORE_SOURCE - "src/cubos/core/log.cpp" - "src/cubos/core/thread_pool.cpp" - - "src/cubos/core/memory/stream.cpp" - "src/cubos/core/memory/standard_stream.cpp" - "src/cubos/core/memory/buffer_stream.cpp" - "src/cubos/core/memory/any_value.cpp" - "src/cubos/core/memory/any_vector.cpp" - - "src/cubos/core/reflection/type.cpp" - "src/cubos/core/reflection/type_registry.cpp" - "src/cubos/core/reflection/traits/constructible.cpp" - "src/cubos/core/reflection/traits/fields.cpp" - "src/cubos/core/reflection/traits/array.cpp" - "src/cubos/core/reflection/traits/dictionary.cpp" - "src/cubos/core/reflection/traits/string_conversion.cpp" - "src/cubos/core/reflection/traits/nullable.cpp" - "src/cubos/core/reflection/traits/enum.cpp" - "src/cubos/core/reflection/external/primitives.cpp" - "src/cubos/core/reflection/external/cstring.cpp" - "src/cubos/core/reflection/external/string.cpp" - "src/cubos/core/reflection/external/string_view.cpp" - "src/cubos/core/reflection/external/uuid.cpp" - "src/cubos/core/reflection/external/glm.cpp" - - "src/cubos/core/data/old/serializer.cpp" - "src/cubos/core/data/old/deserializer.cpp" - "src/cubos/core/data/old/json_serializer.cpp" - "src/cubos/core/data/old/json_deserializer.cpp" - "src/cubos/core/data/old/binary_serializer.cpp" - "src/cubos/core/data/old/binary_deserializer.cpp" - "src/cubos/core/data/old/package.cpp" - "src/cubos/core/data/old/context.cpp" - - "src/cubos/core/data/fs/file.cpp" - "src/cubos/core/data/fs/file_system.cpp" - "src/cubos/core/data/fs/standard_archive.cpp" - "src/cubos/core/data/fs/embedded_archive.cpp" - "src/cubos/core/data/ser/serializer.cpp" - "src/cubos/core/data/ser/json.cpp" - "src/cubos/core/data/ser/debug.cpp" - "src/cubos/core/data/des/deserializer.cpp" - "src/cubos/core/data/des/json.cpp" - - "src/cubos/core/io/window.cpp" - "src/cubos/core/io/cursor.cpp" - "src/cubos/core/io/glfw_window.hpp" - "src/cubos/core/io/glfw_window.cpp" - "src/cubos/core/io/keyboard.cpp" - "src/cubos/core/io/gamepad.cpp" - - "src/cubos/core/gl/debug.cpp" - "src/cubos/core/gl/render_device.cpp" - "src/cubos/core/gl/ogl_render_device.hpp" - "src/cubos/core/gl/ogl_render_device.cpp" - "src/cubos/core/gl/util.cpp" - - "src/cubos/core/al/audio_device.cpp" - "src/cubos/core/al/oal_audio_device.cpp" - "src/cubos/core/al/oal_audio_device.hpp" - - "src/cubos/core/ecs/entity/entity.cpp" - "src/cubos/core/ecs/entity/hash.cpp" - "src/cubos/core/ecs/entity/archetype_graph.cpp" - "src/cubos/core/ecs/entity/archetype_id.cpp" - "src/cubos/core/ecs/entity/pool.cpp" - - "src/cubos/core/ecs/table/column.cpp" - "src/cubos/core/ecs/table/dense/table.cpp" - "src/cubos/core/ecs/table/dense/registry.cpp" - "src/cubos/core/ecs/table/sparse_relation/id.cpp" - "src/cubos/core/ecs/table/sparse_relation/table.cpp" - "src/cubos/core/ecs/table/sparse_relation/registry.cpp" - "src/cubos/core/ecs/table/tables.cpp" - - "src/cubos/core/ecs/system/access.cpp" - "src/cubos/core/ecs/system/system.cpp" - "src/cubos/core/ecs/system/options.cpp" - "src/cubos/core/ecs/system/dispatcher.cpp" - "src/cubos/core/ecs/system/arguments/commands.cpp" - "src/cubos/core/ecs/system/arguments/query.cpp" - "src/cubos/core/ecs/system/arguments/resources.cpp" - "src/cubos/core/ecs/system/arguments/world.cpp" - - "src/cubos/core/ecs/query/term.cpp" - "src/cubos/core/ecs/query/data.cpp" - "src/cubos/core/ecs/query/filter.cpp" - "src/cubos/core/ecs/query/fetcher.cpp" - "src/cubos/core/ecs/query/opt.cpp" - - "src/cubos/core/ecs/reflection.cpp" - "src/cubos/core/ecs/blueprint.cpp" - "src/cubos/core/ecs/name.cpp" - "src/cubos/core/ecs/world.cpp" - "src/cubos/core/ecs/command_buffer.cpp" - "src/cubos/core/ecs/types.cpp" - "src/cubos/core/ecs/cubos.cpp" - - "src/cubos/core/geom/box.cpp" - "src/cubos/core/geom/capsule.cpp" + "src/log.cpp" + "src/thread_pool.cpp" + + "src/memory/stream.cpp" + "src/memory/standard_stream.cpp" + "src/memory/buffer_stream.cpp" + "src/memory/any_value.cpp" + "src/memory/any_vector.cpp" + + "src/reflection/type.cpp" + "src/reflection/comparison.cpp" + "src/reflection/type_registry.cpp" + "src/reflection/traits/constructible.cpp" + "src/reflection/traits/fields.cpp" + "src/reflection/traits/array.cpp" + "src/reflection/traits/dictionary.cpp" + "src/reflection/traits/string_conversion.cpp" + "src/reflection/traits/nullable.cpp" + "src/reflection/traits/enum.cpp" + "src/reflection/external/primitives.cpp" + "src/reflection/external/cstring.cpp" + "src/reflection/external/string.cpp" + "src/reflection/external/string_view.cpp" + "src/reflection/external/uuid.cpp" + "src/reflection/external/glm.cpp" + + "src/data/old/serializer.cpp" + "src/data/old/deserializer.cpp" + "src/data/old/json_serializer.cpp" + "src/data/old/json_deserializer.cpp" + "src/data/old/binary_serializer.cpp" + "src/data/old/binary_deserializer.cpp" + "src/data/old/package.cpp" + "src/data/old/context.cpp" + + "src/data/fs/file.cpp" + "src/data/fs/file_system.cpp" + "src/data/fs/standard_archive.cpp" + "src/data/fs/embedded_archive.cpp" + "src/data/ser/serializer.cpp" + "src/data/ser/json.cpp" + "src/data/ser/debug.cpp" + "src/data/des/deserializer.cpp" + "src/data/des/json.cpp" + + "src/io/window.cpp" + "src/io/cursor.cpp" + "src/io/glfw_window.hpp" + "src/io/glfw_window.cpp" + "src/io/keyboard.cpp" + "src/io/gamepad.cpp" + + "src/gl/debug.cpp" + "src/gl/render_device.cpp" + "src/gl/ogl_render_device.hpp" + "src/gl/ogl_render_device.cpp" + "src/gl/util.cpp" + + "src/al/audio_device.cpp" + "src/al/oal_audio_device.cpp" + "src/al/oal_audio_device.hpp" + + "src/ecs/entity/entity.cpp" + "src/ecs/entity/hash.cpp" + "src/ecs/entity/archetype_graph.cpp" + "src/ecs/entity/archetype_id.cpp" + "src/ecs/entity/pool.cpp" + + "src/ecs/table/column.cpp" + "src/ecs/table/dense/table.cpp" + "src/ecs/table/dense/registry.cpp" + "src/ecs/table/sparse_relation/id.cpp" + "src/ecs/table/sparse_relation/table.cpp" + "src/ecs/table/sparse_relation/registry.cpp" + "src/ecs/table/tables.cpp" + + "src/ecs/system/access.cpp" + "src/ecs/system/system.cpp" + "src/ecs/system/options.cpp" + "src/ecs/system/dispatcher.cpp" + "src/ecs/system/arguments/commands.cpp" + "src/ecs/system/arguments/query.cpp" + "src/ecs/system/arguments/resources.cpp" + "src/ecs/system/arguments/world.cpp" + + "src/ecs/query/term.cpp" + "src/ecs/query/data.cpp" + "src/ecs/query/filter.cpp" + "src/ecs/query/fetcher.cpp" + "src/ecs/query/opt.cpp" + + "src/ecs/reflection.cpp" + "src/ecs/blueprint.cpp" + "src/ecs/name.cpp" + "src/ecs/world.cpp" + "src/ecs/command_buffer.cpp" + "src/ecs/types.cpp" + "src/ecs/cubos.cpp" + + "src/geom/box.cpp" + "src/geom/capsule.cpp" ) # Create core library - add_library(cubos-core ${CUBOS_CORE_SOURCE}) target_include_directories(cubos-core PUBLIC "include") target_compile_definitions(cubos-core PUBLIC - -DCUBOS_CORE_ECS_MAX_COMPONENTS=${CUBOS_CORE_ECS_MAX_COMPONENTS} - -DCUBOS_CORE_DISPATCHER_MAX_CONDITIONS=${CUBOS_CORE_DISPATCHER_MAX_CONDITIONS} + -DCUBOS_CORE_ECS_MAX_COMPONENTS=${CUBOS_CORE_ECS_MAX_COMPONENTS} + -DCUBOS_CORE_DISPATCHER_MAX_CONDITIONS=${CUBOS_CORE_DISPATCHER_MAX_CONDITIONS} ) cubos_common_target_options(cubos-core) # Link dependencies +if(WITH_OPENGL) + set(GLAD_SOUURCES_DIR "lib/glad") + add_subdirectory("${GLAD_SOUURCES_DIR}/cmake" glad_cmake SYSTEM) + glad_add_library(glad REPRODUCIBLE API gl:core=3.3) + target_link_libraries(cubos-core PRIVATE glad) + target_compile_definitions(cubos-core PRIVATE WITH_OPENGL) +endif() -if (WITH_OPENGL) - set(GLAD_SOUURCES_DIR "lib/glad") - add_subdirectory("${GLAD_SOUURCES_DIR}/cmake" glad_cmake SYSTEM) - glad_add_library(glad REPRODUCIBLE API gl:core=3.3) - target_link_libraries(cubos-core PRIVATE glad) - target_compile_definitions(cubos-core PRIVATE WITH_OPENGL) -endif () - -if (WITH_GLFW) - if (GLFW_USE_SUBMODULE) - set(GLFW_BUILD_DOCS OFF CACHE BOOL "" FORCE) - set(GLFW_BUILD_TESTS OFF CACHE BOOL "" FORCE) - set(GLFW_BUILD_EXAMPLES OFF CACHE BOOL "" FORCE) - add_subdirectory(lib/glfw) - else () - find_package(glfw3 REQUIRED) - endif () - - target_link_libraries(cubos-core PRIVATE glfw) - target_compile_definitions(cubos-core PRIVATE WITH_GLFW) -endif () - -if (WITH_OPENAL) - set(ALSOFT_UTILS OFF CACHE BOOL "" FORCE) - set(ALSOFT_NO_CONFIG_UTIL OFF CACHE BOOL "" FORCE) - set(ALSOFT_EXAMPLES OFF CACHE BOOL "" FORCE) - add_subdirectory(lib/openal-soft) - target_include_directories(cubos-core PRIVATE lib/openal-soft/include) - target_link_libraries(cubos-core PRIVATE OpenAL) - target_compile_definitions(cubos-core PRIVATE WITH_OPENAL) +if(WITH_GLFW) + if(GLFW_USE_SUBMODULE) + set(GLFW_BUILD_DOCS OFF CACHE BOOL "" FORCE) + set(GLFW_BUILD_TESTS OFF CACHE BOOL "" FORCE) + set(GLFW_BUILD_EXAMPLES OFF CACHE BOOL "" FORCE) + add_subdirectory(lib/glfw) + else() + find_package(glfw3 REQUIRED) + endif() + + target_link_libraries(cubos-core PRIVATE glfw) + target_compile_definitions(cubos-core PRIVATE WITH_GLFW) endif() -if (GLM_USE_SUBMODULE) - add_subdirectory(lib/glm SYSTEM) -else () - find_package(glm REQUIRED) -endif () +if(WITH_OPENAL) + set(ALSOFT_UTILS OFF CACHE BOOL "" FORCE) + set(ALSOFT_NO_CONFIG_UTIL OFF CACHE BOOL "" FORCE) + set(ALSOFT_EXAMPLES OFF CACHE BOOL "" FORCE) + add_subdirectory(lib/openal-soft) + target_include_directories(cubos-core PRIVATE lib/openal-soft/include) + target_link_libraries(cubos-core PRIVATE OpenAL) + target_compile_definitions(cubos-core PRIVATE WITH_OPENAL) +endif() + +if(GLM_USE_SUBMODULE) + add_subdirectory(lib/glm SYSTEM) +else() + find_package(glm REQUIRED) +endif() set(JSON_BuildTests OFF CACHE INTERNAL "") add_subdirectory(lib/json) @@ -187,12 +187,11 @@ target_link_libraries(cubos-core PUBLIC glm::glm nlohmann_json::nlohmann_json ${ target_link_libraries(cubos-core PRIVATE Threads::Threads) # Add core tests - -if (CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME AND BUILD_CORE_TESTS) - add_subdirectory(tests) -endif () +if(CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME AND BUILD_CORE_TESTS) + add_subdirectory(tests) +endif() # Add core samples -if (BUILD_CORE_SAMPLES) - add_subdirectory(samples) -endif () +if(BUILD_CORE_SAMPLES) + add_subdirectory(samples) +endif() \ No newline at end of file diff --git a/core/include/cubos/core/ecs/blueprint.hpp b/core/include/cubos/core/ecs/blueprint.hpp index 880e296175..415128e849 100644 --- a/core/include/cubos/core/ecs/blueprint.hpp +++ b/core/include/cubos/core/ecs/blueprint.hpp @@ -49,13 +49,6 @@ namespace cubos::core::ecs /// @param relation Relation. using Relate = void (*)(void* userData, Entity fromEntity, Entity toEntity, memory::AnyValue relation); - /// @brief Constructs. - Blueprint(); - - /// @brief Move constructs. - /// @param other Blueprint to move from. - Blueprint(Blueprint&& other) noexcept; - /// @brief Creates a new entity in the blueprint and returns it. /// /// An entity with the same name must not exist. The name must be @ref validEntityName @@ -106,7 +99,8 @@ namespace cubos::core::ecs /// /// @param prefix Name to prefix with the merged blueprint. /// @param other Blueprint to merge. - void merge(const std::string& prefix, const Blueprint& other); + /// @param withName Whether to use the entity names from the other blueprint. + void merge(const std::string& prefix, const Blueprint& other, bool withName); /// @brief Clears the blueprint. void clear(); @@ -120,7 +114,8 @@ namespace cubos::core::ecs /// @param create Function used to create entities. /// @param add Function used to add components to entities. /// @param relate Function used to add relations to entities. - void instantiate(void* userData, Create create, Add add, Relate relate) const; + /// @param withName Whether to use the entity names from the blueprint. + void instantiate(void* userData, Create create, Add add, Relate relate, bool withName) const; /// @brief Instantiates the blueprint by calling the given functors. /// @tparam C Create functor type. @@ -129,8 +124,9 @@ namespace cubos::core::ecs /// @param create Functor used to create entities. /// @param add Functor used to add components to entities. /// @param relate Functor used to add relations to entities. + /// @param withName Whether to use the entity names from the blueprint. template - void instantiate(C create, A add, R relate) const + void instantiate(C create, A add, R relate, bool withName) const { struct Functors { @@ -156,7 +152,7 @@ namespace cubos::core::ecs // We pass the functors pair using the userData argument. We could use std::function // here and pass them directly, but that would mean unnecessary heap allocations and an // extra large include on the header. - this->instantiate(&functors, createFunc, addFunc, relateFunc); + this->instantiate(&functors, createFunc, addFunc, relateFunc, withName); } /// @brief Checks if the given name is a valid entity name. @@ -166,10 +162,32 @@ namespace cubos::core::ecs /// @return Whether the name is valid. static bool validEntityName(const std::string& name); - private: template using EntityMap = std::unordered_map; + /// @brief Gets the map relating entities to their name + /// @return Bimap relating entities and names + memory::UnorderedBimap entities() const + { + return mBimap; + } + + /// @brief Gets the map relating types of components to maps of entities to the component values. + /// @return TypeMap of an EntityMap to component values + memory::TypeMap> components() const + { + return mComponents; + } + + /// @brief Gets the map relating types of relations to maps of entities to maps of entities to the component + /// values. + /// @return TypeMap of an EntityMap to another EntityMap to component values + memory::TypeMap>> relations() const + { + return mRelations; + } + + private: /// @brief Maps entities to their names. memory::UnorderedBimap mBimap; diff --git a/core/include/cubos/core/ecs/command_buffer.hpp b/core/include/cubos/core/ecs/command_buffer.hpp index f4474c077f..e6136c366c 100644 --- a/core/include/cubos/core/ecs/command_buffer.hpp +++ b/core/include/cubos/core/ecs/command_buffer.hpp @@ -40,8 +40,9 @@ namespace cubos::core::ecs /// @brief Spawns a blueprint into the world. /// @param blueprint Blueprint to spawn. + /// @param withName Whether to use the entity names from the blueprint. /// @return Map of entity names to their identifiers. - std::unordered_map spawn(const Blueprint& blueprint); + std::unordered_map spawn(const Blueprint& blueprint, bool withName); /// @brief Adds a component to an entity. /// @param entity Entity identifier. diff --git a/core/include/cubos/core/ecs/system/arguments/commands.hpp b/core/include/cubos/core/ecs/system/arguments/commands.hpp index 6d768d0f21..63d6c4a5e2 100644 --- a/core/include/cubos/core/ecs/system/arguments/commands.hpp +++ b/core/include/cubos/core/ecs/system/arguments/commands.hpp @@ -46,8 +46,9 @@ namespace cubos::core::ecs /// @brief Spawns a blueprint into the world. /// @param blueprint Blueprint to spawn. + /// @param withName Whether to use the entity names from the blueprint. /// @return Blueprint builder. - BlueprintBuilder spawn(const Blueprint& blueprint); + BlueprintBuilder spawn(const Blueprint& blueprint, bool withName); /// @brief Adds a component to an entity. /// @param entity Entity identifier. diff --git a/core/include/cubos/core/io/cursor.hpp b/core/include/cubos/core/io/cursor.hpp index eea990e572..a35d8059f1 100644 --- a/core/include/cubos/core/io/cursor.hpp +++ b/core/include/cubos/core/io/cursor.hpp @@ -4,6 +4,8 @@ #pragma once +#include + #ifdef WITH_GLFW #define GLFW_INCLUDE_NONE #include @@ -43,3 +45,5 @@ namespace cubos::core::io #endif }; } // namespace cubos::core::io + +CUBOS_REFLECT_EXTERNAL_DECL(cubos::core::io::Cursor::Standard); diff --git a/core/include/cubos/core/io/gamepad.hpp b/core/include/cubos/core/io/gamepad.hpp index 9914b97677..1738ceff1c 100644 --- a/core/include/cubos/core/io/gamepad.hpp +++ b/core/include/cubos/core/io/gamepad.hpp @@ -6,6 +6,8 @@ #include +#include + namespace cubos::core::io { /// @brief Gamepad buttons. @@ -100,3 +102,6 @@ namespace cubos::core::io /// @ingroup core-io GamepadAxis stringToGamepadAxis(const std::string& str); } // namespace cubos::core::io + +CUBOS_REFLECT_EXTERNAL_DECL(cubos::core::io::GamepadButton); +CUBOS_REFLECT_EXTERNAL_DECL(cubos::core::io::GamepadAxis); diff --git a/core/include/cubos/core/io/keyboard.hpp b/core/include/cubos/core/io/keyboard.hpp index 9981a23e8b..354b3c878a 100644 --- a/core/include/cubos/core/io/keyboard.hpp +++ b/core/include/cubos/core/io/keyboard.hpp @@ -6,6 +6,8 @@ #include +#include + namespace cubos::core::io { /// @brief Keyboard key codes enum. @@ -173,3 +175,6 @@ namespace cubos::core::io /// @ingroup core-io Key stringToKey(const std::string& str); } // namespace cubos::core::io + +CUBOS_REFLECT_EXTERNAL_DECL(cubos::core::io::Key); +CUBOS_REFLECT_EXTERNAL_DECL(cubos::core::io::Modifiers); diff --git a/core/include/cubos/core/io/window.hpp b/core/include/cubos/core/io/window.hpp index a478684ccd..0333add59b 100644 --- a/core/include/cubos/core/io/window.hpp +++ b/core/include/cubos/core/io/window.hpp @@ -15,6 +15,7 @@ #include #include #include +#include namespace cubos::core::gl { @@ -258,3 +259,7 @@ namespace cubos::core::io std::deque mEvents; }; } // namespace cubos::core::io + +CUBOS_REFLECT_EXTERNAL_DECL(cubos::core::io::MouseButton); +CUBOS_REFLECT_EXTERNAL_DECL(cubos::core::io::MouseAxis); +CUBOS_REFLECT_EXTERNAL_DECL(cubos::core::io::MouseState); diff --git a/core/include/cubos/core/memory/any_value.hpp b/core/include/cubos/core/memory/any_value.hpp index 490d500f18..6863b21722 100644 --- a/core/include/cubos/core/memory/any_value.hpp +++ b/core/include/cubos/core/memory/any_value.hpp @@ -25,6 +25,10 @@ namespace cubos::core::memory /// @param other Value. AnyValue(AnyValue&& other) noexcept; + /// @brief Copy constructs. + /// @param other Value. + AnyValue(const AnyValue& other) noexcept; + /// @brief Move assignment. /// @param other Value. AnyValue& operator=(AnyValue&& other) noexcept; diff --git a/core/include/cubos/core/reflection/comparison.hpp b/core/include/cubos/core/reflection/comparison.hpp new file mode 100644 index 0000000000..58ff65afe0 --- /dev/null +++ b/core/include/cubos/core/reflection/comparison.hpp @@ -0,0 +1,15 @@ +/// @file +/// @brief Function @ref cubos::core::reflection::compare. +/// @ingroup core-reflection +#include + +namespace cubos::core::reflection +{ + /// @brief Compares two instances of the same type. + /// @param type The type of the data being compared + /// @param a One of the instances. + /// @param b The other instance. + /// @note If the type has no comparable trait, this function will abort. + /// @return True if the values are equal, false otherwise. + bool compare(const Type& type, void* a, void* b); +} // namespace cubos::core::reflection diff --git a/core/src/cubos/core/al/audio_device.cpp b/core/src/al/audio_device.cpp similarity index 100% rename from core/src/cubos/core/al/audio_device.cpp rename to core/src/al/audio_device.cpp diff --git a/core/src/cubos/core/al/oal_audio_device.cpp b/core/src/al/oal_audio_device.cpp similarity index 100% rename from core/src/cubos/core/al/oal_audio_device.cpp rename to core/src/al/oal_audio_device.cpp diff --git a/core/src/cubos/core/al/oal_audio_device.hpp b/core/src/al/oal_audio_device.hpp similarity index 100% rename from core/src/cubos/core/al/oal_audio_device.hpp rename to core/src/al/oal_audio_device.hpp diff --git a/core/src/cubos/core/io/cursor.cpp b/core/src/cubos/core/io/cursor.cpp deleted file mode 100644 index a0f4404bbf..0000000000 --- a/core/src/cubos/core/io/cursor.cpp +++ /dev/null @@ -1,20 +0,0 @@ -#include - -using namespace cubos::core; - -#ifdef WITH_GLFW -io::Cursor::Cursor(GLFWcursor* handle) -{ - mGlfwHandle = handle; -} -#endif - -io::Cursor::~Cursor() -{ -#ifdef WITH_GLFW - if (mGlfwHandle != nullptr) - { - glfwDestroyCursor(mGlfwHandle); - } -#endif -} diff --git a/core/src/cubos/core/io/gamepad.cpp b/core/src/cubos/core/io/gamepad.cpp deleted file mode 100644 index 56d8043959..0000000000 --- a/core/src/cubos/core/io/gamepad.cpp +++ /dev/null @@ -1,125 +0,0 @@ -#include -#include -#include - -using cubos::core::data::old::Deserializer; -using cubos::core::data::old::Serializer; -using cubos::core::io::GamepadAxis; -using cubos::core::io::GamepadButton; -using namespace cubos::core; - -std::string io::gamepadButtonToString(GamepadButton button) -{ -#define MAP_BUTTON_TO_STRING(button, string) \ - case GamepadButton::button: \ - return string; - switch (button) - { - MAP_BUTTON_TO_STRING(A, "A") - MAP_BUTTON_TO_STRING(B, "B") - MAP_BUTTON_TO_STRING(X, "X") - MAP_BUTTON_TO_STRING(Y, "Y") - MAP_BUTTON_TO_STRING(LBumper, "LBumper") - MAP_BUTTON_TO_STRING(RBumper, "RBumper") - MAP_BUTTON_TO_STRING(Back, "Back") - MAP_BUTTON_TO_STRING(Start, "Start") - MAP_BUTTON_TO_STRING(Guide, "Guide") - MAP_BUTTON_TO_STRING(LThumb, "LThumb") - MAP_BUTTON_TO_STRING(RThumb, "RThumb") - MAP_BUTTON_TO_STRING(Up, "Up") - MAP_BUTTON_TO_STRING(Right, "Right") - MAP_BUTTON_TO_STRING(Down, "Down") - MAP_BUTTON_TO_STRING(Left, "Left") - default: - return "Invalid"; - } -#undef MAP_KEY_TO_STRING -} - -template <> -void data::old::serialize(Serializer& ser, const GamepadButton& obj, const char* name) -{ - ser.write(io::gamepadButtonToString(obj), name); -} - -GamepadButton io::stringToGamepadButton(const std::string& str) -{ -#define MAP_STRING_TO_BUTTON(string, button) \ - if (str == (string)) \ - return GamepadButton::button; - MAP_STRING_TO_BUTTON("A", A) - MAP_STRING_TO_BUTTON("B", B) - MAP_STRING_TO_BUTTON("X", X) - MAP_STRING_TO_BUTTON("Y", Y) - MAP_STRING_TO_BUTTON("LBumper", LBumper) - MAP_STRING_TO_BUTTON("RBumper", RBumper) - MAP_STRING_TO_BUTTON("Back", Back) - MAP_STRING_TO_BUTTON("Start", Start) - MAP_STRING_TO_BUTTON("Guide", Guide) - MAP_STRING_TO_BUTTON("LThumb", LThumb) - MAP_STRING_TO_BUTTON("RThumb", RThumb) - MAP_STRING_TO_BUTTON("Up", Up) - MAP_STRING_TO_BUTTON("Right", Right) - MAP_STRING_TO_BUTTON("Down", Down) - MAP_STRING_TO_BUTTON("Left", Left) - // else - return GamepadButton::Invalid; -#undef MAP_STRING_TO_BUTTON -} - -template <> -void data::old::deserialize(Deserializer& des, GamepadButton& obj) -{ - std::string axis; - des.read(axis); - obj = io::stringToGamepadButton(axis); -} - -std::string io::gamepadAxisToString(GamepadAxis axis) -{ -#define MAP_AXIS_TO_STRING(axis, string) \ - case GamepadAxis::axis: \ - return string; - switch (axis) - { - MAP_AXIS_TO_STRING(LX, "LX") - MAP_AXIS_TO_STRING(LY, "LY") - MAP_AXIS_TO_STRING(RX, "RX") - MAP_AXIS_TO_STRING(RY, "RY") - MAP_AXIS_TO_STRING(LTrigger, "LTrigger") - MAP_AXIS_TO_STRING(RTrigger, "RTrigger") - default: - return "Invalid"; - } -#undef MAP_AXIS_TO_STRING -} - -template <> -void data::old::serialize(Serializer& ser, const GamepadAxis& obj, const char* name) -{ - ser.write(io::gamepadAxisToString(obj), name); -} - -GamepadAxis io::stringToGamepadAxis(const std::string& str) -{ -#define MAP_STRING_TO_AXIS(string, axis) \ - if (str == (string)) \ - return GamepadAxis::axis; - MAP_STRING_TO_AXIS("LX", LX) - MAP_STRING_TO_AXIS("LY", LY) - MAP_STRING_TO_AXIS("RX", RX) - MAP_STRING_TO_AXIS("RY", RY) - MAP_STRING_TO_AXIS("LTrigger", LTrigger) - MAP_STRING_TO_AXIS("RTrigger", RTrigger) - // else - return GamepadAxis::Invalid; -#undef MAP_STRING_TO_AXIS -} - -template <> -void data::old::deserialize(Deserializer& des, GamepadAxis& obj) -{ - std::string axis; - des.read(axis); - obj = io::stringToGamepadAxis(axis); -} diff --git a/core/src/cubos/core/io/keyboard.cpp b/core/src/cubos/core/io/keyboard.cpp deleted file mode 100644 index eae5c873d1..0000000000 --- a/core/src/cubos/core/io/keyboard.cpp +++ /dev/null @@ -1,310 +0,0 @@ -#include -#include -#include - -using cubos::core::data::old::Deserializer; -using cubos::core::data::old::Serializer; -using cubos::core::io::Key; -using cubos::core::io::Modifiers; -using namespace cubos::core; - -std::string io::modifiersToString(Modifiers modifiers) -{ - std::string result; - - if ((modifiers & Modifiers::Control) != Modifiers::None) - { - result += "C-"; - } - - if ((modifiers & Modifiers::Shift) != Modifiers::None) - { - result += "S-"; - } - - if ((modifiers & Modifiers::Alt) != Modifiers::None) - { - result += "M-"; - } - - if ((modifiers & Modifiers::System) != Modifiers::None) - { - result += "D-"; - } - - return result; -} - -template <> -void data::old::serialize(Serializer& ser, const Modifiers& obj, const char* name) -{ - ser.write(io::modifiersToString(obj), name); -} - -Modifiers io::stringToModifiers(const std::string& str) -{ - Modifiers result = Modifiers::None; - - if (str.find("C-") != std::string::npos) - { - result |= Modifiers::Control; - } - - if (str.find("S-") != std::string::npos) - { - result |= Modifiers::Shift; - } - - if (str.find("M-") != std::string::npos) - { - result |= Modifiers::Alt; - } - - if (str.find("D-") != std::string::npos) - { - result |= Modifiers::System; - } - - return result; -} - -template <> -void data::old::deserialize(Deserializer& des, Modifiers& obj) -{ - std::string str; - des.read(str); - obj = io::stringToModifiers(str); -} - -std::string io::keyToString(Key key) -{ -#define MAP_KEY_TO_STRING(key, string) \ - case Key::key: \ - return (string); - switch (key) - { - MAP_KEY_TO_STRING(A, "a") - MAP_KEY_TO_STRING(B, "b") - MAP_KEY_TO_STRING(C, "c") - MAP_KEY_TO_STRING(D, "d") - MAP_KEY_TO_STRING(E, "e") - MAP_KEY_TO_STRING(F, "f") - MAP_KEY_TO_STRING(G, "g") - MAP_KEY_TO_STRING(H, "h") - MAP_KEY_TO_STRING(I, "i") - MAP_KEY_TO_STRING(J, "j") - MAP_KEY_TO_STRING(K, "k") - MAP_KEY_TO_STRING(L, "l") - MAP_KEY_TO_STRING(M, "m") - MAP_KEY_TO_STRING(N, "n") - MAP_KEY_TO_STRING(O, "o") - MAP_KEY_TO_STRING(P, "p") - MAP_KEY_TO_STRING(Q, "q") - MAP_KEY_TO_STRING(R, "r") - MAP_KEY_TO_STRING(S, "s") - MAP_KEY_TO_STRING(T, "t") - MAP_KEY_TO_STRING(U, "u") - MAP_KEY_TO_STRING(V, "v") - MAP_KEY_TO_STRING(W, "w") - MAP_KEY_TO_STRING(X, "x") - MAP_KEY_TO_STRING(Y, "y") - MAP_KEY_TO_STRING(Z, "z") - MAP_KEY_TO_STRING(Num0, "0") - MAP_KEY_TO_STRING(Num1, "1") - MAP_KEY_TO_STRING(Num2, "2") - MAP_KEY_TO_STRING(Num3, "3") - MAP_KEY_TO_STRING(Num4, "4") - MAP_KEY_TO_STRING(Num5, "5") - MAP_KEY_TO_STRING(Num6, "6") - MAP_KEY_TO_STRING(Num7, "7") - MAP_KEY_TO_STRING(Num8, "8") - MAP_KEY_TO_STRING(Num9, "9") - MAP_KEY_TO_STRING(Escape, "Escape") - MAP_KEY_TO_STRING(LControl, "LControl") - MAP_KEY_TO_STRING(LShift, "LShift") - MAP_KEY_TO_STRING(LAlt, "LAlt") - MAP_KEY_TO_STRING(LSystem, "LSystem") - MAP_KEY_TO_STRING(RControl, "RControl") - MAP_KEY_TO_STRING(RShift, "RShift") - MAP_KEY_TO_STRING(RAlt, "RAlt") - MAP_KEY_TO_STRING(RSystem, "RSystem") - MAP_KEY_TO_STRING(Menu, "Menu") - MAP_KEY_TO_STRING(LBracket, "LBracket") - MAP_KEY_TO_STRING(RBracket, "RBracket") - MAP_KEY_TO_STRING(SemiColon, "SemiColon") - MAP_KEY_TO_STRING(Comma, "Comma") - MAP_KEY_TO_STRING(Period, "Period") - MAP_KEY_TO_STRING(Quote, "Quote") - MAP_KEY_TO_STRING(Slash, "Slash") - MAP_KEY_TO_STRING(BackSlash, "BackSlash") - MAP_KEY_TO_STRING(Tilde, "Tilde") - MAP_KEY_TO_STRING(Equal, "Equal") - MAP_KEY_TO_STRING(Dash, "Dash") - MAP_KEY_TO_STRING(Space, "Space") - MAP_KEY_TO_STRING(Return, "Return") - MAP_KEY_TO_STRING(BackSpace, "BackSpace") - MAP_KEY_TO_STRING(Tab, "Tab") - MAP_KEY_TO_STRING(PageUp, "PageUp") - MAP_KEY_TO_STRING(PageDown, "PageDown") - MAP_KEY_TO_STRING(End, "End") - MAP_KEY_TO_STRING(Home, "Home") - MAP_KEY_TO_STRING(Insert, "Insert") - MAP_KEY_TO_STRING(Delete, "Delete") - MAP_KEY_TO_STRING(Add, "Add") - MAP_KEY_TO_STRING(Subtract, "Subtract") - MAP_KEY_TO_STRING(Multiply, "Multiply") - MAP_KEY_TO_STRING(Divide, "Divide") - MAP_KEY_TO_STRING(Left, "Left") - MAP_KEY_TO_STRING(Right, "Right") - MAP_KEY_TO_STRING(Up, "Up") - MAP_KEY_TO_STRING(Down, "Down") - MAP_KEY_TO_STRING(Numpad0, "Numpad0") - MAP_KEY_TO_STRING(Numpad1, "Numpad1") - MAP_KEY_TO_STRING(Numpad2, "Numpad2") - MAP_KEY_TO_STRING(Numpad3, "Numpad3") - MAP_KEY_TO_STRING(Numpad4, "Numpad4") - MAP_KEY_TO_STRING(Numpad5, "Numpad5") - MAP_KEY_TO_STRING(Numpad6, "Numpad6") - MAP_KEY_TO_STRING(Numpad7, "Numpad7") - MAP_KEY_TO_STRING(Numpad8, "Numpad8") - MAP_KEY_TO_STRING(Numpad9, "Numpad9") - MAP_KEY_TO_STRING(F1, "F1") - MAP_KEY_TO_STRING(F2, "F2") - MAP_KEY_TO_STRING(F3, "F3") - MAP_KEY_TO_STRING(F4, "F4") - MAP_KEY_TO_STRING(F5, "F5") - MAP_KEY_TO_STRING(F6, "F6") - MAP_KEY_TO_STRING(F7, "F7") - MAP_KEY_TO_STRING(F8, "F8") - MAP_KEY_TO_STRING(F9, "F9") - MAP_KEY_TO_STRING(F10, "F10") - MAP_KEY_TO_STRING(F11, "F11") - MAP_KEY_TO_STRING(F12, "F12") - MAP_KEY_TO_STRING(Pause, "Pause") - default: - return "Invalid"; - } -#undef MAP_KEY_TO_STRING -} - -template <> -void data::old::serialize(Serializer& ser, const Key& obj, const char* name) -{ - ser.write(io::keyToString(obj), name); -} - -Key io::stringToKey(const std::string& str) -{ -#define MAP_STRING_TO_KEY(string, key) \ - if (str == (string)) \ - return Key::key; - MAP_STRING_TO_KEY("a", A) - MAP_STRING_TO_KEY("b", B) - MAP_STRING_TO_KEY("c", C) - MAP_STRING_TO_KEY("d", D) - MAP_STRING_TO_KEY("e", E) - MAP_STRING_TO_KEY("f", F) - MAP_STRING_TO_KEY("g", G) - MAP_STRING_TO_KEY("h", H) - MAP_STRING_TO_KEY("i", I) - MAP_STRING_TO_KEY("j", J) - MAP_STRING_TO_KEY("k", K) - MAP_STRING_TO_KEY("l", L) - MAP_STRING_TO_KEY("m", M) - MAP_STRING_TO_KEY("n", N) - MAP_STRING_TO_KEY("o", O) - MAP_STRING_TO_KEY("p", P) - MAP_STRING_TO_KEY("q", Q) - MAP_STRING_TO_KEY("r", R) - MAP_STRING_TO_KEY("s", S) - MAP_STRING_TO_KEY("t", T) - MAP_STRING_TO_KEY("u", U) - MAP_STRING_TO_KEY("v", V) - MAP_STRING_TO_KEY("w", W) - MAP_STRING_TO_KEY("x", X) - MAP_STRING_TO_KEY("y", Y) - MAP_STRING_TO_KEY("z", Z) - MAP_STRING_TO_KEY("0", Num0) - MAP_STRING_TO_KEY("1", Num1) - MAP_STRING_TO_KEY("2", Num2) - MAP_STRING_TO_KEY("3", Num3) - MAP_STRING_TO_KEY("4", Num4) - MAP_STRING_TO_KEY("5", Num5) - MAP_STRING_TO_KEY("6", Num6) - MAP_STRING_TO_KEY("7", Num7) - MAP_STRING_TO_KEY("8", Num8) - MAP_STRING_TO_KEY("9", Num9) - MAP_STRING_TO_KEY("Escape", Escape) - MAP_STRING_TO_KEY("LControl", LControl) - MAP_STRING_TO_KEY("LShift", LShift) - MAP_STRING_TO_KEY("LAlt", LAlt) - MAP_STRING_TO_KEY("LSystem", LSystem) - MAP_STRING_TO_KEY("RControl", RControl) - MAP_STRING_TO_KEY("RShift", RShift) - MAP_STRING_TO_KEY("RAlt", RAlt) - MAP_STRING_TO_KEY("RSystem", RSystem) - MAP_STRING_TO_KEY("Menu", Menu) - MAP_STRING_TO_KEY("LBracket", LBracket) - MAP_STRING_TO_KEY("RBracket", RBracket) - MAP_STRING_TO_KEY("SemiColon", SemiColon) - MAP_STRING_TO_KEY("Comma", Comma) - MAP_STRING_TO_KEY("Period", Period) - MAP_STRING_TO_KEY("Quote", Quote) - MAP_STRING_TO_KEY("Slash", Slash) - MAP_STRING_TO_KEY("BackSlash", BackSlash) - MAP_STRING_TO_KEY("Tilde", Tilde) - MAP_STRING_TO_KEY("Equal", Equal) - MAP_STRING_TO_KEY("Dash", Dash) - MAP_STRING_TO_KEY("Space", Space) - MAP_STRING_TO_KEY("Return", Return) - MAP_STRING_TO_KEY("BackSpace", BackSpace) - MAP_STRING_TO_KEY("Tab", Tab) - MAP_STRING_TO_KEY("PageUp", PageUp) - MAP_STRING_TO_KEY("PageDown", PageDown) - MAP_STRING_TO_KEY("End", End) - MAP_STRING_TO_KEY("Home", Home) - MAP_STRING_TO_KEY("Insert", Insert) - MAP_STRING_TO_KEY("Delete", Delete) - MAP_STRING_TO_KEY("Add", Add) - MAP_STRING_TO_KEY("Subtract", Subtract) - MAP_STRING_TO_KEY("Multiply", Multiply) - MAP_STRING_TO_KEY("Divide", Divide) - MAP_STRING_TO_KEY("Left", Left) - MAP_STRING_TO_KEY("Right", Right) - MAP_STRING_TO_KEY("Up", Up) - MAP_STRING_TO_KEY("Down", Down) - MAP_STRING_TO_KEY("Numpad0", Numpad0) - MAP_STRING_TO_KEY("Numpad1", Numpad1) - MAP_STRING_TO_KEY("Numpad2", Numpad2) - MAP_STRING_TO_KEY("Numpad3", Numpad3) - MAP_STRING_TO_KEY("Numpad4", Numpad4) - MAP_STRING_TO_KEY("Numpad5", Numpad5) - MAP_STRING_TO_KEY("Numpad6", Numpad6) - MAP_STRING_TO_KEY("Numpad7", Numpad7) - MAP_STRING_TO_KEY("Numpad8", Numpad8) - MAP_STRING_TO_KEY("Numpad9", Numpad9) - MAP_STRING_TO_KEY("F1", F1) - MAP_STRING_TO_KEY("F2", F2) - MAP_STRING_TO_KEY("F3", F3) - MAP_STRING_TO_KEY("F4", F4) - MAP_STRING_TO_KEY("F5", F5) - MAP_STRING_TO_KEY("F6", F6) - MAP_STRING_TO_KEY("F7", F7) - MAP_STRING_TO_KEY("F8", F8) - MAP_STRING_TO_KEY("F9", F9) - MAP_STRING_TO_KEY("F10", F10) - MAP_STRING_TO_KEY("F11", F11) - MAP_STRING_TO_KEY("F12", F12) - MAP_STRING_TO_KEY("Pause", Pause) - // else - return Key::Invalid; -#undef MAP_STRING_TO_KEY -} - -template <> -void data::old::deserialize(Deserializer& des, Key& obj) -{ - std::string str; - des.read(str); - obj = io::stringToKey(str); -} diff --git a/core/src/cubos/core/io/window.cpp b/core/src/cubos/core/io/window.cpp deleted file mode 100644 index cc08969821..0000000000 --- a/core/src/cubos/core/io/window.cpp +++ /dev/null @@ -1,92 +0,0 @@ -#include -#include -#include - -#include "glfw_window.hpp" - -using namespace cubos::core::io; -using cubos::core::data::old::Deserializer; -using cubos::core::data::old::Serializer; - -Window cubos::core::io::openWindow(const std::string& title, const glm::ivec2& size) -{ - return std::make_shared(title, size); -} - -std::string cubos::core::io::mouseButtonToString(MouseButton button) -{ -#define MAP_BUTTON_TO_STRING(button, string) \ - case MouseButton::button: \ - return string; - switch (button) - { - MAP_BUTTON_TO_STRING(Left, "Left") - MAP_BUTTON_TO_STRING(Right, "Right") - MAP_BUTTON_TO_STRING(Middle, "Middle") - MAP_BUTTON_TO_STRING(Extra1, "Extra1") - MAP_BUTTON_TO_STRING(Extra2, "Extra2") - default: - return "Invalid"; - } -#undef MAP_KEY_TO_STRING -} - -template <> -void cubos::core::data::old::serialize(Serializer& ser, const MouseButton& obj, const char* name) -{ - ser.write(io::mouseButtonToString(obj), name); -} - -MouseButton cubos::core::io::stringToMouseButton(const std::string& str) -{ -#define MAP_STRING_TO_BUTTON(string, button) \ - if (str == (string)) \ - return MouseButton::button; - MAP_STRING_TO_BUTTON("Left", Left) - MAP_STRING_TO_BUTTON("Right", Right) - MAP_STRING_TO_BUTTON("Middle", Middle) - MAP_STRING_TO_BUTTON("Extra1", Extra1) - MAP_STRING_TO_BUTTON("Extra2", Extra2) - // else - return MouseButton::Invalid; -#undef MAP_STRING_TO_BUTTON -} - -template <> -void cubos::core::data::old::deserialize(Deserializer& des, MouseButton& obj) -{ - std::string axis; - des.read(axis); - obj = io::stringToMouseButton(axis); -} - -BaseWindow::BaseWindow() -{ - mPolled = false; -} - -void BaseWindow::pushEvent(WindowEvent&& event) -{ - mEvents.push_back(event); -} - -std::optional BaseWindow::pollEvent() -{ - // Only poll events after pollEvent() has returned std::nullopt (or if it has never been called). - if (!mPolled) - { - this->pollEvents(); - mPolled = true; - } - - // No more events, we're done for now, but we need to poll again next time. - if (mEvents.empty()) - { - mPolled = false; - return std::nullopt; - } - - WindowEvent event = mEvents.front(); - mEvents.pop_front(); - return event; -} diff --git a/core/src/cubos/core/data/des/deserializer.cpp b/core/src/data/des/deserializer.cpp similarity index 100% rename from core/src/cubos/core/data/des/deserializer.cpp rename to core/src/data/des/deserializer.cpp diff --git a/core/src/cubos/core/data/des/json.cpp b/core/src/data/des/json.cpp similarity index 100% rename from core/src/cubos/core/data/des/json.cpp rename to core/src/data/des/json.cpp diff --git a/core/src/cubos/core/data/fs/embedded_archive.cpp b/core/src/data/fs/embedded_archive.cpp similarity index 100% rename from core/src/cubos/core/data/fs/embedded_archive.cpp rename to core/src/data/fs/embedded_archive.cpp diff --git a/core/src/cubos/core/data/fs/file.cpp b/core/src/data/fs/file.cpp similarity index 100% rename from core/src/cubos/core/data/fs/file.cpp rename to core/src/data/fs/file.cpp diff --git a/core/src/cubos/core/data/fs/file_system.cpp b/core/src/data/fs/file_system.cpp similarity index 100% rename from core/src/cubos/core/data/fs/file_system.cpp rename to core/src/data/fs/file_system.cpp diff --git a/core/src/cubos/core/data/fs/standard_archive.cpp b/core/src/data/fs/standard_archive.cpp similarity index 100% rename from core/src/cubos/core/data/fs/standard_archive.cpp rename to core/src/data/fs/standard_archive.cpp diff --git a/core/src/cubos/core/data/old/binary_deserializer.cpp b/core/src/data/old/binary_deserializer.cpp similarity index 100% rename from core/src/cubos/core/data/old/binary_deserializer.cpp rename to core/src/data/old/binary_deserializer.cpp diff --git a/core/src/cubos/core/data/old/binary_serializer.cpp b/core/src/data/old/binary_serializer.cpp similarity index 100% rename from core/src/cubos/core/data/old/binary_serializer.cpp rename to core/src/data/old/binary_serializer.cpp diff --git a/core/src/cubos/core/data/old/context.cpp b/core/src/data/old/context.cpp similarity index 100% rename from core/src/cubos/core/data/old/context.cpp rename to core/src/data/old/context.cpp diff --git a/core/src/cubos/core/data/old/deserializer.cpp b/core/src/data/old/deserializer.cpp similarity index 100% rename from core/src/cubos/core/data/old/deserializer.cpp rename to core/src/data/old/deserializer.cpp diff --git a/core/src/cubos/core/data/old/json_deserializer.cpp b/core/src/data/old/json_deserializer.cpp similarity index 100% rename from core/src/cubos/core/data/old/json_deserializer.cpp rename to core/src/data/old/json_deserializer.cpp diff --git a/core/src/cubos/core/data/old/json_serializer.cpp b/core/src/data/old/json_serializer.cpp similarity index 100% rename from core/src/cubos/core/data/old/json_serializer.cpp rename to core/src/data/old/json_serializer.cpp diff --git a/core/src/cubos/core/data/old/package.cpp b/core/src/data/old/package.cpp similarity index 100% rename from core/src/cubos/core/data/old/package.cpp rename to core/src/data/old/package.cpp diff --git a/core/src/cubos/core/data/old/serializer.cpp b/core/src/data/old/serializer.cpp similarity index 100% rename from core/src/cubos/core/data/old/serializer.cpp rename to core/src/data/old/serializer.cpp diff --git a/core/src/cubos/core/data/ser/debug.cpp b/core/src/data/ser/debug.cpp similarity index 100% rename from core/src/cubos/core/data/ser/debug.cpp rename to core/src/data/ser/debug.cpp diff --git a/core/src/cubos/core/data/ser/json.cpp b/core/src/data/ser/json.cpp similarity index 90% rename from core/src/cubos/core/data/ser/json.cpp rename to core/src/data/ser/json.cpp index 1affc5af85..ef52752365 100644 --- a/core/src/cubos/core/data/ser/json.cpp +++ b/core/src/data/ser/json.cpp @@ -94,6 +94,18 @@ bool JSONSerializer::decompose(const Type& type, const void* value) if (type.has()) { + if (type.get().size() == 1) + { + // If there's a single field, write it directly. + if (!this->write(type.get().begin()->type(), + type.get().view(value).begin()->value)) + { + CUBOS_WARN("Couldn't serialize wrapped field '{}'", type.get().begin()->name()); + return false; + } + + return true; + } auto jsonObj = nlohmann::json::object(); for (const auto& [field, fieldValue] : type.get().view(value)) diff --git a/core/src/cubos/core/data/ser/serializer.cpp b/core/src/data/ser/serializer.cpp similarity index 100% rename from core/src/cubos/core/data/ser/serializer.cpp rename to core/src/data/ser/serializer.cpp diff --git a/core/src/cubos/core/ecs/blueprint.cpp b/core/src/ecs/blueprint.cpp similarity index 96% rename from core/src/cubos/core/ecs/blueprint.cpp rename to core/src/ecs/blueprint.cpp index 9802926d98..357bfa356e 100644 --- a/core/src/cubos/core/ecs/blueprint.cpp +++ b/core/src/ecs/blueprint.cpp @@ -20,10 +20,6 @@ using cubos::core::reflection::ConstructibleTrait; using cubos::core::reflection::reflect; using cubos::core::reflection::Type; -Blueprint::Blueprint() = default; - -Blueprint::Blueprint(Blueprint&& other) noexcept = default; - Entity Blueprint::create(std::string name) { CUBOS_ASSERT(!mBimap.containsRight(name), "An entity with the name '{}' already exists on the blueprint", name); @@ -82,7 +78,7 @@ void Blueprint::relate(Entity fromEntity, Entity toEntity, AnyValue relation) mRelations.at(relation.type())[fromEntity].insert_or_assign(toEntity, std::move(relation)); } -void Blueprint::merge(const std::string& prefix, const Blueprint& other) +void Blueprint::merge(const std::string& prefix, const Blueprint& other, bool withName) { other.instantiate( [&](std::string name) -> Entity { @@ -98,7 +94,7 @@ void Blueprint::merge(const std::string& prefix, const Blueprint& other) [&](Entity entity, AnyValue component) { this->add(entity, std::move(component)); }, [&](Entity fromEntity, Entity toEntity, AnyValue relation) { this->relate(fromEntity, toEntity, std::move(relation)); - }); + }, withName); } void Blueprint::clear() @@ -157,15 +153,19 @@ static void convertToInstancedEntities(const std::unordered_map thisToInstance{}; for (const auto& [entity, name] : mBimap) { thisToInstance.emplace(entity, create(userData, name)); - Name nameComponent{name}; - add(userData, thisToInstance.at(entity), AnyValue::moveConstruct(reflect(), (void*)&nameComponent)); + + if (withName) + { + Name nameComponent{name}; + add(userData, thisToInstance.at(entity), AnyValue::moveConstruct(reflect(), (void*)&nameComponent)); + } } // Add copies of our components to their instantiated entities. Since the components themselves diff --git a/core/src/cubos/core/ecs/command_buffer.cpp b/core/src/ecs/command_buffer.cpp similarity index 97% rename from core/src/cubos/core/ecs/command_buffer.cpp rename to core/src/ecs/command_buffer.cpp index 924ebc9abc..81e5a69ff0 100644 --- a/core/src/cubos/core/ecs/command_buffer.cpp +++ b/core/src/ecs/command_buffer.cpp @@ -28,7 +28,7 @@ void CommandBuffer::destroy(Entity entity) mCommands.emplace_back([entity](World& world) { world.destroy(entity); }); } -std::unordered_map CommandBuffer::spawn(const Blueprint& blueprint) +std::unordered_map CommandBuffer::spawn(const Blueprint& blueprint, bool withName) { std::unordered_map nameToEntity{}; @@ -41,7 +41,7 @@ std::unordered_map CommandBuffer::spawn(const Blueprint& bl [&](Entity entity, memory::AnyValue component) { this->add(entity, component.type(), component.get()); }, [&](Entity fromEntity, Entity toEntity, memory::AnyValue relation) { this->relate(fromEntity, toEntity, relation.type(), relation.get()); - }); + }, withName); return nameToEntity; } diff --git a/core/src/cubos/core/ecs/cubos.cpp b/core/src/ecs/cubos.cpp similarity index 100% rename from core/src/cubos/core/ecs/cubos.cpp rename to core/src/ecs/cubos.cpp diff --git a/core/src/cubos/core/ecs/entity/archetype_graph.cpp b/core/src/ecs/entity/archetype_graph.cpp similarity index 100% rename from core/src/cubos/core/ecs/entity/archetype_graph.cpp rename to core/src/ecs/entity/archetype_graph.cpp diff --git a/core/src/cubos/core/ecs/entity/archetype_id.cpp b/core/src/ecs/entity/archetype_id.cpp similarity index 100% rename from core/src/cubos/core/ecs/entity/archetype_id.cpp rename to core/src/ecs/entity/archetype_id.cpp diff --git a/core/src/cubos/core/ecs/entity/entity.cpp b/core/src/ecs/entity/entity.cpp similarity index 100% rename from core/src/cubos/core/ecs/entity/entity.cpp rename to core/src/ecs/entity/entity.cpp diff --git a/core/src/cubos/core/ecs/entity/hash.cpp b/core/src/ecs/entity/hash.cpp similarity index 100% rename from core/src/cubos/core/ecs/entity/hash.cpp rename to core/src/ecs/entity/hash.cpp diff --git a/core/src/cubos/core/ecs/entity/pool.cpp b/core/src/ecs/entity/pool.cpp similarity index 100% rename from core/src/cubos/core/ecs/entity/pool.cpp rename to core/src/ecs/entity/pool.cpp diff --git a/core/src/cubos/core/ecs/name.cpp b/core/src/ecs/name.cpp similarity index 100% rename from core/src/cubos/core/ecs/name.cpp rename to core/src/ecs/name.cpp diff --git a/core/src/cubos/core/ecs/query/data.cpp b/core/src/ecs/query/data.cpp similarity index 100% rename from core/src/cubos/core/ecs/query/data.cpp rename to core/src/ecs/query/data.cpp diff --git a/core/src/cubos/core/ecs/query/fetcher.cpp b/core/src/ecs/query/fetcher.cpp similarity index 100% rename from core/src/cubos/core/ecs/query/fetcher.cpp rename to core/src/ecs/query/fetcher.cpp diff --git a/core/src/cubos/core/ecs/query/filter.cpp b/core/src/ecs/query/filter.cpp similarity index 100% rename from core/src/cubos/core/ecs/query/filter.cpp rename to core/src/ecs/query/filter.cpp diff --git a/core/src/cubos/core/ecs/query/opt.cpp b/core/src/ecs/query/opt.cpp similarity index 100% rename from core/src/cubos/core/ecs/query/opt.cpp rename to core/src/ecs/query/opt.cpp diff --git a/core/src/cubos/core/ecs/query/term.cpp b/core/src/ecs/query/term.cpp similarity index 100% rename from core/src/cubos/core/ecs/query/term.cpp rename to core/src/ecs/query/term.cpp diff --git a/core/src/cubos/core/ecs/reflection.cpp b/core/src/ecs/reflection.cpp similarity index 100% rename from core/src/cubos/core/ecs/reflection.cpp rename to core/src/ecs/reflection.cpp diff --git a/core/src/cubos/core/ecs/system/access.cpp b/core/src/ecs/system/access.cpp similarity index 100% rename from core/src/cubos/core/ecs/system/access.cpp rename to core/src/ecs/system/access.cpp diff --git a/core/src/cubos/core/ecs/system/arguments/commands.cpp b/core/src/ecs/system/arguments/commands.cpp similarity index 96% rename from core/src/cubos/core/ecs/system/arguments/commands.cpp rename to core/src/ecs/system/arguments/commands.cpp index 4e631eadc7..a6f06da3a8 100644 --- a/core/src/cubos/core/ecs/system/arguments/commands.cpp +++ b/core/src/ecs/system/arguments/commands.cpp @@ -22,9 +22,9 @@ void Commands::destroy(Entity entity) mBuffer.destroy(entity); } -Commands::BlueprintBuilder Commands::spawn(const Blueprint& blueprint) +Commands::BlueprintBuilder Commands::spawn(const Blueprint& blueprint, bool withName) { - auto nameToEntity = mBuffer.spawn(blueprint); + auto nameToEntity = mBuffer.spawn(blueprint, withName); return {mBuffer, std::move(nameToEntity)}; } diff --git a/core/src/cubos/core/ecs/system/arguments/query.cpp b/core/src/ecs/system/arguments/query.cpp similarity index 100% rename from core/src/cubos/core/ecs/system/arguments/query.cpp rename to core/src/ecs/system/arguments/query.cpp diff --git a/core/src/cubos/core/ecs/system/arguments/resources.cpp b/core/src/ecs/system/arguments/resources.cpp similarity index 100% rename from core/src/cubos/core/ecs/system/arguments/resources.cpp rename to core/src/ecs/system/arguments/resources.cpp diff --git a/core/src/cubos/core/ecs/system/arguments/world.cpp b/core/src/ecs/system/arguments/world.cpp similarity index 100% rename from core/src/cubos/core/ecs/system/arguments/world.cpp rename to core/src/ecs/system/arguments/world.cpp diff --git a/core/src/cubos/core/ecs/system/dispatcher.cpp b/core/src/ecs/system/dispatcher.cpp similarity index 100% rename from core/src/cubos/core/ecs/system/dispatcher.cpp rename to core/src/ecs/system/dispatcher.cpp diff --git a/core/src/cubos/core/ecs/system/options.cpp b/core/src/ecs/system/options.cpp similarity index 100% rename from core/src/cubos/core/ecs/system/options.cpp rename to core/src/ecs/system/options.cpp diff --git a/core/src/cubos/core/ecs/system/system.cpp b/core/src/ecs/system/system.cpp similarity index 100% rename from core/src/cubos/core/ecs/system/system.cpp rename to core/src/ecs/system/system.cpp diff --git a/core/src/cubos/core/ecs/table/column.cpp b/core/src/ecs/table/column.cpp similarity index 100% rename from core/src/cubos/core/ecs/table/column.cpp rename to core/src/ecs/table/column.cpp diff --git a/core/src/cubos/core/ecs/table/dense/registry.cpp b/core/src/ecs/table/dense/registry.cpp similarity index 100% rename from core/src/cubos/core/ecs/table/dense/registry.cpp rename to core/src/ecs/table/dense/registry.cpp diff --git a/core/src/cubos/core/ecs/table/dense/table.cpp b/core/src/ecs/table/dense/table.cpp similarity index 100% rename from core/src/cubos/core/ecs/table/dense/table.cpp rename to core/src/ecs/table/dense/table.cpp diff --git a/core/src/cubos/core/ecs/table/sparse_relation/id.cpp b/core/src/ecs/table/sparse_relation/id.cpp similarity index 100% rename from core/src/cubos/core/ecs/table/sparse_relation/id.cpp rename to core/src/ecs/table/sparse_relation/id.cpp diff --git a/core/src/cubos/core/ecs/table/sparse_relation/registry.cpp b/core/src/ecs/table/sparse_relation/registry.cpp similarity index 100% rename from core/src/cubos/core/ecs/table/sparse_relation/registry.cpp rename to core/src/ecs/table/sparse_relation/registry.cpp diff --git a/core/src/cubos/core/ecs/table/sparse_relation/table.cpp b/core/src/ecs/table/sparse_relation/table.cpp similarity index 100% rename from core/src/cubos/core/ecs/table/sparse_relation/table.cpp rename to core/src/ecs/table/sparse_relation/table.cpp diff --git a/core/src/cubos/core/ecs/table/tables.cpp b/core/src/ecs/table/tables.cpp similarity index 100% rename from core/src/cubos/core/ecs/table/tables.cpp rename to core/src/ecs/table/tables.cpp diff --git a/core/src/cubos/core/ecs/types.cpp b/core/src/ecs/types.cpp similarity index 100% rename from core/src/cubos/core/ecs/types.cpp rename to core/src/ecs/types.cpp diff --git a/core/src/cubos/core/ecs/world.cpp b/core/src/ecs/world.cpp similarity index 100% rename from core/src/cubos/core/ecs/world.cpp rename to core/src/ecs/world.cpp diff --git a/core/src/cubos/core/geom/box.cpp b/core/src/geom/box.cpp similarity index 100% rename from core/src/cubos/core/geom/box.cpp rename to core/src/geom/box.cpp diff --git a/core/src/cubos/core/geom/capsule.cpp b/core/src/geom/capsule.cpp similarity index 100% rename from core/src/cubos/core/geom/capsule.cpp rename to core/src/geom/capsule.cpp diff --git a/core/src/cubos/core/gl/debug.cpp b/core/src/gl/debug.cpp similarity index 100% rename from core/src/cubos/core/gl/debug.cpp rename to core/src/gl/debug.cpp diff --git a/core/src/cubos/core/gl/ogl_render_device.cpp b/core/src/gl/ogl_render_device.cpp similarity index 100% rename from core/src/cubos/core/gl/ogl_render_device.cpp rename to core/src/gl/ogl_render_device.cpp diff --git a/core/src/cubos/core/gl/ogl_render_device.hpp b/core/src/gl/ogl_render_device.hpp similarity index 100% rename from core/src/cubos/core/gl/ogl_render_device.hpp rename to core/src/gl/ogl_render_device.hpp diff --git a/core/src/cubos/core/gl/render_device.cpp b/core/src/gl/render_device.cpp similarity index 100% rename from core/src/cubos/core/gl/render_device.cpp rename to core/src/gl/render_device.cpp diff --git a/core/src/cubos/core/gl/util.cpp b/core/src/gl/util.cpp similarity index 100% rename from core/src/cubos/core/gl/util.cpp rename to core/src/gl/util.cpp diff --git a/core/src/io/cursor.cpp b/core/src/io/cursor.cpp new file mode 100644 index 0000000000..ab6b198dc0 --- /dev/null +++ b/core/src/io/cursor.cpp @@ -0,0 +1,42 @@ +#include +#include +#include + +using namespace cubos::core; + +using cubos::core::io::Cursor; +using cubos::core::reflection::EnumTrait; +using cubos::core::reflection::Type; + +#ifdef WITH_GLFW +io::Cursor::Cursor(GLFWcursor* handle) +{ + mGlfwHandle = handle; +} +#endif + +io::Cursor::~Cursor() +{ +#ifdef WITH_GLFW + if (mGlfwHandle != nullptr) + { + glfwDestroyCursor(mGlfwHandle); + } +#endif +} + +CUBOS_REFLECT_EXTERNAL_IMPL(Cursor::Standard) +{ + return Type::create("Standard") + .with(EnumTrait{} + .withVariant("Arrow") + .withVariant("IBeam") + .withVariant("Cross") + .withVariant("Hand") + .withVariant("EWResize") + .withVariant("NSResize") + .withVariant("NWSEResize") + .withVariant("NESWResize") + .withVariant("AllResize") + .withVariant("NotAllowed")); +} diff --git a/core/src/io/gamepad.cpp b/core/src/io/gamepad.cpp new file mode 100644 index 0000000000..d2574863db --- /dev/null +++ b/core/src/io/gamepad.cpp @@ -0,0 +1,51 @@ +#include +#include +#include + +using namespace cubos::core; + +using cubos::core::io::GamepadAxis; +using cubos::core::io::GamepadButton; +using cubos::core::reflection::EnumTrait; +using cubos::core::reflection::Type; + +CUBOS_REFLECT_EXTERNAL_IMPL(GamepadButton) +{ + return Type::create("GamepadButton") + .with(EnumTrait{} + .withVariant("Invalid") + + .withVariant("A") + .withVariant("B") + .withVariant("X") + .withVariant("Y") + .withVariant("LBumper") + .withVariant("RBumper") + .withVariant("Back") + .withVariant("Start") + .withVariant("Guide") + .withVariant("LThumb") + .withVariant("RThumb") + .withVariant("Up") + .withVariant("Right") + .withVariant("Down") + .withVariant("Left") + + .withVariant("Count")); +} + +CUBOS_REFLECT_EXTERNAL_IMPL(GamepadAxis) +{ + return Type::create("GamepadAxis") + .with(EnumTrait{} + .withVariant("Invalid") + + .withVariant("LX") + .withVariant("LY") + .withVariant("RX") + .withVariant("RY") + .withVariant("LTrigger") + .withVariant("RTrigger") + + .withVariant("Count")); +} diff --git a/core/src/cubos/core/io/glfw_window.cpp b/core/src/io/glfw_window.cpp similarity index 100% rename from core/src/cubos/core/io/glfw_window.cpp rename to core/src/io/glfw_window.cpp diff --git a/core/src/cubos/core/io/glfw_window.hpp b/core/src/io/glfw_window.hpp similarity index 100% rename from core/src/cubos/core/io/glfw_window.hpp rename to core/src/io/glfw_window.hpp diff --git a/core/src/io/keyboard.cpp b/core/src/io/keyboard.cpp new file mode 100644 index 0000000000..0f349e2b01 --- /dev/null +++ b/core/src/io/keyboard.cpp @@ -0,0 +1,128 @@ +#include +#include +#include + +using namespace cubos::core; + +using cubos::core::io::Key; +using cubos::core::io::Modifiers; +using cubos::core::reflection::EnumTrait; +using cubos::core::reflection::Type; + +CUBOS_REFLECT_EXTERNAL_IMPL(Key) +{ + return Type::create("Key").with(EnumTrait{} + .withVariant("Invalid") + + .withVariant("A") + .withVariant("B") + .withVariant("C") + .withVariant("D") + .withVariant("E") + .withVariant("F") + .withVariant("G") + .withVariant("H") + .withVariant("I") + .withVariant("J") + .withVariant("K") + .withVariant("L") + .withVariant("M") + .withVariant("N") + .withVariant("O") + .withVariant("P") + .withVariant("Q") + .withVariant("R") + .withVariant("S") + .withVariant("T") + .withVariant("U") + .withVariant("V") + .withVariant("W") + .withVariant("X") + .withVariant("Y") + .withVariant("Z") + .withVariant("Num0") + .withVariant("Num1") + .withVariant("Num2") + .withVariant("Num3") + .withVariant("Num4") + .withVariant("Num5") + .withVariant("Num6") + .withVariant("Num7") + .withVariant("Num8") + .withVariant("Num9") + .withVariant("Escape") + .withVariant("LControl") + .withVariant("LShift") + .withVariant("LAlt") + .withVariant("LSystem") + .withVariant("RControl") + .withVariant("RShift") + .withVariant("RAlt") + .withVariant("RSystem") + .withVariant("Menu") + .withVariant("LBracket") + .withVariant("RBracket") + .withVariant("SemiColon") + .withVariant("Comma") + .withVariant("Period") + .withVariant("Quote") + .withVariant("Slash") + .withVariant("BackSlash") + .withVariant("Tilde") + .withVariant("Equal") + .withVariant("Dash") + .withVariant("Space") + .withVariant("Return") + .withVariant("BackSpace") + .withVariant("Tab") + .withVariant("PageUp") + .withVariant("PageDown") + .withVariant("End") + .withVariant("Home") + .withVariant("Insert") + .withVariant("Delete") + .withVariant("Add") + .withVariant("Subtract") + .withVariant("Multiply") + .withVariant("Divide") + .withVariant("Left") + .withVariant("Right") + .withVariant("Up") + .withVariant("Down") + .withVariant("Numpad0") + .withVariant("Numpad1") + .withVariant("Numpad2") + .withVariant("Numpad3") + .withVariant("Numpad4") + .withVariant("Numpad5") + .withVariant("Numpad6") + .withVariant("Numpad7") + .withVariant("Numpad8") + .withVariant("Numpad9") + .withVariant("F1") + .withVariant("F2") + .withVariant("F3") + .withVariant("F4") + .withVariant("F5") + .withVariant("F6") + .withVariant("F7") + .withVariant("F8") + .withVariant("F9") + .withVariant("F10") + .withVariant("F11") + .withVariant("F12") + .withVariant("Pause") + + .withVariant("Count")); +} + +CUBOS_REFLECT_EXTERNAL_IMPL(Modifiers) +{ + return Type::create("Modifiers") + .with(EnumTrait{} + .withVariant("None") + .withVariant("Control") + .withVariant("Shift") + .withVariant("Alt") + .withVariant("System")); +} \ No newline at end of file diff --git a/core/src/io/window.cpp b/core/src/io/window.cpp new file mode 100644 index 0000000000..68b3fd51c0 --- /dev/null +++ b/core/src/io/window.cpp @@ -0,0 +1,78 @@ +#include +#include +#include + +#include "glfw_window.hpp" + +using namespace cubos::core::io; + +using cubos::core::io::MouseAxis; +using cubos::core::io::MouseButton; +using cubos::core::io::MouseState; +using cubos::core::reflection::EnumTrait; +using cubos::core::reflection::Type; + +Window cubos::core::io::openWindow(const std::string& title, const glm::ivec2& size) +{ + return std::make_shared(title, size); +} + +BaseWindow::BaseWindow() +{ + mPolled = false; +} + +void BaseWindow::pushEvent(WindowEvent&& event) +{ + mEvents.push_back(event); +} + +std::optional BaseWindow::pollEvent() +{ + // Only poll events after pollEvent() has returned std::nullopt (or if it has never been called). + if (!mPolled) + { + this->pollEvents(); + mPolled = true; + } + + // No more events, we're done for now, but we need to poll again next time. + if (mEvents.empty()) + { + mPolled = false; + return std::nullopt; + } + + WindowEvent event = mEvents.front(); + mEvents.pop_front(); + return event; +} + +CUBOS_REFLECT_EXTERNAL_IMPL(MouseButton) +{ + return Type::create("MouseButton") + .with(EnumTrait{} + .withVariant("Invalid") + + .withVariant("Left") + .withVariant("Right") + .withVariant("Middle") + .withVariant("Extra1") + .withVariant("Extra2")); +} + +CUBOS_REFLECT_EXTERNAL_IMPL(MouseAxis) +{ + return Type::create("MouseAxis") + .with(EnumTrait{}.withVariant("X").withVariant("Y").withVariant( + "Scroll")); +} + +CUBOS_REFLECT_EXTERNAL_IMPL(MouseState) +{ + return Type::create("MouseState") + .with(EnumTrait{} + .withVariant("Default") + .withVariant("Locked") + .withVariant("Hidden")); +} diff --git a/core/src/cubos/core/log.cpp b/core/src/log.cpp similarity index 100% rename from core/src/cubos/core/log.cpp rename to core/src/log.cpp diff --git a/core/src/cubos/core/memory/any_value.cpp b/core/src/memory/any_value.cpp similarity index 89% rename from core/src/cubos/core/memory/any_value.cpp rename to core/src/memory/any_value.cpp index ca70d051dd..d3575edb86 100644 --- a/core/src/cubos/core/memory/any_value.cpp +++ b/core/src/memory/any_value.cpp @@ -46,6 +46,16 @@ AnyValue::AnyValue(AnyValue&& other) noexcept other.mValue = nullptr; } +AnyValue::AnyValue(const AnyValue& other) noexcept + : AnyValue{*other.mType} +{ + CUBOS_ASSERT(mType->has(), "Type must be constructible"); + const auto& trait = mType->get(); + CUBOS_ASSERT(trait.hasCopyConstruct(), "Type must be copy constructible"); + + trait.copyConstruct(get(), other.get()); +} + AnyValue AnyValue::defaultConstruct(const Type& type) noexcept { CUBOS_ASSERT(type.has(), "Type must be constructible"); diff --git a/core/src/cubos/core/memory/any_vector.cpp b/core/src/memory/any_vector.cpp similarity index 100% rename from core/src/cubos/core/memory/any_vector.cpp rename to core/src/memory/any_vector.cpp diff --git a/core/src/cubos/core/memory/buffer_stream.cpp b/core/src/memory/buffer_stream.cpp similarity index 100% rename from core/src/cubos/core/memory/buffer_stream.cpp rename to core/src/memory/buffer_stream.cpp diff --git a/core/src/cubos/core/memory/standard_stream.cpp b/core/src/memory/standard_stream.cpp similarity index 100% rename from core/src/cubos/core/memory/standard_stream.cpp rename to core/src/memory/standard_stream.cpp diff --git a/core/src/cubos/core/memory/stream.cpp b/core/src/memory/stream.cpp similarity index 100% rename from core/src/cubos/core/memory/stream.cpp rename to core/src/memory/stream.cpp diff --git a/core/src/reflection/comparison.cpp b/core/src/reflection/comparison.cpp new file mode 100644 index 0000000000..76879ad73c --- /dev/null +++ b/core/src/reflection/comparison.cpp @@ -0,0 +1,91 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using cubos::core::memory::AnyValue; + +#define PRIMITIVE_CHECK(reflected, type, a, b) \ + if ((reflected).is()) \ + return *(type*)(a) == *(type*)(b) + +bool cubos::core::reflection::compare(const Type& type, void* a, void* b) +{ + PRIMITIVE_CHECK(type, bool, a, b); + PRIMITIVE_CHECK(type, char, a, b); + PRIMITIVE_CHECK(type, signed char, a, b); + PRIMITIVE_CHECK(type, short, a, b); + PRIMITIVE_CHECK(type, int, a, b); + PRIMITIVE_CHECK(type, long, a, b); + PRIMITIVE_CHECK(type, long long, a, b); + PRIMITIVE_CHECK(type, unsigned char, a, b); + PRIMITIVE_CHECK(type, unsigned short, a, b); + PRIMITIVE_CHECK(type, unsigned int, a, b); + PRIMITIVE_CHECK(type, unsigned long, a, b); + PRIMITIVE_CHECK(type, unsigned long long, a, b); + PRIMITIVE_CHECK(type, float, a, b); + PRIMITIVE_CHECK(type, double, a, b); + + if (type.has()) + { + for (const auto& trait = type.get(); const auto& field : trait) + { + if (!compare(field.type(), trait.view(a).get(field), trait.view(b).get(field))) + { + return false; + } + } + return true; + } + + if (type.has()) + { + const auto& trait = type.get(); + if (trait.view(a).length() != trait.view(b).length()) + { + return false; + } + for (size_t i = 0; i < trait.view(a).length(); i++) + { + if (!compare(trait.elementType(), trait.view(a).get(i), trait.view(b).get(i))) + { + return false; + } + } + return true; + } + + if (type.has()) + { + const auto& trait = type.get(); + if (trait.view(a).length() != trait.view(b).length()) + { + return false; + } + for (const auto& [key, value] : trait.view(a)) + { + if (trait.view(b).find(key) == trait.view(b).end()) + { + return false; + } + if (!compare(trait.valueType(), value, trait.view(b).find(key)->value)) + { + return false; + } + } + return true; + } + + if (type.has()) + { + const auto& trait = type.get(); + return trait.into(a) == trait.into(b); + } + + CUBOS_FAIL("Type cannot be compared!"); +} diff --git a/core/src/cubos/core/reflection/external/cstring.cpp b/core/src/reflection/external/cstring.cpp similarity index 100% rename from core/src/cubos/core/reflection/external/cstring.cpp rename to core/src/reflection/external/cstring.cpp diff --git a/core/src/cubos/core/reflection/external/glm.cpp b/core/src/reflection/external/glm.cpp similarity index 100% rename from core/src/cubos/core/reflection/external/glm.cpp rename to core/src/reflection/external/glm.cpp diff --git a/core/src/cubos/core/reflection/external/primitives.cpp b/core/src/reflection/external/primitives.cpp similarity index 100% rename from core/src/cubos/core/reflection/external/primitives.cpp rename to core/src/reflection/external/primitives.cpp diff --git a/core/src/cubos/core/reflection/external/string.cpp b/core/src/reflection/external/string.cpp similarity index 100% rename from core/src/cubos/core/reflection/external/string.cpp rename to core/src/reflection/external/string.cpp diff --git a/core/src/cubos/core/reflection/external/string_view.cpp b/core/src/reflection/external/string_view.cpp similarity index 100% rename from core/src/cubos/core/reflection/external/string_view.cpp rename to core/src/reflection/external/string_view.cpp diff --git a/core/src/cubos/core/reflection/external/uuid.cpp b/core/src/reflection/external/uuid.cpp similarity index 100% rename from core/src/cubos/core/reflection/external/uuid.cpp rename to core/src/reflection/external/uuid.cpp diff --git a/core/src/cubos/core/reflection/traits/array.cpp b/core/src/reflection/traits/array.cpp similarity index 100% rename from core/src/cubos/core/reflection/traits/array.cpp rename to core/src/reflection/traits/array.cpp diff --git a/core/src/cubos/core/reflection/traits/constructible.cpp b/core/src/reflection/traits/constructible.cpp similarity index 100% rename from core/src/cubos/core/reflection/traits/constructible.cpp rename to core/src/reflection/traits/constructible.cpp diff --git a/core/src/cubos/core/reflection/traits/dictionary.cpp b/core/src/reflection/traits/dictionary.cpp similarity index 100% rename from core/src/cubos/core/reflection/traits/dictionary.cpp rename to core/src/reflection/traits/dictionary.cpp diff --git a/core/src/cubos/core/reflection/traits/enum.cpp b/core/src/reflection/traits/enum.cpp similarity index 100% rename from core/src/cubos/core/reflection/traits/enum.cpp rename to core/src/reflection/traits/enum.cpp diff --git a/core/src/cubos/core/reflection/traits/fields.cpp b/core/src/reflection/traits/fields.cpp similarity index 100% rename from core/src/cubos/core/reflection/traits/fields.cpp rename to core/src/reflection/traits/fields.cpp diff --git a/core/src/cubos/core/reflection/traits/nullable.cpp b/core/src/reflection/traits/nullable.cpp similarity index 100% rename from core/src/cubos/core/reflection/traits/nullable.cpp rename to core/src/reflection/traits/nullable.cpp diff --git a/core/src/cubos/core/reflection/traits/string_conversion.cpp b/core/src/reflection/traits/string_conversion.cpp similarity index 100% rename from core/src/cubos/core/reflection/traits/string_conversion.cpp rename to core/src/reflection/traits/string_conversion.cpp diff --git a/core/src/cubos/core/reflection/type.cpp b/core/src/reflection/type.cpp similarity index 100% rename from core/src/cubos/core/reflection/type.cpp rename to core/src/reflection/type.cpp diff --git a/core/src/cubos/core/reflection/type_registry.cpp b/core/src/reflection/type_registry.cpp similarity index 100% rename from core/src/cubos/core/reflection/type_registry.cpp rename to core/src/reflection/type_registry.cpp diff --git a/core/src/cubos/core/thread_pool.cpp b/core/src/thread_pool.cpp similarity index 100% rename from core/src/cubos/core/thread_pool.cpp rename to core/src/thread_pool.cpp diff --git a/core/tests/CMakeLists.txt b/core/tests/CMakeLists.txt index 8c2eb6f10b..b8fc366c8c 100644 --- a/core/tests/CMakeLists.txt +++ b/core/tests/CMakeLists.txt @@ -2,66 +2,67 @@ # Core tests build configuration add_executable( - cubos-core-tests - main.cpp - utils.cpp + cubos-core-tests + main.cpp + utils.cpp - reflection/reflect.cpp - reflection/type.cpp - reflection/type_registry.cpp - reflection/traits/constructible.cpp - reflection/traits/fields.cpp - reflection/traits/nullable.cpp - reflection/traits/enum.cpp - reflection/external/primitives.cpp - reflection/external/cstring.cpp - reflection/external/string.cpp - reflection/external/string_view.cpp - reflection/external/uuid.cpp - reflection/external/glm.cpp - reflection/external/vector.cpp - reflection/external/map.cpp - reflection/external/unordered_map.cpp + reflection/reflect.cpp + reflection/comparison.cpp + reflection/type.cpp + reflection/type_registry.cpp + reflection/traits/constructible.cpp + reflection/traits/fields.cpp + reflection/traits/nullable.cpp + reflection/traits/enum.cpp + reflection/external/primitives.cpp + reflection/external/cstring.cpp + reflection/external/string.cpp + reflection/external/string_view.cpp + reflection/external/uuid.cpp + reflection/external/glm.cpp + reflection/external/vector.cpp + reflection/external/map.cpp + reflection/external/unordered_map.cpp - data/fs/embedded_archive.cpp - data/fs/standard_archive.cpp - data/fs/file_system.cpp - data/ser/debug.cpp - data/ser/json.cpp - data/des/json.cpp - data/context.cpp + data/fs/embedded_archive.cpp + data/fs/standard_archive.cpp + data/fs/file_system.cpp + data/ser/debug.cpp + data/ser/json.cpp + data/des/json.cpp + data/context.cpp - memory/any_value.cpp - memory/any_vector.cpp - memory/function.cpp - memory/type_map.cpp - memory/unordered_bimap.cpp + memory/any_value.cpp + memory/any_vector.cpp + memory/function.cpp + memory/type_map.cpp + memory/unordered_bimap.cpp - ecs/utils.cpp - ecs/cubos.cpp - ecs/world.cpp - ecs/query.cpp - ecs/blueprint.cpp + ecs/utils.cpp + ecs/cubos.cpp + ecs/world.cpp + ecs/query.cpp + ecs/blueprint.cpp - ecs/commands.cpp - ecs/system.cpp - ecs/dispatcher.cpp + ecs/commands.cpp + ecs/system.cpp + ecs/dispatcher.cpp - ecs/utils/expected.cpp - ecs/utils/action.cpp - ecs/types.cpp - ecs/table/dense/table.cpp - ecs/table/sparse_relation/table.cpp - ecs/entity/archetype_graph.cpp - ecs/entity/pool.cpp - ecs/query/data.cpp - ecs/query/term.cpp - ecs/query/filter.cpp - ecs/system/access.cpp - ecs/stress.cpp + ecs/utils/expected.cpp + ecs/utils/action.cpp + ecs/types.cpp + ecs/table/dense/table.cpp + ecs/table/sparse_relation/table.cpp + ecs/entity/archetype_graph.cpp + ecs/entity/pool.cpp + ecs/query/data.cpp + ecs/query/term.cpp + ecs/query/filter.cpp + ecs/system/access.cpp + ecs/stress.cpp - geom/box.cpp - geom/capsule.cpp + geom/box.cpp + geom/capsule.cpp ) target_link_libraries(cubos-core-tests cubos-core doctest::doctest) diff --git a/core/tests/ecs/blueprint.cpp b/core/tests/ecs/blueprint.cpp index 7cb5a67d4f..8f744d1919 100644 --- a/core/tests/ecs/blueprint.cpp +++ b/core/tests/ecs/blueprint.cpp @@ -64,7 +64,7 @@ TEST_CASE("ecs::Blueprint") SUBCASE("spawn the blueprint") { // Spawn the blueprint into the world and get the identifiers of the spawned entities. - auto spawned = cmds.spawn(blueprint); + auto spawned = cmds.spawn(blueprint, false); auto spawnedBar = spawned.entity("bar"); auto spawnedBaz = spawned.entity("baz"); auto spawnedQux = spawned.entity("qux"); @@ -110,7 +110,7 @@ TEST_CASE("ecs::Blueprint") merged.relate(foo, foo, EmptyRelation{}); // Merge the original blueprint into the new one. - merged.merge("sub", blueprint); + merged.merge("sub", blueprint, false); // Then the new blueprint has the correct entities. CHECK(merged.bimap().atRight("foo") == foo); @@ -118,7 +118,7 @@ TEST_CASE("ecs::Blueprint") CHECK(merged.bimap().containsRight("sub.baz")); // Spawn the blueprint into the world and get the identifiers of the spawned entities. - auto spawned = cmds.spawn(merged); + auto spawned = cmds.spawn(merged, false); auto spawnedFoo = spawned.entity("foo"); auto spawnedBar = spawned.entity("sub.bar"); auto spawnedBaz = spawned.entity("sub.baz"); @@ -154,7 +154,7 @@ TEST_CASE("ecs::Blueprint") blueprint.add(entity0, EntityArrayComponent{{entity0, entity1}}); // Spawn the blueprint into the world and get the identifiers of the spawned entities. - auto spawned = cmds.spawn(blueprint); + auto spawned = cmds.spawn(blueprint, false); auto spawned0 = spawned.entity("0"); auto spawned1 = spawned.entity("1"); cmdBuffer.commit(); @@ -173,7 +173,7 @@ TEST_CASE("ecs::Blueprint") blueprint.add(entity0, EntityDictionaryComponent{{{'0', entity0}, {'1', entity1}}}); // Spawn the blueprint into the world and get the identifiers of the spawned entities. - auto spawned = cmds.spawn(blueprint); + auto spawned = cmds.spawn(blueprint, false); auto spawned0 = spawned.entity("0"); auto spawned1 = spawned.entity("1"); cmdBuffer.commit(); @@ -195,7 +195,7 @@ TEST_CASE("ecs::Blueprint") blueprint.add(entity1, IntegerComponent{1}); // Spawn the blueprint into the world and get the identifiers of the spawned entities. - auto spawned = cmds.spawn(blueprint); + auto spawned = cmds.spawn(blueprint, true); auto spawned0 = spawned.entity("0"); auto spawned1 = spawned.entity("1"); cmdBuffer.commit(); diff --git a/core/tests/reflection/comparison.cpp b/core/tests/reflection/comparison.cpp new file mode 100644 index 0000000000..63c8aa460b --- /dev/null +++ b/core/tests/reflection/comparison.cpp @@ -0,0 +1,58 @@ +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using cubos::core::reflection::compare; +using cubos::core::reflection::FieldsTrait; +using cubos::core::reflection::reflect; +using cubos::core::reflection::Type; + +struct FieldsObject +{ + CUBOS_REFLECT; + int age; + float weight; +}; + +CUBOS_REFLECT_IMPL(FieldsObject) +{ + return Type::create("FieldsObject") + .with(FieldsTrait().withField("age", &FieldsObject::age).withField("weight", &FieldsObject::weight)); +} + +TEST_CASE("reflection::compare") +{ + const auto fo = FieldsObject{1, 0.3F}; + const auto foEqual = FieldsObject{1, 0.3F}; + const auto foDifferent = FieldsObject{2, 0.3F}; + CHECK(compare(fo.reflect(), (void*)&fo, (void*)&foEqual)); + CHECK_FALSE(compare(fo.reflect(), (void*)&fo, (void*)&foDifferent)); + + std::vector> vec = { + std::unordered_map{{1, {1.2, 2.3, 4.5}}, {2, {1.2, 1.3, 4.5}}, {560, {1.2, 2.3, 4.5}}}, + std::unordered_map{{5, {1.2, 2.3, 4.5}}}, + std::unordered_map{{6, {1.2, 2.5, 4.5}}}}; + + std::vector> vecEqual = { + std::unordered_map{{1, {1.2, 2.3, 4.5}}, {2, {1.2, 1.3, 4.5}}, {560, {1.2, 2.3, 4.5}}}, + std::unordered_map{{5, {1.2, 2.3, 4.5}}}, + std::unordered_map{{6, {1.2, 2.5, 4.5}}}}; + + std::vector> vecDiff = { + std::unordered_map{{1, {1.2, 2.31, 4.5}}, {2, {1.2, 1.3, 4.5}}, {560, {1.2, 2.3, 4.5}}}, + std::unordered_map{{5, {1.2, 2.3, 4.5}}}, + std::unordered_map{{6, {1.2, 2.5, 4.5}}}}; + + CHECK(compare(reflect>>(), (void*)&vec, (void*)&vecEqual)); + CHECK_FALSE(compare(reflect>>(), (void*)&vec, (void*)&vecDiff)); +} diff --git a/engine/.DS_Store b/engine/.DS_Store deleted file mode 100644 index 19b9fa6a28..0000000000 Binary files a/engine/.DS_Store and /dev/null differ diff --git a/engine/CMakeLists.txt b/engine/CMakeLists.txt index 94f38394ba..c002195a47 100644 --- a/engine/CMakeLists.txt +++ b/engine/CMakeLists.txt @@ -9,82 +9,84 @@ message("# Building engine tests: " ${BUILD_ENGINE_TESTS}) # Set engine source files set(CUBOS_ENGINE_SOURCE - "src/cubos/engine/prelude.cpp" - - "src/cubos/engine/settings/plugin.cpp" - "src/cubos/engine/settings/settings.cpp" - - "src/cubos/engine/window/plugin.cpp" - - "src/cubos/engine/imgui/plugin.cpp" - "src/cubos/engine/imgui/imgui.cpp" - "src/cubos/engine/imgui/data_inspector.cpp" - - "src/cubos/engine/transform/plugin.cpp" - "src/cubos/engine/transform/local_to_world.cpp" - "src/cubos/engine/transform/position.cpp" - "src/cubos/engine/transform/rotation.cpp" - "src/cubos/engine/transform/scale.cpp" - - "src/cubos/engine/utils/free_camera_controller/plugin.cpp" - "src/cubos/engine/utils/free_camera_controller/controller.cpp" - - "src/cubos/engine/assets/plugin.cpp" - "src/cubos/engine/assets/assets.cpp" - "src/cubos/engine/assets/bridge.cpp" - "src/cubos/engine/assets/asset.cpp" - "src/cubos/engine/assets/meta.cpp" - "src/cubos/engine/assets/bridges/file.cpp" - - "src/cubos/engine/gizmos/plugin.cpp" - "src/cubos/engine/gizmos/gizmos.cpp" - "src/cubos/engine/gizmos/renderer.cpp" - - "src/cubos/engine/scene/plugin.cpp" - "src/cubos/engine/scene/scene.cpp" - "src/cubos/engine/scene/bridge.cpp" - - "src/cubos/engine/voxels/plugin.cpp" - "src/cubos/engine/voxels/grid.cpp" - "src/cubos/engine/voxels/material.cpp" - "src/cubos/engine/voxels/palette.cpp" - - "src/cubos/engine/collisions/plugin.cpp" - "src/cubos/engine/collisions/collider.cpp" - "src/cubos/engine/collisions/shapes/box.cpp" - "src/cubos/engine/collisions/shapes/capsule.cpp" - "src/cubos/engine/collisions/broad_phase/plugin.cpp" - "src/cubos/engine/collisions/broad_phase/sweep_and_prune.cpp" - "src/cubos/engine/collisions/broad_phase/potentially_colliding_with.cpp" - - "src/cubos/engine/physics/plugin.cpp" - "src/cubos/engine/physics/gravity.cpp" - - "src/cubos/engine/input/plugin.cpp" - "src/cubos/engine/input/input.cpp" - "src/cubos/engine/input/bindings.cpp" - "src/cubos/engine/input/action.cpp" - "src/cubos/engine/input/axis.cpp" - - "src/cubos/engine/renderer/plugin.cpp" - "src/cubos/engine/renderer/vertex.cpp" - "src/cubos/engine/renderer/frame.cpp" - "src/cubos/engine/renderer/camera.cpp" - "src/cubos/engine/renderer/directional_light.cpp" - "src/cubos/engine/renderer/point_light.cpp" - "src/cubos/engine/renderer/spot_light.cpp" - "src/cubos/engine/renderer/renderer.cpp" - "src/cubos/engine/renderer/deferred_renderer.cpp" - "src/cubos/engine/renderer/pps/bloom.cpp" - "src/cubos/engine/renderer/pps/copy_pass.cpp" - "src/cubos/engine/renderer/pps/manager.cpp" - "src/cubos/engine/renderer/pps/pass.cpp" - "src/cubos/engine/renderer/viewport.cpp" - - "src/cubos/engine/splitscreen/plugin.cpp" - - "src/cubos/engine/screen_picker/plugin.cpp" - "src/cubos/engine/screen_picker/screen_picker.cpp" + "src/prelude.cpp" + + "src/settings/plugin.cpp" + "src/settings/settings.cpp" + + "src/window/plugin.cpp" + + "src/imgui/plugin.cpp" + "src/imgui/imgui.cpp" + "src/imgui/data_inspector.cpp" + + "src/transform/plugin.cpp" + "src/transform/child_of.cpp" + "src/transform/local_to_parent.cpp" + "src/transform/local_to_world.cpp" + "src/transform/position.cpp" + "src/transform/rotation.cpp" + "src/transform/scale.cpp" + + "src/utils/free_camera_controller/plugin.cpp" + "src/utils/free_camera_controller/controller.cpp" + + "src/assets/plugin.cpp" + "src/assets/assets.cpp" + "src/assets/bridge.cpp" + "src/assets/asset.cpp" + "src/assets/meta.cpp" + "src/assets/bridges/file.cpp" + + "src/gizmos/plugin.cpp" + "src/gizmos/gizmos.cpp" + "src/gizmos/renderer.cpp" + + "src/scene/plugin.cpp" + "src/scene/scene.cpp" + "src/scene/bridge.cpp" + + "src/voxels/plugin.cpp" + "src/voxels/grid.cpp" + "src/voxels/material.cpp" + "src/voxels/palette.cpp" + + "src/collisions/plugin.cpp" + "src/collisions/collider.cpp" + "src/collisions/shapes/box.cpp" + "src/collisions/shapes/capsule.cpp" + "src/collisions/broad_phase/plugin.cpp" + "src/collisions/broad_phase/sweep_and_prune.cpp" + "src/collisions/broad_phase/potentially_colliding_with.cpp" + + "src/physics/plugin.cpp" + "src/physics/gravity.cpp" + + "src/input/plugin.cpp" + "src/input/input.cpp" + "src/input/bindings.cpp" + "src/input/action.cpp" + "src/input/axis.cpp" + + "src/renderer/plugin.cpp" + "src/renderer/vertex.cpp" + "src/renderer/frame.cpp" + "src/renderer/camera.cpp" + "src/renderer/directional_light.cpp" + "src/renderer/point_light.cpp" + "src/renderer/spot_light.cpp" + "src/renderer/renderer.cpp" + "src/renderer/deferred_renderer.cpp" + "src/renderer/pps/bloom.cpp" + "src/renderer/pps/copy_pass.cpp" + "src/renderer/pps/manager.cpp" + "src/renderer/pps/pass.cpp" + "src/renderer/viewport.cpp" + + "src/splitscreen/plugin.cpp" + + "src/screen_picker/plugin.cpp" + "src/screen_picker/screen_picker.cpp" ) # Create cubos engine diff --git a/engine/include/cubos/engine/gizmos/gizmos.hpp b/engine/include/cubos/engine/gizmos/gizmos.hpp index 26886a420f..79d8381279 100644 --- a/engine/include/cubos/engine/gizmos/gizmos.hpp +++ b/engine/include/cubos/engine/gizmos/gizmos.hpp @@ -168,13 +168,15 @@ namespace cubos::engine std::vector> viewGizmos; ///< Queued gizmos to be drawn in viewport space. std::vector> screenGizmos; ///< Queued gizmos to be drawn in screen space. + bool mLocking; ///< Whether the mouse has just now been pressed. + private: /// @brief Adds a gizmo into the corresponding vector. /// @param gizmo Gizmo to be added. /// @param space Space in which the gizmo will be drawn. void push(const std::shared_ptr& gizmo, const Space& space); - std::hash mHasher; ///< Hash function to convert string ids into integers. + static uint32_t mHasher(const std::string& id); ///< Hash function to convert string ids into integers. glm::vec3 mColor; ///< Currently set color. diff --git a/engine/include/cubos/engine/gizmos/plugin.hpp b/engine/include/cubos/engine/gizmos/plugin.hpp index b048f24a00..c1801124d0 100644 --- a/engine/include/cubos/engine/gizmos/plugin.hpp +++ b/engine/include/cubos/engine/gizmos/plugin.hpp @@ -27,8 +27,11 @@ namespace cubos::engine /// before `cubos.gizmos.draw`. /// - `cubos.gizmos.draw` - queued gizmos are rendered to the window, after `cubos.renderer.draw` and /// before `cubos.window.render`. + /// - `cubos.gizmos.pick` - the ScreenPicker resource is accessed to detect gizmos at mouse coordinates, after + /// `cubos.gizmos.draw` /// /// ## Dependencies + /// - @ref screen-picker-plugin /// - @ref window-plugin /// @brief Plugin entry function. diff --git a/engine/include/cubos/engine/physics/components/force.hpp b/engine/include/cubos/engine/physics/components/force.hpp new file mode 100644 index 0000000000..32bd5acd24 --- /dev/null +++ b/engine/include/cubos/engine/physics/components/force.hpp @@ -0,0 +1,39 @@ +/// @file +/// @brief Component @ref cubos::engine::Force. +/// @ingroup physics-plugin + +#pragma once + +#include + +#include + +namespace cubos::engine +{ + /// @brief Component which holds forces applied on a particle. + /// @note Should be used with @ref Velocity. + /// @ingroup physics-plugin + struct Force + { + CUBOS_REFLECT; + + glm::vec3 vec() const + { + return mForce; + } + + void add(glm::vec3 force) + { + mForce += force; + } + + void clear() + { + mForce = {0.0F, 0.0F, 0.0F}; + } + + private: + glm::vec3 mForce = {0.0F, 0.0F, 0.0F}; + }; + +} // namespace cubos::engine diff --git a/engine/include/cubos/engine/physics/components/impulse.hpp b/engine/include/cubos/engine/physics/components/impulse.hpp new file mode 100644 index 0000000000..21fef1e1de --- /dev/null +++ b/engine/include/cubos/engine/physics/components/impulse.hpp @@ -0,0 +1,39 @@ +/// @file +/// @brief Component @ref cubos::engine::Force. +/// @ingroup physics-plugin + +#pragma once + +#include + +#include + +namespace cubos::engine +{ + /// @brief Component which holds impulses applied on a particle. + /// @note Should be used with @ref Velocity. + /// @ingroup physics-plugin + struct Impulse + { + CUBOS_REFLECT; + + glm::vec3 vec() const + { + return mImpulse; + } + + void add(glm::vec3 impulse) + { + mImpulse += impulse; + } + + void clear() + { + mImpulse = {0.0F, 0.0F, 0.0F}; + } + + private: + glm::vec3 mImpulse; + }; + +} // namespace cubos::engine diff --git a/engine/include/cubos/engine/physics/components/physics_mass.hpp b/engine/include/cubos/engine/physics/components/mass.hpp similarity index 82% rename from engine/include/cubos/engine/physics/components/physics_mass.hpp rename to engine/include/cubos/engine/physics/components/mass.hpp index f60d32ba25..dc3a09eb5b 100644 --- a/engine/include/cubos/engine/physics/components/physics_mass.hpp +++ b/engine/include/cubos/engine/physics/components/mass.hpp @@ -1,5 +1,5 @@ /// @file -/// @brief Component @ref cubos::engine::PhysicsMass. +/// @brief Component @ref cubos::engine::Mass. /// @ingroup physics-plugin #pragma once @@ -12,7 +12,7 @@ namespace cubos::engine { /// @brief Component which defines the mass of a particle. /// @ingroup physics-plugin - struct PhysicsMass + struct Mass { CUBOS_REFLECT; diff --git a/engine/include/cubos/engine/physics/components/physics_velocity.hpp b/engine/include/cubos/engine/physics/components/velocity.hpp similarity index 58% rename from engine/include/cubos/engine/physics/components/physics_velocity.hpp rename to engine/include/cubos/engine/physics/components/velocity.hpp index 6d0edc6c40..2a8df0dc3d 100644 --- a/engine/include/cubos/engine/physics/components/physics_velocity.hpp +++ b/engine/include/cubos/engine/physics/components/velocity.hpp @@ -1,5 +1,5 @@ /// @file -/// @brief Component @ref cubos::engine::PhysicsVelocity. +/// @brief Component @ref cubos::engine::Velocity. /// @ingroup physics-plugin #pragma once @@ -11,14 +11,12 @@ namespace cubos::engine { /// @brief Component which holds velocity and forces applied on a particle. - /// @note Should be used with @ref PhysicsMass and @ref Position. + /// @note Should be used with @ref Mass and @ref Position. /// @ingroup physics-plugin - struct PhysicsVelocity + struct Velocity { CUBOS_REFLECT; - glm::vec3 velocity; - glm::vec3 force; - glm::vec3 impulse; + glm::vec3 vec; }; } // namespace cubos::engine diff --git a/engine/include/cubos/engine/physics/plugin.hpp b/engine/include/cubos/engine/physics/plugin.hpp index 4ffe6bb0dc..d3533b0ac8 100644 --- a/engine/include/cubos/engine/physics/plugin.hpp +++ b/engine/include/cubos/engine/physics/plugin.hpp @@ -13,9 +13,11 @@ #include #include -#include -#include +#include +#include +#include #include +#include #include #include #include @@ -37,8 +39,10 @@ namespace cubos::engine /// - @ref Substeps - holds the amount of substeps for the physics update. /// /// ## Components - /// - @ref PhysicsVelocity - holds the information for moving an object straight. - /// - @ref PhysicsMass - holds the mass of an object. + /// - @ref Velocity - holds the information for moving an object straight. + /// - @ref Force - holds forces applied on a particle. + /// - @ref Impulse - holds impulses applied on a particle. + /// - @ref Mass - holds the mass of an object. /// - @ref PreviousPosition - holds the previous position of the entity in a substep. /// - @ref AccumulatedCorrection - holds the corrections accumulated from the constraints solving. /// diff --git a/engine/include/cubos/engine/physics/plugins/gravity.hpp b/engine/include/cubos/engine/physics/plugins/gravity.hpp index 084ccb9e89..eb143a37d2 100644 --- a/engine/include/cubos/engine/physics/plugins/gravity.hpp +++ b/engine/include/cubos/engine/physics/plugins/gravity.hpp @@ -4,8 +4,10 @@ #pragma once -#include -#include +#include +#include +#include +#include #include #include diff --git a/engine/include/cubos/engine/transform/child_of.hpp b/engine/include/cubos/engine/transform/child_of.hpp new file mode 100644 index 0000000000..24328ff1c6 --- /dev/null +++ b/engine/include/cubos/engine/transform/child_of.hpp @@ -0,0 +1,17 @@ +/// @file +/// @brief Relation @ref cubos::engine::ChildOf. +/// @ingroup transform-plugin + +#pragma once + +#include + +namespace cubos::engine +{ + /// @brief Tree relation which indicates the 'from' entity is a child of the 'to' entity. + /// @ingroup transform-plugin + struct ChildOf + { + CUBOS_REFLECT; + }; +} // namespace cubos::engine diff --git a/engine/include/cubos/engine/transform/local_to_parent.hpp b/engine/include/cubos/engine/transform/local_to_parent.hpp new file mode 100644 index 0000000000..b8f2959961 --- /dev/null +++ b/engine/include/cubos/engine/transform/local_to_parent.hpp @@ -0,0 +1,28 @@ +/// @file +/// @brief Component @ref cubos::engine::LocalToParent. +/// @ingroup transform-plugin + +#pragma once + +#include + +#include + +namespace cubos::engine +{ + /// @brief Component which stores the transformation matrix of an entity, from local to parent + /// space. + /// + /// @note This component is written to by the @ref transform-plugin "transform plugin", thus + /// it never makes sense to write to it manually. + /// + /// @sa @ref Position, @ref Rotation and @ref Scale, which apply transformations to this matrix. + /// @ingroup transform-plugin + struct LocalToParent + { + CUBOS_REFLECT; + + glm::mat4 mat = glm::mat4(1.0F); ///< Local to parent space matrix. + }; + +} // namespace cubos::engine diff --git a/engine/include/cubos/engine/transform/local_to_world.hpp b/engine/include/cubos/engine/transform/local_to_world.hpp index 9e0a166259..a8d183a880 100644 --- a/engine/include/cubos/engine/transform/local_to_world.hpp +++ b/engine/include/cubos/engine/transform/local_to_world.hpp @@ -13,13 +13,11 @@ namespace cubos::engine /// @brief Component which stores the transformation matrix of an entity, from local to world /// space. /// - /// @note This component is written to by the @ref transform-plugin "transform plugin", and - /// it only makes sense to modify it manually if its not accompanied by the other transform - /// components. + /// @note This component is written to by the @ref transform-plugin "transform plugin", thus it never makes sense to + /// write to it manually. /// - /// @sa Position Applies a translation to this matrix. - /// @sa Rotation Applies a rotation to this matrix. - /// @sa Scale Applies a scaling to this matrix. + /// @sa The value is calculated from the @ref LocalToParent component and the parent's @ref LocalToWorld, if there's + /// any. /// @ingroup transform-plugin struct LocalToWorld { diff --git a/engine/include/cubos/engine/transform/plugin.hpp b/engine/include/cubos/engine/transform/plugin.hpp index 70880f7200..a0b8f8c581 100644 --- a/engine/include/cubos/engine/transform/plugin.hpp +++ b/engine/include/cubos/engine/transform/plugin.hpp @@ -8,6 +8,8 @@ #pragma once #include +#include +#include #include #include #include @@ -19,23 +21,33 @@ namespace cubos::engine /// @ingroup engine /// @brief Adds transform components which assign positions, rotations and scaling to entities. /// - /// This plugin operates on entities with a @ref LocalToWorld component and any combination of - /// the @ref Position, @ref Rotation and @ref Scale components. For example, if you have an - /// entity which doesn't need rotation, but has a position and a scale, you do not need to add - /// the @ref Rotation component, and its transform will still be updated. + /// This plugin operates on entities with @ref LocalToWorld and @ref LocalToParent components, and any combination + /// of the @ref Position, @ref Rotation and @ref Scale components. For example, if you have an entity which doesn't + /// need rotation, but has a position and a scale, you do not need to add the @ref Rotation component, and its + /// transform will still be updated. /// /// @note Any entity with either a @ref Position, @ref Rotation or @ref Scale component /// automatically gets a @ref LocalToWorld component. /// /// ## Components + /// - @ref LocalToParent - holds the local to parent transform matrix. /// - @ref LocalToWorld - holds the local to world transform matrix. /// - @ref Position - holds the position of an entity. /// - @ref Rotation - holds the rotation of an entity. /// - @ref Scale - holds the scaling of an entity. /// + /// ## Relations + /// - @ref ChildOf - tree like relation which indicates an entity is a child of another. + /// /// ## Tags - /// - `cubos.transform.update` - the @ref LocalToWorld components are updated with the - /// information from the @ref Position, @ref Rotation and @ref Scale components. + /// - `cubos.transform.missing.local_to_world` - the @ref LocalToWorld components are added to entities with @ref + /// Position, @ref Rotation or @ref Scale components. + /// - `cubos.transform.missing` - the @ref Position, @ref Rotation, @ref Scale and possibly @ref LocalToParent + /// components are added to entities with @ref LocalToWorld components. + /// - `cubos.transform.update.relative` - the @ref LocalToWorld or @ref LocalToParent components are updated with + /// the information from the @ref Position, @ref Rotation and @ref Scale components. + /// - `cubos.transform.update` - the @ref LocalToWorld components are updated with the information from the @ref + /// LocalToParent component and the @ref LocalToWorld components of the parent. /// @brief Plugin entry function. /// @param cubos @b CUBOS. main class diff --git a/engine/include/cubos/engine/transform/scale.hpp b/engine/include/cubos/engine/transform/scale.hpp index 916d426edc..1ba8260597 100644 --- a/engine/include/cubos/engine/transform/scale.hpp +++ b/engine/include/cubos/engine/transform/scale.hpp @@ -15,6 +15,6 @@ namespace cubos::engine { CUBOS_REFLECT; - float factor; ///< Uniform scale factor of the entity. + float factor{1.0F}; ///< Uniform scale factor of the entity. }; } // namespace cubos::engine diff --git a/engine/samples/physics/main.cpp b/engine/samples/physics/main.cpp index d068544b9c..e60ee19fba 100644 --- a/engine/samples/physics/main.cpp +++ b/engine/samples/physics/main.cpp @@ -66,25 +66,26 @@ int main(int argc, char** argv) .add(RenderableGrid{CarAsset, offset}) .add(Position{{0.0F, 0.0F, 0.0F}}) .add(PreviousPosition{{0.0F, 0.0F, 0.0F}}) - .add(PhysicsVelocity{ - .velocity = {0.0F, 0.0F, 0.0F}, .force = {0.0F, 0.0F, 0.0F}, .impulse = {0.0F, 0.0F, 0.0F}}) - .add(PhysicsMass{.mass = 500.0F, .inverseMass = 1.0F / 500.0F}) + .add(Velocity{.vec = {0.0F, 0.0F, 0.0F}}) + .add(Force{}) + .add(Impulse{}) + .add(Mass{.mass = 500.0F, .inverseMass = 1.0F / 500.0F}) .add(AccumulatedCorrection{{0.0F, 0.0F, 0.0F}}) .add(LocalToWorld{}); }); cubos.system("push the car") .tagged("cubos.physics.apply_forces") - .call([](Query query, MaxTime& time, const DeltaTime& deltaTime) { - for (auto [velocity] : query) + .call([](Query query, MaxTime& time, const DeltaTime& deltaTime) { + for (auto [velocity, force, impulse] : query) { if (time.current < time.max) { if (time.current == 0.0F) { - velocity.impulse += glm::vec3(0.0F, 5000.0F, 0.0F); + impulse.add(glm::vec3(0.0F, 5000.0F, 0.0F)); } - velocity.force += glm::vec3(0.0F, 0.0F, -5000.0F); + force.add(glm::vec3(0.0F, 0.0F, -5000.0F)); time.current += deltaTime.value; } } diff --git a/engine/samples/scene/assets/main.cubos b/engine/samples/scene/assets/main.cubos index 1b3fda4a0a..ec8e7a2812 100644 --- a/engine/samples/scene/assets/main.cubos +++ b/engine/samples/scene/assets/main.cubos @@ -1,21 +1,22 @@ { - "imports": { - "sub1": "cd007ba2-ee0d-44fd-bf36-85c829dbe66f", - "sub2": "cd007ba2-ee0d-44fd-bf36-85c829dbe66f" - }, "entities": { "main": { "Num": 0 }, + "notmain": { + "Num": 120, + "OwnedBy@main": {} + }, "sub1.root": { - "OwnedBy": "main", - "DistanceTo": { - "entity": "sub2.root", - "value": 5 - } + "DistanceTo@sub2.root": 5, + "OwnedBy@main": {} }, "sub2.root": { - "OwnedBy": "main" + "OwnedBy@main": {} } + }, + "imports": { + "sub1": "cd007ba2-ee0d-44fd-bf36-85c829dbe66f", + "sub2": "cd007ba2-ee0d-44fd-bf36-85c829dbe66f" } -} +} \ No newline at end of file diff --git a/engine/samples/scene/assets/sub.cubos b/engine/samples/scene/assets/sub.cubos index ce337a0b33..232501c716 100644 --- a/engine/samples/scene/assets/sub.cubos +++ b/engine/samples/scene/assets/sub.cubos @@ -6,7 +6,7 @@ }, "child": { "Num": 2, - "OwnedBy": "root" + "OwnedBy@root": {} } } -} +} \ No newline at end of file diff --git a/engine/samples/scene/main.cpp b/engine/samples/scene/main.cpp index b45615181f..ae25dc2d8c 100644 --- a/engine/samples/scene/main.cpp +++ b/engine/samples/scene/main.cpp @@ -60,7 +60,7 @@ int main(int argc, char** argv) .tagged("cubos.assets") .call([](Commands commands, const Assets& assets) { auto sceneRead = assets.read(SceneAsset); - commands.spawn(sceneRead->blueprint); + commands.spawn(sceneRead->blueprint, true); }); /// [Spawning the scene] diff --git a/engine/samples/scene/page.md b/engine/samples/scene/page.md index 00a7f6fe7f..8ed5a6ce55 100644 --- a/engine/samples/scene/page.md +++ b/engine/samples/scene/page.md @@ -18,7 +18,7 @@ Scene files are JSON files with the extension `.cubos`. They must have two field The `entities` field is an object where each field identifies and describes the components and relations of an entity. In this scene we have two entities, `root` and `child`. `root` has a single component, `Num`, with a value of 1. -`child` too has a component `Num`, but also has a relation `OwnedBy` with `root` as target. +`child` too has a component `Num`, but also has a relation `OwnedBy` with `root` as target, indicated by the character `@`. In this sample, `Num` is used so we can later identify the entities. @note Make sure these component names match the ones in your application and that they have been registered with @ref cubos::engine::Cubos "Cubos". @@ -32,7 +32,7 @@ It then imports the very same scene again, but this time with the name `sub2` in This effectively instantiates the entities of the previous scene twice in this new scene, each with their names prefixed with either `sub1.` or `sub2.` Also take a look at the `DistanceTo` relation: it is a symmetric relation, so it doesn't make a different whether wwe put it in `sub.root` or `sub2.root`. -Since `DistanceTo` is a relation which holds data, instead of only specifying the target, as we do with `OwnedBy`, we write a JSON object with two keys, `"entity"` and `"value"`. +Since `DistanceTo` is a relation which holds data, instead of only specifying the target, as we do with `OwnedBy`, we write a JSON object with a key, `"value"`. Under `entities`, we can override the entities in the sub-scenes to edit components or add new ones. For example, by referencing `sub1.root` we are making local changes to the `root` entity of that instance of the subscene. diff --git a/engine/src/cubos/engine/assets/asset.cpp b/engine/src/assets/asset.cpp similarity index 100% rename from engine/src/cubos/engine/assets/asset.cpp rename to engine/src/assets/asset.cpp diff --git a/engine/src/cubos/engine/assets/assets.cpp b/engine/src/assets/assets.cpp similarity index 100% rename from engine/src/cubos/engine/assets/assets.cpp rename to engine/src/assets/assets.cpp diff --git a/engine/src/cubos/engine/assets/bridge.cpp b/engine/src/assets/bridge.cpp similarity index 100% rename from engine/src/cubos/engine/assets/bridge.cpp rename to engine/src/assets/bridge.cpp diff --git a/engine/src/cubos/engine/assets/bridges/file.cpp b/engine/src/assets/bridges/file.cpp similarity index 100% rename from engine/src/cubos/engine/assets/bridges/file.cpp rename to engine/src/assets/bridges/file.cpp diff --git a/engine/src/cubos/engine/assets/meta.cpp b/engine/src/assets/meta.cpp similarity index 100% rename from engine/src/cubos/engine/assets/meta.cpp rename to engine/src/assets/meta.cpp diff --git a/engine/src/cubos/engine/assets/plugin.cpp b/engine/src/assets/plugin.cpp similarity index 100% rename from engine/src/cubos/engine/assets/plugin.cpp rename to engine/src/assets/plugin.cpp diff --git a/engine/src/cubos/engine/collisions/broad_phase/plugin.cpp b/engine/src/collisions/broad_phase/plugin.cpp similarity index 100% rename from engine/src/cubos/engine/collisions/broad_phase/plugin.cpp rename to engine/src/collisions/broad_phase/plugin.cpp diff --git a/engine/src/cubos/engine/collisions/broad_phase/plugin.hpp b/engine/src/collisions/broad_phase/plugin.hpp similarity index 100% rename from engine/src/cubos/engine/collisions/broad_phase/plugin.hpp rename to engine/src/collisions/broad_phase/plugin.hpp diff --git a/engine/src/cubos/engine/collisions/broad_phase/potentially_colliding_with.cpp b/engine/src/collisions/broad_phase/potentially_colliding_with.cpp similarity index 100% rename from engine/src/cubos/engine/collisions/broad_phase/potentially_colliding_with.cpp rename to engine/src/collisions/broad_phase/potentially_colliding_with.cpp diff --git a/engine/src/cubos/engine/collisions/broad_phase/sweep_and_prune.cpp b/engine/src/collisions/broad_phase/sweep_and_prune.cpp similarity index 100% rename from engine/src/cubos/engine/collisions/broad_phase/sweep_and_prune.cpp rename to engine/src/collisions/broad_phase/sweep_and_prune.cpp diff --git a/engine/src/cubos/engine/collisions/broad_phase/sweep_and_prune.hpp b/engine/src/collisions/broad_phase/sweep_and_prune.hpp similarity index 100% rename from engine/src/cubos/engine/collisions/broad_phase/sweep_and_prune.hpp rename to engine/src/collisions/broad_phase/sweep_and_prune.hpp diff --git a/engine/src/cubos/engine/collisions/collider.cpp b/engine/src/collisions/collider.cpp similarity index 100% rename from engine/src/cubos/engine/collisions/collider.cpp rename to engine/src/collisions/collider.cpp diff --git a/engine/src/cubos/engine/collisions/plugin.cpp b/engine/src/collisions/plugin.cpp similarity index 100% rename from engine/src/cubos/engine/collisions/plugin.cpp rename to engine/src/collisions/plugin.cpp diff --git a/engine/src/cubos/engine/collisions/shapes/box.cpp b/engine/src/collisions/shapes/box.cpp similarity index 100% rename from engine/src/cubos/engine/collisions/shapes/box.cpp rename to engine/src/collisions/shapes/box.cpp diff --git a/engine/src/cubos/engine/collisions/shapes/capsule.cpp b/engine/src/collisions/shapes/capsule.cpp similarity index 100% rename from engine/src/cubos/engine/collisions/shapes/capsule.cpp rename to engine/src/collisions/shapes/capsule.cpp diff --git a/engine/src/cubos/engine/input/bindings.cpp b/engine/src/cubos/engine/input/bindings.cpp deleted file mode 100644 index 9ccb4dfc60..0000000000 --- a/engine/src/cubos/engine/input/bindings.cpp +++ /dev/null @@ -1,128 +0,0 @@ -#include -#include -#include - -#include - -using cubos::core::io::Key; -using cubos::core::io::keyToString; -using cubos::core::io::Modifiers; -using cubos::core::io::modifiersToString; -using cubos::core::io::stringToKey; -using cubos::core::io::stringToModifiers; -using namespace cubos::engine; - -CUBOS_REFLECT_IMPL(cubos::engine::InputBindings) -{ - return core::reflection::Type::create("cubos::engine::InputBindings"); -} - -const std::unordered_map& InputBindings::actions() const -{ - return mActions; -} - -const std::unordered_map& InputBindings::axes() const -{ - return mAxes; -} - -std::unordered_map& InputBindings::actions() -{ - return mActions; -} - -std::unordered_map& InputBindings::axes() -{ - return mAxes; -} - -template <> -void cubos::core::data::old::serialize(Serializer& ser, const InputBindings& obj, const char* name) -{ - ser.beginObject(name); - ser.beginDictionary(obj.actions().size(), "actions"); - for (const auto& [actionName, action] : obj.actions()) - { - ser.write(actionName, nullptr); - ser.beginObject(nullptr); - ser.write(action.keys(), "keys"); - ser.write(action.gamepadButtons(), "gamepad"); - ser.write(action.mouseButtons(), "mouse"); - ser.endObject(); - } - ser.endDictionary(); - ser.beginDictionary(obj.axes().size(), "axes"); - for (const auto& [axisName, axis] : obj.axes()) - { - ser.write(axisName, nullptr); - ser.beginObject(nullptr); - ser.write(axis.positive(), "pos"); - ser.write(axis.negative(), "neg"); - ser.write(axis.gamepadAxes(), "gamepad"); - ser.endObject(); - } - ser.endDictionary(); - ser.endObject(); -} - -template <> -void cubos::core::data::old::deserialize(Deserializer& des, InputBindings& obj) -{ - des.beginObject(); - - std::size_t actionsSz = des.beginDictionary(); - for (std::size_t i = 0; i < actionsSz; ++i) - { - std::string action; - des.read(action); - des.beginObject(); - des.read(obj.actions()[action].keys()); - des.read(obj.actions()[action].gamepadButtons()); - des.read(obj.actions()[action].mouseButtons()); - des.endObject(); - } - des.endDictionary(); - - std::size_t axesSz = des.beginDictionary(); - for (std::size_t i = 0; i < axesSz; ++i) - { - std::string axis; - des.read(axis); - des.beginObject(); - des.read(obj.axes()[axis].positive()); - des.read(obj.axes()[axis].negative()); - des.read(obj.axes()[axis].gamepadAxes()); - des.endObject(); - } - des.endDictionary(); - - des.endObject(); -} - -// This is a specialization of the serialize and deserialize functions for std::pair. -// Overloading these functions allows for human-readable serialization of the keybindings. - -template <> -void cubos::core::data::old::serialize(Serializer& ser, const std::pair& obj, - const char* name) -{ - ser.write(modifiersToString(obj.second) + keyToString(obj.first), name); -} - -template <> -void cubos::core::data::old::deserialize(Deserializer& des, std::pair& obj) -{ - std::string str; - des.readString(str); - - std::size_t split = str.find_last_of('-'); - if (split == std::string::npos) - { - obj = {stringToKey(str), Modifiers::None}; - } - else - { - obj = {stringToKey(str.substr(split + 1)), stringToModifiers(str.substr(0, split + 1))}; - } -} diff --git a/engine/src/cubos/engine/scene/bridge.cpp b/engine/src/cubos/engine/scene/bridge.cpp deleted file mode 100644 index 69e1afc6b5..0000000000 --- a/engine/src/cubos/engine/scene/bridge.cpp +++ /dev/null @@ -1,255 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -using cubos::core::data::JSONDeserializer; -using cubos::core::ecs::Blueprint; -using cubos::core::ecs::Entity; -using cubos::core::memory::AnyValue; -using cubos::core::memory::Stream; -using cubos::core::reflection::TypeRegistry; - -using namespace cubos::engine; - -SceneBridge::SceneBridge(TypeRegistry components, TypeRegistry relations) - : FileBridge(core::reflection::reflect()) - , mComponents{std::move(components)} - , mRelations{std::move(relations)} -{ -} - -TypeRegistry& SceneBridge::components() -{ - return mComponents; -} - -bool SceneBridge::loadFromFile(Assets& assets, const AnyAsset& handle, Stream& stream) -{ - // Dump the file contents into a string. - std::string contents{}; - stream.readUntil(contents, nullptr); - - // Parse the file contents as JSON. - nlohmann::json json{}; - - try - { - json = nlohmann::json::parse(contents); - } - catch (nlohmann::json::parse_error& e) - { - CUBOS_ERROR("{}", e.what()); - return false; - } - - // Check if the parsed JSON follows the expected scene structure - if (!json.is_object()) - { - CUBOS_ERROR("Expected root to be a JSON object, found {}", json.type_name()); - return false; - } - - for (const auto& [name, item] : json.items()) - { - if (name != "imports" && name != "entities") - { - CUBOS_ERROR("Expected 'imports' or 'entities', found '{}'", name); - return false; - } - } - - Scene scene{}; - JSONDeserializer des{}; - des.hook([&des, &scene](Entity& entity) { - std::string name{}; - if (!des.read(name)) - { - return false; - } - - if (!scene.blueprint.bimap().containsRight(name)) - { - CUBOS_ERROR("Could not deserialize entity from name, no such entity '{}' in scene", name); - return false; - } - - entity = scene.blueprint.bimap().atRight(name); - return true; - }); - - if (json.contains("imports")) - { - des.feed(json.at("imports")); - if (!des.read(scene.imports)) - { - CUBOS_ERROR("Could not deserialize scene imports"); - return false; - } - - for (const auto& [name, asset] : scene.imports) - { - scene.blueprint.merge(name, assets.read(asset)->blueprint); - } - } - - if (json.contains("entities")) - { - const auto& entitiesJSON = json.at("entities"); - if (!entitiesJSON.is_object()) - { - CUBOS_ERROR("Expected 'entities' to be a JSON object, found {}", entitiesJSON.type_name()); - return false; - } - - // Create all entities first. - for (const auto& [entityName, entityJSON] : entitiesJSON.items()) - { - // If we didn't find an entity with the given name, then we must create one. - if (!scene.blueprint.bimap().containsRight(entityName)) - { - // If the entity name contains a dot, then it must have been imported. If we didn't - // find it, the user did something wrong. - if (entityName.find('.') != std::string::npos) - { - CUBOS_ERROR("No such entity '{}' was imported", entityName); - return false; - } - - if (!Blueprint::validEntityName(entityName)) - { - CUBOS_ERROR("Invalid entity name '{}'", entityName); - return false; - } - - scene.blueprint.create(entityName); - } - } - - // Then add their components. This way the Entity hook will be able to handle entities which - // are declared after it in the scene file. - for (const auto& [entityName, entityJSON] : entitiesJSON.items()) - { - if (!entityJSON.is_object()) - { - CUBOS_ERROR("Expected entity {} to be a JSON object, found {}", entityName, entitiesJSON.type_name()); - return false; - } - - auto entity = scene.blueprint.bimap().atRight(entityName); - - for (const auto& [typeName, dataJSON] : entityJSON.items()) - { - if (mComponents.contains(typeName)) - { - // Create the component with the default value. - auto component = AnyValue::defaultConstruct(mComponents.at(typeName)); - - // Then change any values using the associated JSON. - des.feed(dataJSON); - if (!des.read(component.type(), component.get())) - { - CUBOS_ERROR("Could not deserialize component of type {} of entity {}", typeName, entityName); - return false; - } - - // And finally, add it to the blueprint. - scene.blueprint.add(entity, core::memory::move(component)); - } - else if (mRelations.contains(typeName)) - { - // Create the relation with the default value. - auto relation = AnyValue::defaultConstruct(mRelations.at(typeName)); - - std::string toName; - if (dataJSON.is_string()) - { - // If the user only specified a string, then the relation will keep the default value and the - // string represents the 'to' entity. - toName = dataJSON; - } - else if (dataJSON.is_object()) - { - // If the user specified an object, then it must contain an "entity" key, whose value - // represents the 'to' entity. - if (!dataJSON.contains("entity") || !dataJSON.at("entity").is_string()) - { - CUBOS_ERROR("Could not deserialize relation of type {} from entity {}: expected JSON " - "object to contain key \"entity\" with a string value", - typeName, entityName, dataJSON.type_name()); - return false; - } - toName = dataJSON.at("entity"); - - // If the value is specified, then deserialize the relation from it. - if (dataJSON.contains("value")) - { - des.feed(dataJSON.at("value")); - if (!des.read(relation.type(), relation.get())) - { - CUBOS_ERROR("Could not deserialize relation of type {} from entity {} to {}", typeName, - entityName, toName); - return false; - } - } - - // Check if there extra unused fields in the object. - for (const auto& [key, unusedJSON] : dataJSON.items()) - { - if (key != "entity" && key != "value") - { - CUBOS_ERROR("Could not deserialize relation of type {} from entity {} to entity {}: " - "expected \"entity\" or \"value\", found {}", - typeName, entityName, toName, key); - return false; - } - } - } - else - { - CUBOS_ERROR("Could not deserialize relation of type {} from entity {}: expected JSON object " - "but found {}", - typeName, entityName, dataJSON.type_name()); - return false; - } - - if (!scene.blueprint.bimap().containsRight(toName)) - { - CUBOS_ERROR("Could not deserialize relation of type {} from entity {} to {}: no such entity {}", - typeName, entityName, toName, toName); - return false; - } - - auto toEntity = scene.blueprint.bimap().atRight(toName); - scene.blueprint.relate(entity, toEntity, std::move(relation)); - } - else - { - CUBOS_ERROR("No such component or relation type {} registered on the scene bridge", typeName); - return false; - } - } - } - } - - // Finally, write the scene to the asset. - assets.store(handle, std::move(scene)); - return true; -} - -bool SceneBridge::saveToFile(const Assets& /*assets*/, const AnyAsset& /*handle*/, Stream& /*stream*/) -{ - // TODO: figure out how to do this. - // One of the problems is finding out exactly what was overriden in sub-scenes. - // One way to solve it would be to have a way to compare entities between blueprints, maybe - // with a hash? - CUBOS_CRITICAL("SceneBridge::save not implemented"); - return false; -} diff --git a/engine/src/cubos/engine/transform/plugin.cpp b/engine/src/cubos/engine/transform/plugin.cpp deleted file mode 100644 index 235c6a6eed..0000000000 --- a/engine/src/cubos/engine/transform/plugin.cpp +++ /dev/null @@ -1,46 +0,0 @@ -#include - -void cubos::engine::transformPlugin(Cubos& cubos) -{ - cubos.addComponent(); - cubos.addComponent(); - cubos.addComponent(); - cubos.addComponent(); - - cubos.system("add LocalToWorld where needed") - .before("cubos.transform.update") - .call([](Commands cmds, - Query, Opt, Opt, Opt> - query) { - for (auto [entity, localToWorld, position, rotation, scale] : query) - { - if (!localToWorld && (position || rotation || scale)) - { - cmds.add(entity, LocalToWorld{}); - } - } - }); - - cubos.system("update LocalToWorld") - .tagged("cubos.transform.update") - .call([](Query, Opt, Opt> query) { - for (auto [entity, localToWorld, position, rotation, scale] : query) - { - localToWorld.mat = glm::mat4(1.0F); - if (position) - { - localToWorld.mat = glm::translate(localToWorld.mat, position->vec); - } - - if (rotation) - { - localToWorld.mat *= glm::toMat4(rotation->quat); - } - - if (scale) - { - localToWorld.mat = glm::scale(localToWorld.mat, glm::vec3(scale->factor)); - } - } - }); -} diff --git a/engine/src/cubos/engine/gizmos/gizmos.cpp b/engine/src/gizmos/gizmos.cpp similarity index 95% rename from engine/src/cubos/engine/gizmos/gizmos.cpp rename to engine/src/gizmos/gizmos.cpp index 1061c3a487..c6c6e52136 100644 --- a/engine/src/cubos/engine/gizmos/gizmos.cpp +++ b/engine/src/gizmos/gizmos.cpp @@ -83,6 +83,14 @@ void Gizmos::push(const std::shared_ptr& gizmo, const Space& space) } } +uint32_t Gizmos::mHasher(const std::string& id) +{ + uint32_t hash = static_cast(std::hash{}(id)); + // Set 32nd bit to distinguish from entities + hash |= static_cast(1 << 31); + return hash; +} + void Gizmos::drawLine(const std::string& id, glm::vec3 from, glm::vec3 to, float lifespan, Space space) { push(std::make_shared((uint32_t)mHasher(id), from, to, mColor, lifespan), space); diff --git a/engine/src/cubos/engine/gizmos/plugin.cpp b/engine/src/gizmos/plugin.cpp similarity index 80% rename from engine/src/cubos/engine/gizmos/plugin.cpp rename to engine/src/gizmos/plugin.cpp index bdf7b3272e..9608642987 100644 --- a/engine/src/cubos/engine/gizmos/plugin.cpp +++ b/engine/src/gizmos/plugin.cpp @@ -6,6 +6,7 @@ #include #include +#include #include #include @@ -23,7 +24,7 @@ using namespace cubos::engine; static void iterateGizmos(std::vector>& gizmosVector, const std::vector>& cameras, - GizmosRenderer& gizmosRenderer, const DeltaTime& deltaTime) + GizmosRenderer& gizmosRenderer, ScreenPicker& screenPicker, const DeltaTime& deltaTime) { std::vector toRemove; @@ -42,7 +43,7 @@ static void iterateGizmos(std::vector>& gizmosVec // Id gizmosRenderer.renderDevice->setShaderPipeline(gizmosRenderer.idPipeline); - gizmosRenderer.renderDevice->setFramebuffer(gizmosRenderer.idFramebuffer); + gizmosRenderer.renderDevice->setFramebuffer(screenPicker.framebuffer()); gizmosRenderer.idPipeline->getBindingPoint("gizmo")->setConstant(gizmo.id); @@ -186,6 +187,7 @@ static std::vector> getScreenInfo(c void cubos::engine::gizmosPlugin(Cubos& cubos) { + cubos.addPlugin(cubos::engine::screenPickerPlugin); cubos.addPlugin(cubos::engine::windowPlugin); cubos.addResource(); @@ -194,16 +196,15 @@ void cubos::engine::gizmosPlugin(Cubos& cubos) cubos.startupSystem("initialize GizmosRenderer") .tagged("cubos.gizmos.init") .after("cubos.window.init") - .call([](GizmosRenderer& gizmosRenderer, const Window& window) { - gizmosRenderer.init(&window->renderDevice(), window->framebufferSize()); - }); + .call( + [](GizmosRenderer& gizmosRenderer, const Window& window) { gizmosRenderer.init(&window->renderDevice()); }); cubos.system("process gizmos input") .tagged("cubos.gizmos.input") .after("cubos.window.poll") .before("cubos.gizmos.draw") .call([](GizmosRenderer& gizmosRenderer, Gizmos& gizmos, EventReader windowEvent) { - bool locking = false; + gizmos.mLocking = false; for (const auto& event : windowEvent) { if (std::holds_alternative(event)) @@ -221,74 +222,56 @@ void cubos::engine::gizmosPlugin(Cubos& cubos) } else { - locking = true; + gizmos.mLocking = true; } } } - else if (std::holds_alternative(event)) - { - gizmosRenderer.resizeTexture(std::get(event).size); - } - } - - auto* texBuffer = new uint16_t[(std::size_t)gizmosRenderer.textureSize.x * - (std::size_t)gizmosRenderer.textureSize.y * 2U]; - - gizmosRenderer.idTexture->read(texBuffer); - - int mouseX = gizmosRenderer.lastMousePosition.x; - int mouseY = gizmosRenderer.textureSize.y - gizmosRenderer.lastMousePosition.y - 1; - - if (mouseX >= gizmosRenderer.textureSize.x || mouseX < 0) - { - delete[] texBuffer; - return; - } - if (mouseY >= gizmosRenderer.textureSize.y || mouseY < 0) - { - delete[] texBuffer; - return; } - - uint16_t r = texBuffer[(ptrdiff_t)(mouseY * gizmosRenderer.textureSize.x + mouseX) * 2U]; - uint16_t g = texBuffer[(ptrdiff_t)(mouseY * gizmosRenderer.textureSize.x + mouseX) * 2U + 1U]; - - uint32_t id = (static_cast(r) << 16U) | g; - - gizmos.handleInput(id, gizmosRenderer.mousePressed); - - if (locking) - { - gizmos.setLocked(id); - } - - delete[] texBuffer; }); cubos.system("draw gizmos") .tagged("cubos.gizmos.draw") .after("cubos.renderer.draw") .before("cubos.window.render") - .call([](Gizmos& gizmos, GizmosRenderer& gizmosRenderer, const ActiveCameras& activeCameras, - const Window& window, const DeltaTime& deltaTime, Query query) { + .call([](Gizmos& gizmos, GizmosRenderer& gizmosRenderer, ScreenPicker& screenPicker, + const ActiveCameras& activeCameras, const Window& window, const DeltaTime& deltaTime, + Query query) { auto screenSize = window->framebufferSize(); gizmosRenderer.renderDevice->setShaderPipeline(gizmosRenderer.drawPipeline); gizmosRenderer.renderDevice->setDepthStencilState(gizmosRenderer.doDepthCheckStencilState); gizmosRenderer.renderDevice->clearDepth(1.0F); - gizmosRenderer.renderDevice->setFramebuffer(gizmosRenderer.idFramebuffer); - gizmosRenderer.renderDevice->clearColor(0, 0, 0, 0); - gizmosRenderer.renderDevice->clearDepth(1.0F); - auto worldInfo = getWorldInfo(query, activeCameras, screenSize); - iterateGizmos(gizmos.worldGizmos, worldInfo, gizmosRenderer, deltaTime); + iterateGizmos(gizmos.worldGizmos, worldInfo, gizmosRenderer, screenPicker, deltaTime); gizmosRenderer.renderDevice->setDepthStencilState(gizmosRenderer.noDepthCheckStencilState); auto viewInfo = getViewInfo(activeCameras, screenSize); - iterateGizmos(gizmos.viewGizmos, viewInfo, gizmosRenderer, deltaTime); + iterateGizmos(gizmos.viewGizmos, viewInfo, gizmosRenderer, screenPicker, deltaTime); auto screenInfo = getScreenInfo(screenSize); - iterateGizmos(gizmos.screenGizmos, screenInfo, gizmosRenderer, deltaTime); + iterateGizmos(gizmos.screenGizmos, screenInfo, gizmosRenderer, screenPicker, deltaTime); + }); + + cubos.system("do gizmos screen picking") + .tagged("cubos.gizmos.pick") + .after("cubos.gizmos.draw") + .call([](GizmosRenderer& gizmosRenderer, Gizmos& gizmos, const ScreenPicker& screenPicker) { + int mouseX = gizmosRenderer.lastMousePosition.x; + int mouseY = gizmosRenderer.lastMousePosition.y; + + uint32_t id = screenPicker.at(mouseX, mouseY); + if (id < static_cast(1 << 31)) + { + // Not a gizmo, treat it like empty space + id = UINT32_MAX; + } + + gizmos.handleInput(id, gizmosRenderer.mousePressed); + + if (gizmos.mLocking) + { + gizmos.setLocked(id); + } }); } diff --git a/engine/src/cubos/engine/gizmos/renderer.cpp b/engine/src/gizmos/renderer.cpp similarity index 91% rename from engine/src/cubos/engine/gizmos/renderer.cpp rename to engine/src/gizmos/renderer.cpp index 1d3192b89a..fded053a0c 100644 --- a/engine/src/cubos/engine/gizmos/renderer.cpp +++ b/engine/src/gizmos/renderer.cpp @@ -5,33 +5,6 @@ using cubos::engine::GizmosRenderer; using namespace cubos::core::gl; -void GizmosRenderer::initIdTexture(glm::ivec2 size) -{ - Texture2DDesc texDesc; - texDesc.width = (std::size_t)size.x; - texDesc.height = (std::size_t)size.y; - texDesc.usage = Usage::Dynamic; - texDesc.format = TextureFormat::RG16UInt; - - idTexture = renderDevice->createTexture2D(texDesc); - - texDesc.format = TextureFormat::Depth16; - mDepthTexture = renderDevice->createTexture2D(texDesc); - - FramebufferDesc frameDesc; - frameDesc.targetCount = 1; - - FramebufferDesc::FramebufferTarget target; - target.setTexture2DTarget(idTexture); - - frameDesc.targets[0] = target; - frameDesc.depthStencil.setTexture2DTarget(mDepthTexture); - - idFramebuffer = renderDevice->createFramebuffer(frameDesc); - - textureSize = size; -} - void GizmosRenderer::initDrawPipeline() { auto vs = renderDevice->createShaderStage(Stage::Vertex, R"( @@ -101,7 +74,7 @@ void GizmosRenderer::initIdPipeline() idPipeline = renderDevice->createShaderPipeline(vs, ps); } -void GizmosRenderer::init(RenderDevice* currentRenderDevice, glm::ivec2 size) +void GizmosRenderer::init(RenderDevice* currentRenderDevice) { renderDevice = currentRenderDevice; @@ -113,8 +86,6 @@ void GizmosRenderer::init(RenderDevice* currentRenderDevice, glm::ivec2 size) dss.depth.writeEnabled = false; noDepthCheckStencilState = renderDevice->createDepthStencilState(dss); - initIdTexture(size); - initDrawPipeline(); initIdPipeline(); @@ -142,11 +113,6 @@ void GizmosRenderer::initLinePrimitive() linePrimitive.va = renderDevice->createVertexArray(linePrimitive.vaDesc); } -void GizmosRenderer::resizeTexture(glm::ivec2 size) -{ - initIdTexture(size); -} - void GizmosRenderer::initBoxPrimitive() { boxPrimitive.vaDesc.elementCount = 1; diff --git a/engine/src/cubos/engine/gizmos/renderer.hpp b/engine/src/gizmos/renderer.hpp similarity index 82% rename from engine/src/cubos/engine/gizmos/renderer.hpp rename to engine/src/gizmos/renderer.hpp index 139559b0fe..0996985d83 100644 --- a/engine/src/cubos/engine/gizmos/renderer.hpp +++ b/engine/src/gizmos/renderer.hpp @@ -31,20 +31,12 @@ namespace cubos::engine Primitive cutConePrimitive; ///< GL cut cone information. Primitive ringPrimitive; ///< GL ring information. - glm::ivec2 textureSize; ///< Size of the id texture. - cubos::core::gl::Texture2D idTexture; ///< Texture holding the ids of the gizmo that was drawn to each pixel. - cubos::core::gl::Framebuffer idFramebuffer; ///< Buffer holding the id texture. - cubos::core::gl::DepthStencilState doDepthCheckStencilState; ///< Stencil State that performs depth checks. cubos::core::gl::DepthStencilState noDepthCheckStencilState; ///< Stencil State that ignores depth checks. /// @brief Sets up the render device to be used. /// @param renderDevice the current Render device being used. - void init(cubos::core::gl::RenderDevice* currentRenderDevice, glm::ivec2 size); - - /// @brief Resizes the id texture. - /// @param size New size of the texture. - void resizeTexture(glm::ivec2 size); + void init(cubos::core::gl::RenderDevice* currentRenderDevice); glm::ivec2 lastMousePosition; ///< Cursor position. bool mousePressed; ///< Whether or not the mouse left button is pressed. @@ -52,8 +44,6 @@ namespace cubos::engine private: cubos::core::gl::Texture2D mDepthTexture; - void initIdTexture(glm::ivec2 size); - void initIdPipeline(); void initDrawPipeline(); diff --git a/engine/src/cubos/engine/gizmos/types/box.hpp b/engine/src/gizmos/types/box.hpp similarity index 100% rename from engine/src/cubos/engine/gizmos/types/box.hpp rename to engine/src/gizmos/types/box.hpp diff --git a/engine/src/cubos/engine/gizmos/types/cut_cone.hpp b/engine/src/gizmos/types/cut_cone.hpp similarity index 100% rename from engine/src/cubos/engine/gizmos/types/cut_cone.hpp rename to engine/src/gizmos/types/cut_cone.hpp diff --git a/engine/src/cubos/engine/gizmos/types/line.hpp b/engine/src/gizmos/types/line.hpp similarity index 100% rename from engine/src/cubos/engine/gizmos/types/line.hpp rename to engine/src/gizmos/types/line.hpp diff --git a/engine/src/cubos/engine/gizmos/types/ring.hpp b/engine/src/gizmos/types/ring.hpp similarity index 100% rename from engine/src/cubos/engine/gizmos/types/ring.hpp rename to engine/src/gizmos/types/ring.hpp diff --git a/engine/src/cubos/engine/imgui/data_inspector.cpp b/engine/src/imgui/data_inspector.cpp similarity index 100% rename from engine/src/cubos/engine/imgui/data_inspector.cpp rename to engine/src/imgui/data_inspector.cpp diff --git a/engine/src/cubos/engine/imgui/imgui.cpp b/engine/src/imgui/imgui.cpp similarity index 100% rename from engine/src/cubos/engine/imgui/imgui.cpp rename to engine/src/imgui/imgui.cpp diff --git a/engine/src/cubos/engine/imgui/imgui.hpp b/engine/src/imgui/imgui.hpp similarity index 100% rename from engine/src/cubos/engine/imgui/imgui.hpp rename to engine/src/imgui/imgui.hpp diff --git a/engine/src/cubos/engine/imgui/plugin.cpp b/engine/src/imgui/plugin.cpp similarity index 100% rename from engine/src/cubos/engine/imgui/plugin.cpp rename to engine/src/imgui/plugin.cpp diff --git a/engine/src/cubos/engine/input/action.cpp b/engine/src/input/action.cpp similarity index 100% rename from engine/src/cubos/engine/input/action.cpp rename to engine/src/input/action.cpp diff --git a/engine/src/cubos/engine/input/axis.cpp b/engine/src/input/axis.cpp similarity index 100% rename from engine/src/cubos/engine/input/axis.cpp rename to engine/src/input/axis.cpp diff --git a/engine/src/input/bindings.cpp b/engine/src/input/bindings.cpp new file mode 100644 index 0000000000..eba0842a2a --- /dev/null +++ b/engine/src/input/bindings.cpp @@ -0,0 +1,36 @@ +#include + +#include + +using cubos::core::io::Key; +using cubos::core::io::keyToString; +using cubos::core::io::Modifiers; +using cubos::core::io::modifiersToString; +using cubos::core::io::stringToKey; +using cubos::core::io::stringToModifiers; +using namespace cubos::engine; + +CUBOS_REFLECT_IMPL(cubos::engine::InputBindings) +{ + return core::reflection::Type::create("cubos::engine::InputBindings"); +} + +const std::unordered_map& InputBindings::actions() const +{ + return mActions; +} + +const std::unordered_map& InputBindings::axes() const +{ + return mAxes; +} + +std::unordered_map& InputBindings::actions() +{ + return mActions; +} + +std::unordered_map& InputBindings::axes() +{ + return mAxes; +} diff --git a/engine/src/cubos/engine/input/input.cpp b/engine/src/input/input.cpp similarity index 100% rename from engine/src/cubos/engine/input/input.cpp rename to engine/src/input/input.cpp diff --git a/engine/src/cubos/engine/input/plugin.cpp b/engine/src/input/plugin.cpp similarity index 100% rename from engine/src/cubos/engine/input/plugin.cpp rename to engine/src/input/plugin.cpp diff --git a/engine/src/cubos/engine/physics/gravity.cpp b/engine/src/physics/gravity.cpp similarity index 73% rename from engine/src/cubos/engine/physics/gravity.cpp rename to engine/src/physics/gravity.cpp index ce42a237d0..e5e3021585 100644 --- a/engine/src/cubos/engine/physics/gravity.cpp +++ b/engine/src/physics/gravity.cpp @@ -10,8 +10,8 @@ void cubos::engine::gravityPlugin(Cubos& cubos) cubos.system("apply gravity") .tagged("cubos.physics.apply_forces") - .call([](Query query, const Gravity& gravity) { - for (auto [velocity, mass] : query) + .call([](Query query, const Gravity& gravity) { + for (auto [velocity, force, mass] : query) { if (mass.inverseMass <= 0.0F) { @@ -21,7 +21,7 @@ void cubos::engine::gravityPlugin(Cubos& cubos) // Apply gravity force glm::vec3 gravitationForce = mass.mass * gravity.value; - velocity.force += gravitationForce; + force.add(gravitationForce); } }); } diff --git a/engine/src/cubos/engine/physics/physics_accumulator.hpp b/engine/src/physics/physics_accumulator.hpp similarity index 100% rename from engine/src/cubos/engine/physics/physics_accumulator.hpp rename to engine/src/physics/physics_accumulator.hpp diff --git a/engine/src/cubos/engine/physics/plugin.cpp b/engine/src/physics/plugin.cpp similarity index 66% rename from engine/src/cubos/engine/physics/plugin.cpp rename to engine/src/physics/plugin.cpp index fa436bfb8c..090f59bf6e 100644 --- a/engine/src/cubos/engine/physics/plugin.cpp +++ b/engine/src/physics/plugin.cpp @@ -15,20 +15,30 @@ CUBOS_REFLECT_IMPL(AccumulatedCorrection) .build(); } -CUBOS_REFLECT_IMPL(PhysicsMass) +CUBOS_REFLECT_IMPL(Mass) { - return cubos::core::ecs::TypeBuilder("cubos::engine::PhysicsMass") - .withField("mass", &PhysicsMass::mass) - .withField("inverseMass", &PhysicsMass::inverseMass) + return cubos::core::ecs::TypeBuilder("cubos::engine::Mass") + .withField("mass", &Mass::mass) + .withField("inverseMass", &Mass::inverseMass) .build(); } -CUBOS_REFLECT_IMPL(PhysicsVelocity) +CUBOS_REFLECT_IMPL(Velocity) { - return cubos::core::ecs::TypeBuilder("cubos::engine::PhysicsVelocity") - .withField("velocity", &PhysicsVelocity::velocity) - .withField("force", &PhysicsVelocity::force) - .withField("impulse", &PhysicsVelocity::impulse) + return cubos::core::ecs::TypeBuilder("cubos::engine::Velocity") + .withField("velocity", &Velocity::vec) + .build(); +} + +CUBOS_REFLECT_IMPL(Force) +{ + return cubos::core::ecs::TypeBuilder("cubos::engine::Force").withField("mForce", &Force::mForce).build(); +} + +CUBOS_REFLECT_IMPL(Impulse) +{ + return cubos::core::ecs::TypeBuilder("cubos::engine::Impulse") + .withField("mImpulse", &Impulse::mImpulse) .build(); } @@ -46,18 +56,20 @@ static bool simulatePhysicsStep(PhysicsAccumulator& accumulator, const FixedDelt void cubos::engine::physicsPlugin(Cubos& cubos) { - cubos.addPlugin(gravityPlugin); - cubos.addResource(); cubos.addResource(); cubos.addResource(); cubos.addResource(); - cubos.addComponent(); - cubos.addComponent(); + cubos.addComponent(); + cubos.addComponent(); + cubos.addComponent(); + cubos.addComponent(); cubos.addComponent(); cubos.addComponent(); + cubos.addPlugin(gravityPlugin); + // executed every frame cubos.system("increase fixed-step accumulator") .tagged("cubos.physics.simulation.prepare") @@ -74,10 +86,10 @@ void cubos::engine::physicsPlugin(Cubos& cubos) .after("cubos.physics.apply_forces") .before("cubos.physics.simulation.substeps.integrate") .onlyIf(simulatePhysicsStep) - .call([](Query query) { - for (auto [velocity, mass] : query) + .call([](Query query) { + for (auto [velocity, impulse, mass] : query) { - velocity.velocity += velocity.impulse * mass.inverseMass; + velocity.vec += impulse.vec() * mass.inverseMass; } }); @@ -85,11 +97,11 @@ void cubos::engine::physicsPlugin(Cubos& cubos) .tagged("cubos.physics.simulation.substeps.integrate") .after("cubos.physics.simulation.prepare") .onlyIf(simulatePhysicsStep) - .call([](Query query, + .call([](Query query, const Damping& damping, const FixedDeltaTime& fixedDeltaTime, const Substeps& substeps) { float subDeltaTime = fixedDeltaTime.value / (float)substeps.value; - for (auto [position, prevPosition, velocity, mass] : query) + for (auto [position, prevPosition, velocity, force, mass] : query) { prevPosition.vec = position.vec; @@ -99,13 +111,13 @@ void cubos::engine::physicsPlugin(Cubos& cubos) } // Apply damping - velocity.velocity *= glm::pow(damping.value, subDeltaTime); + velocity.vec *= glm::pow(damping.value, subDeltaTime); // Apply external forces - glm::vec3 deltaLinearVelocity = velocity.force * mass.inverseMass * subDeltaTime; + glm::vec3 deltaLinearVelocity = force.vec() * mass.inverseMass * subDeltaTime; - velocity.velocity += deltaLinearVelocity; - position.vec += velocity.velocity * subDeltaTime; + velocity.vec += deltaLinearVelocity; + position.vec += velocity.vec * subDeltaTime; } }); @@ -125,13 +137,13 @@ void cubos::engine::physicsPlugin(Cubos& cubos) .tagged("cubos.physics.simulation.substeps.update_velocity") .after("cubos.physics.simulation.substeps.correct_position") .onlyIf(simulatePhysicsStep) - .call([](Query query, - const FixedDeltaTime& fixedDeltaTime, const Substeps& substeps) { + .call([](Query query, const FixedDeltaTime& fixedDeltaTime, + const Substeps& substeps) { float subDeltaTime = fixedDeltaTime.value / (float)substeps.value; for (auto [position, prevPosition, velocity] : query) { - velocity.velocity = (position.vec - prevPosition.vec) / subDeltaTime; + velocity.vec = (position.vec - prevPosition.vec) / subDeltaTime; } }); @@ -139,11 +151,21 @@ void cubos::engine::physicsPlugin(Cubos& cubos) .tagged("cubos.physics.simulation.clear_forces") .after("cubos.physics.simulation.substeps.update_velocity") .onlyIf(simulatePhysicsStep) - .call([](Query query) { - for (auto [velocity] : query) + .call([](Query query) { + for (auto [force] : query) + { + force.clear(); + } + }); + + cubos.system("clear impulses") + .tagged("cubos.physics.simulation.clear_forces") + .after("cubos.physics.simulation.substeps.update_velocity") + .onlyIf(simulatePhysicsStep) + .call([](Query query) { + for (auto [impulse] : query) { - velocity.force = glm::vec3(0, 0, 0); - velocity.impulse = glm::vec3(0, 0, 0); + impulse.clear(); } }); diff --git a/engine/src/cubos/engine/prelude.cpp b/engine/src/prelude.cpp similarity index 100% rename from engine/src/cubos/engine/prelude.cpp rename to engine/src/prelude.cpp diff --git a/engine/src/cubos/engine/renderer/camera.cpp b/engine/src/renderer/camera.cpp similarity index 100% rename from engine/src/cubos/engine/renderer/camera.cpp rename to engine/src/renderer/camera.cpp diff --git a/engine/src/cubos/engine/renderer/deferred_renderer.cpp b/engine/src/renderer/deferred_renderer.cpp similarity index 100% rename from engine/src/cubos/engine/renderer/deferred_renderer.cpp rename to engine/src/renderer/deferred_renderer.cpp diff --git a/engine/src/cubos/engine/renderer/directional_light.cpp b/engine/src/renderer/directional_light.cpp similarity index 100% rename from engine/src/cubos/engine/renderer/directional_light.cpp rename to engine/src/renderer/directional_light.cpp diff --git a/engine/src/cubos/engine/renderer/frame.cpp b/engine/src/renderer/frame.cpp similarity index 100% rename from engine/src/cubos/engine/renderer/frame.cpp rename to engine/src/renderer/frame.cpp diff --git a/engine/src/cubos/engine/renderer/plugin.cpp b/engine/src/renderer/plugin.cpp similarity index 100% rename from engine/src/cubos/engine/renderer/plugin.cpp rename to engine/src/renderer/plugin.cpp diff --git a/engine/src/cubos/engine/renderer/point_light.cpp b/engine/src/renderer/point_light.cpp similarity index 100% rename from engine/src/cubos/engine/renderer/point_light.cpp rename to engine/src/renderer/point_light.cpp diff --git a/engine/src/cubos/engine/renderer/pps/bloom.cpp b/engine/src/renderer/pps/bloom.cpp similarity index 100% rename from engine/src/cubos/engine/renderer/pps/bloom.cpp rename to engine/src/renderer/pps/bloom.cpp diff --git a/engine/src/cubos/engine/renderer/pps/copy_pass.cpp b/engine/src/renderer/pps/copy_pass.cpp similarity index 100% rename from engine/src/cubos/engine/renderer/pps/copy_pass.cpp rename to engine/src/renderer/pps/copy_pass.cpp diff --git a/engine/src/cubos/engine/renderer/pps/manager.cpp b/engine/src/renderer/pps/manager.cpp similarity index 100% rename from engine/src/cubos/engine/renderer/pps/manager.cpp rename to engine/src/renderer/pps/manager.cpp diff --git a/engine/src/cubos/engine/renderer/pps/pass.cpp b/engine/src/renderer/pps/pass.cpp similarity index 100% rename from engine/src/cubos/engine/renderer/pps/pass.cpp rename to engine/src/renderer/pps/pass.cpp diff --git a/engine/src/cubos/engine/renderer/renderer.cpp b/engine/src/renderer/renderer.cpp similarity index 100% rename from engine/src/cubos/engine/renderer/renderer.cpp rename to engine/src/renderer/renderer.cpp diff --git a/engine/src/cubos/engine/renderer/spot_light.cpp b/engine/src/renderer/spot_light.cpp similarity index 100% rename from engine/src/cubos/engine/renderer/spot_light.cpp rename to engine/src/renderer/spot_light.cpp diff --git a/engine/src/cubos/engine/renderer/vertex.cpp b/engine/src/renderer/vertex.cpp similarity index 100% rename from engine/src/cubos/engine/renderer/vertex.cpp rename to engine/src/renderer/vertex.cpp diff --git a/engine/src/cubos/engine/renderer/viewport.cpp b/engine/src/renderer/viewport.cpp similarity index 100% rename from engine/src/cubos/engine/renderer/viewport.cpp rename to engine/src/renderer/viewport.cpp diff --git a/engine/src/scene/bridge.cpp b/engine/src/scene/bridge.cpp new file mode 100644 index 0000000000..36e89bf4cb --- /dev/null +++ b/engine/src/scene/bridge.cpp @@ -0,0 +1,374 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +using cubos::core::data::JSONDeserializer; +using cubos::core::data::JSONSerializer; +using cubos::core::ecs::Blueprint; +using cubos::core::ecs::Entity; +using cubos::core::memory::AnyValue; +using cubos::core::memory::Stream; +using cubos::core::reflection::TypeRegistry; + +using namespace cubos::engine; + +SceneBridge::SceneBridge(TypeRegistry components, TypeRegistry relations) + : FileBridge(core::reflection::reflect()) + , mComponents{std::move(components)} + , mRelations{std::move(relations)} +{ +} + +TypeRegistry& SceneBridge::components() +{ + return mComponents; +} + +bool SceneBridge::loadFromFile(Assets& assets, const AnyAsset& handle, Stream& stream) +{ + // Dump the file contents into a string. + std::string contents{}; + stream.readUntil(contents, nullptr); + + // Parse the file contents as JSON. + nlohmann::json json{}; + + try + { + json = nlohmann::json::parse(contents); + } + catch (nlohmann::json::parse_error& e) + { + CUBOS_ERROR("{}", e.what()); + return false; + } + + // Check if the parsed JSON follows the expected scene structure + if (!json.is_object()) + { + CUBOS_ERROR("Expected root to be a JSON object, found {}", json.type_name()); + return false; + } + + for (const auto& [name, item] : json.items()) + { + if (name != "imports" && name != "entities") + { + CUBOS_ERROR("Expected 'imports' or 'entities', found '{}'", name); + return false; + } + } + + Scene scene{}; + JSONDeserializer des{}; + des.hook([&des, &scene](Entity& entity) { + std::string name{}; + if (!des.read(name)) + { + return false; + } + + if (!scene.blueprint.bimap().containsRight(name)) + { + CUBOS_ERROR("Could not deserialize entity from name, no such entity '{}' in scene", name); + return false; + } + + entity = scene.blueprint.bimap().atRight(name); + return true; + }); + + if (json.contains("imports")) + { + des.feed(json.at("imports")); + if (!des.read(scene.imports)) + { + CUBOS_ERROR("Could not deserialize scene imports"); + return false; + } + + for (const auto& [name, asset] : scene.imports) + { + scene.blueprint.merge(name, assets.read(asset)->blueprint, true); + } + } + + if (json.contains("entities")) + { + const auto& entitiesJSON = json.at("entities"); + if (!entitiesJSON.is_object()) + { + CUBOS_ERROR("Expected 'entities' to be a JSON object, found {}", entitiesJSON.type_name()); + return false; + } + + // Create all entities first. + for (const auto& [entityName, entityJSON] : entitiesJSON.items()) + { + // If we didn't find an entity with the given name, then we must create one. + if (!scene.blueprint.bimap().containsRight(entityName)) + { + // If the entity name contains a dot, then it must have been imported. If we didn't + // find it, the user did something wrong. + if (entityName.find('.') != std::string::npos) + { + CUBOS_ERROR("No such entity '{}' was imported", entityName); + return false; + } + + if (!Blueprint::validEntityName(entityName)) + { + CUBOS_ERROR("Invalid entity name '{}'", entityName); + return false; + } + + scene.blueprint.create(entityName); + } + } + + // Then add their components. This way the Entity hook will be able to handle entities which + // are declared after it in the scene file. + for (const auto& [entityName, entityJSON] : entitiesJSON.items()) + { + if (!entityJSON.is_object()) + { + CUBOS_ERROR("Expected entity {} to be a JSON object, found {}", entityName, entitiesJSON.type_name()); + return false; + } + + auto entity = scene.blueprint.bimap().atRight(entityName); + + for (const auto& [typeName, dataJSON] : entityJSON.items()) + { + if (mComponents.contains(typeName)) + { + // Create the component with the default value. + auto component = AnyValue::defaultConstruct(mComponents.at(typeName)); + + // Then change any values using the associated JSON. + des.feed(dataJSON); + if (!des.read(component.type(), component.get())) + { + CUBOS_ERROR("Could not deserialize component of type {} of entity {}", typeName, entityName); + return false; + } + + // And finally, add it to the blueprint. + scene.blueprint.add(entity, core::memory::move(component)); + } + else if (typeName.find('@') != std::string::npos && + mRelations.contains(typeName.substr(0, typeName.find('@')))) + { + // Create the relation with the default value. + std::string relationName = typeName.substr(0, typeName.find('@')); + std::string toName = typeName.substr(typeName.find('@') + 1); + + auto relation = AnyValue::defaultConstruct(mRelations.at(relationName)); + + des.feed(dataJSON); + if (!des.read(relation.type(), relation.get())) + { + CUBOS_ERROR("Could not deserialize component of type {} of entity {}", typeName, entityName); + return false; + } + + if (!scene.blueprint.bimap().containsRight(toName)) + { + CUBOS_ERROR("Could not deserialize relation of type {} from entity {} to {}: no such entity {}", + relationName, entityName, toName, toName); + return false; + } + + auto toEntity = scene.blueprint.bimap().atRight(toName); + scene.blueprint.relate(entity, toEntity, std::move(relation)); + } + else + { + CUBOS_ERROR("No such component or relation type {} registered on the scene bridge", typeName); + return false; + } + } + } + } + + // Finally, write the scene to the asset. + assets.store(handle, std::move(scene)); + return true; +} + +std::tuple&> originalComponentData(const Assets& assets, const Asset& sceneAsset, + const std::string& entityPath, + const cubos::core::reflection::Type& componentType) +{ + auto scene = assets.read(sceneAsset); + if (entityPath.find('.') == std::string::npos) + { + auto entity = scene->blueprint.entities().atRight(entityPath); + if (auto components = scene->blueprint.components().at(componentType); !components.contains(entity)) + { + return {nullptr, sceneAsset}; + } + return {entityPath, sceneAsset}; + } + + std::string subScenePath = entityPath.substr(0, entityPath.find('.')); + auto newPath = entityPath.substr(entityPath.find('.') + 1); + return originalComponentData(assets, scene->imports.at(subScenePath), newPath, componentType); +} + +std::tuple&> originalRelationData( + const Assets& assets, const Asset& sceneAsset, const std::string& entityPath, const std::string& otherPath, + const cubos::core::reflection::Type& relationType) +{ + auto scene = assets.read(sceneAsset); + if (entityPath.find('.') == std::string::npos) + { + auto entity = scene->blueprint.entities().atRight(entityPath); + auto other = scene->blueprint.entities().atRight(otherPath); + if (!scene->blueprint.relations().contains(relationType)) + { + return {"", "", sceneAsset}; + } + auto relations = scene->blueprint.relations().at(relationType); + if (!relations.contains(entity)) + { + return {"", "", sceneAsset}; + } + if (!relations[entity].contains(other)) + { + return {"", "", sceneAsset}; + } + return {entityPath, otherPath, sceneAsset}; + } + if (otherPath.find('.') == std::string::npos) + { + return {"", "", sceneAsset}; + } + std::string subScenePath = entityPath.substr(0, entityPath.find('.')); + auto newPath = entityPath.substr(entityPath.find('.') + 1); + auto newOtherPath = otherPath.substr(otherPath.find('.') + 1); + return originalRelationData(assets, scene->imports.at(subScenePath), newPath, newOtherPath, relationType); +} + +bool SceneBridge::saveToFile(const Assets& assets, const AnyAsset& handle, Stream& stream) +{ + auto scene = assets.read(handle); + JSONSerializer ser{}; + auto json = nlohmann::json::object(); + + auto importJson = nlohmann::json::object(); + for (const auto& [name, subHandle] : scene->imports) + { + importJson.emplace(name.c_str(), uuids::to_string(subHandle.getId())); + } + json.push_back({"imports", importJson}); + + auto entitiesJson = nlohmann::json::object(); + for (const auto& [entity, name] : scene->blueprint.entities()) + { + if (name.find('.') == std::string::npos) + { + auto entityJson = nlohmann::json::object(); + for (auto& [type, components] : scene->blueprint.components()) + { + if (!components.contains(entity)) + { + continue; + } + ser.write(components[entity].type(), components[entity].get()); + entityJson.emplace(type->name().c_str(), ser.output()); + } + for (auto& [type, relations] : scene->blueprint.relations()) + { + if (!relations.contains(entity)) + { + continue; + } + for (auto& [other, relation] : relations[entity]) + { + ser.write(relation.type(), relation.get()); + entityJson.emplace((type->name() + "@" + scene->blueprint.entities().atLeft(other)).c_str(), + ser.output()); + } + } + + entitiesJson.emplace(name.c_str(), entityJson); + } + else + { + bool dirty = false; + auto entityJson = nlohmann::json::object(); + for (auto& [type, components] : scene->blueprint.components()) + { + if (!components.contains(entity)) + { + continue; + } + auto [entityName, subHandle] = originalComponentData(assets, handle, name, *type); + if (!entityName.empty()) + { + auto subScene = assets.read(subHandle); + if (cubos::core::reflection::compare(*type, components[entity].get(), + subScene->blueprint.components() + .at(*type) + .at(subScene->blueprint.entities().atRight(entityName)) + .get())) + { + continue; + } + } + dirty = true; + ser.write(components[entity].type(), components[entity].get()); + entityJson.emplace(type->name().c_str(), ser.output()); + } + for (auto& [type, relations] : scene->blueprint.relations()) + { + if (!relations.contains(entity)) + { + continue; + } + for (auto& [other, relation] : relations[entity]) + { + auto [entityName, otherName, subHandle] = + originalRelationData(assets, handle, name, scene->blueprint.entities().atLeft(other), *type); + if (!entityName.empty()) + { + if (auto subScene = assets.read(subHandle); + cubos::core::reflection::compare(*type, relation.get(), + subScene->blueprint.relations() + .at(*type) + .at(subScene->blueprint.entities().atRight(entityName)) + .at(subScene->blueprint.entities().atRight(otherName)) + .get())) + { + continue; + } + } + dirty = true; + ser.write(relation.type(), relation.get()); + entityJson.emplace((type->name() + "@" + scene->blueprint.entities().atLeft(other)).c_str(), + ser.output()); + } + } + if (dirty) + { + entitiesJson.emplace(name.c_str(), entityJson); + } + } + } + json.push_back({"entities", entitiesJson}); + + stream.print(json.dump(2)); + return true; +} diff --git a/engine/src/cubos/engine/scene/plugin.cpp b/engine/src/scene/plugin.cpp similarity index 100% rename from engine/src/cubos/engine/scene/plugin.cpp rename to engine/src/scene/plugin.cpp diff --git a/engine/src/cubos/engine/scene/scene.cpp b/engine/src/scene/scene.cpp similarity index 100% rename from engine/src/cubos/engine/scene/scene.cpp rename to engine/src/scene/scene.cpp diff --git a/engine/src/cubos/engine/screen_picker/plugin.cpp b/engine/src/screen_picker/plugin.cpp similarity index 100% rename from engine/src/cubos/engine/screen_picker/plugin.cpp rename to engine/src/screen_picker/plugin.cpp diff --git a/engine/src/cubos/engine/screen_picker/screen_picker.cpp b/engine/src/screen_picker/screen_picker.cpp similarity index 95% rename from engine/src/cubos/engine/screen_picker/screen_picker.cpp rename to engine/src/screen_picker/screen_picker.cpp index 4d58b4c117..9cc063f863 100644 --- a/engine/src/cubos/engine/screen_picker/screen_picker.cpp +++ b/engine/src/screen_picker/screen_picker.cpp @@ -38,6 +38,11 @@ Framebuffer ScreenPicker::framebuffer() uint32_t ScreenPicker::at(int x, int y) const { y = mTextureSize.y - y - 1; + if (x >= mTextureSize.x || x < 0 || y >= mTextureSize.y || y < 0) + { + return UINT32_MAX; + } + auto* texBuffer = new uint16_t[(std::size_t)mTextureSize.x * (std::size_t)mTextureSize.y * 2U]; mIdTexture->read(texBuffer); diff --git a/engine/src/cubos/engine/settings/plugin.cpp b/engine/src/settings/plugin.cpp similarity index 100% rename from engine/src/cubos/engine/settings/plugin.cpp rename to engine/src/settings/plugin.cpp diff --git a/engine/src/cubos/engine/settings/settings.cpp b/engine/src/settings/settings.cpp similarity index 100% rename from engine/src/cubos/engine/settings/settings.cpp rename to engine/src/settings/settings.cpp diff --git a/engine/src/cubos/engine/splitscreen/plugin.cpp b/engine/src/splitscreen/plugin.cpp similarity index 100% rename from engine/src/cubos/engine/splitscreen/plugin.cpp rename to engine/src/splitscreen/plugin.cpp diff --git a/engine/src/transform/child_of.cpp b/engine/src/transform/child_of.cpp new file mode 100644 index 0000000000..908d413100 --- /dev/null +++ b/engine/src/transform/child_of.cpp @@ -0,0 +1,8 @@ +#include + +#include + +CUBOS_REFLECT_IMPL(cubos::engine::ChildOf) +{ + return core::ecs::TypeBuilder("cubos::engine::ChildOf").tree().build(); +} diff --git a/engine/src/transform/local_to_parent.cpp b/engine/src/transform/local_to_parent.cpp new file mode 100644 index 0000000000..89a025d23d --- /dev/null +++ b/engine/src/transform/local_to_parent.cpp @@ -0,0 +1,11 @@ +#include +#include + +#include + +CUBOS_REFLECT_IMPL(cubos::engine::LocalToParent) +{ + return core::ecs::TypeBuilder("cubos::engine::LocalToParent") + .withField("mat", &LocalToParent::mat) + .build(); +} diff --git a/engine/src/cubos/engine/transform/local_to_world.cpp b/engine/src/transform/local_to_world.cpp similarity index 100% rename from engine/src/cubos/engine/transform/local_to_world.cpp rename to engine/src/transform/local_to_world.cpp diff --git a/engine/src/transform/plugin.cpp b/engine/src/transform/plugin.cpp new file mode 100644 index 0000000000..4d385e4a85 --- /dev/null +++ b/engine/src/transform/plugin.cpp @@ -0,0 +1,122 @@ +#include + +using cubos::core::ecs::Traversal; + +void cubos::engine::transformPlugin(Cubos& cubos) +{ + cubos.addComponent(); + cubos.addComponent(); + cubos.addComponent(); + cubos.addComponent(); + cubos.addComponent(); + cubos.addRelation(); + + cubos.system("add LocalToWorld to entities with Position") + .tagged("cubos.transform.missing.local_to_world") + .without() + .with() + .call([](Commands cmds, Query query) { + for (auto [e] : query) + { + cmds.add(e, LocalToWorld{}); + } + }); + + cubos.system("add LocalToWorld to entities with Rotation") + .tagged("cubos.transform.missing.local_to_world") + .without() + .with() + .call([](Commands cmds, Query query) { + for (auto [e] : query) + { + cmds.add(e, LocalToWorld{}); + } + }); + + cubos.system("add LocalToWorld to entities with Scale") + .tagged("cubos.transform.missing.local_to_world") + .without() + .with() + .call([](Commands cmds, Query query) { + for (auto [e] : query) + { + cmds.add(e, LocalToWorld{}); + } + }); + + cubos.tag("cubos.transform.missing.local_to_world").before("cubos.transform.missing"); + + cubos.system("add Position to entities with LocalToWorld") + .tagged("cubos.transform.missing") + .without() + .with() + .call([](Commands cmds, Query query) { + for (auto [e] : query) + { + cmds.add(e, Position{}); + } + }); + + cubos.system("add Rotation to entities with LocalToWorld") + .tagged("cubos.transform.missing") + .without() + .with() + .call([](Commands cmds, Query query) { + for (auto [e] : query) + { + cmds.add(e, Rotation{}); + } + }); + + cubos.system("add Scale to entities with LocalToWorld") + .tagged("cubos.transform.missing") + .without() + .with() + .call([](Commands cmds, Query query) { + for (auto [e] : query) + { + cmds.add(e, Scale{}); + } + }); + + cubos.system("add LocalToParent to entities with LocalToWord and ChildOf other entity with LocalToWorld") + .tagged("cubos.transform.missing") + .entity() + .without() + .with() + .related() + .with() + .call([](Commands cmds, Query query) { + for (auto [e] : query) + { + cmds.add(e, LocalToParent{}); + } + }); + + cubos.tag("cubos.transform.missing").before("cubos.transform.update.relative"); + + cubos.system("update relative transform matrix") + .tagged("cubos.transform.update.relative") + .before("cubos.transform.update") + .call([](Query, const Position&, const Rotation&, const Scale&> query) { + for (auto [localToWorld, localToParent, position, rotation, scale] : query) + { + auto& mat = localToParent ? localToParent->mat : localToWorld.mat; + mat = glm::scale(glm::translate(glm::mat4(1.0F), position.vec) * glm::toMat4(rotation.quat), + glm::vec3(scale.factor)); + } + }); + + cubos.system("update LocalToWorlds of children") + .tagged("cubos.transform.update") + .with() + .with() + .related(Traversal::Down) + .with() + .call([](Query query) { + for (auto [localToWorld, localToParent, parentLocalToWorld] : query) + { + localToWorld.mat = parentLocalToWorld.mat * localToParent.mat; + } + }); +} diff --git a/engine/src/cubos/engine/transform/position.cpp b/engine/src/transform/position.cpp similarity index 100% rename from engine/src/cubos/engine/transform/position.cpp rename to engine/src/transform/position.cpp diff --git a/engine/src/cubos/engine/transform/rotation.cpp b/engine/src/transform/rotation.cpp similarity index 100% rename from engine/src/cubos/engine/transform/rotation.cpp rename to engine/src/transform/rotation.cpp diff --git a/engine/src/cubos/engine/transform/scale.cpp b/engine/src/transform/scale.cpp similarity index 100% rename from engine/src/cubos/engine/transform/scale.cpp rename to engine/src/transform/scale.cpp diff --git a/engine/src/cubos/engine/utils/free_camera_controller/controller.cpp b/engine/src/utils/free_camera_controller/controller.cpp similarity index 100% rename from engine/src/cubos/engine/utils/free_camera_controller/controller.cpp rename to engine/src/utils/free_camera_controller/controller.cpp diff --git a/engine/src/cubos/engine/utils/free_camera_controller/plugin.cpp b/engine/src/utils/free_camera_controller/plugin.cpp similarity index 100% rename from engine/src/cubos/engine/utils/free_camera_controller/plugin.cpp rename to engine/src/utils/free_camera_controller/plugin.cpp diff --git a/engine/src/cubos/engine/voxels/grid.cpp b/engine/src/voxels/grid.cpp similarity index 100% rename from engine/src/cubos/engine/voxels/grid.cpp rename to engine/src/voxels/grid.cpp diff --git a/engine/src/cubos/engine/voxels/material.cpp b/engine/src/voxels/material.cpp similarity index 100% rename from engine/src/cubos/engine/voxels/material.cpp rename to engine/src/voxels/material.cpp diff --git a/engine/src/cubos/engine/voxels/palette.cpp b/engine/src/voxels/palette.cpp similarity index 100% rename from engine/src/cubos/engine/voxels/palette.cpp rename to engine/src/voxels/palette.cpp diff --git a/engine/src/cubos/engine/voxels/plugin.cpp b/engine/src/voxels/plugin.cpp similarity index 100% rename from engine/src/cubos/engine/voxels/plugin.cpp rename to engine/src/voxels/plugin.cpp diff --git a/engine/src/cubos/engine/window/plugin.cpp b/engine/src/window/plugin.cpp similarity index 100% rename from engine/src/cubos/engine/window/plugin.cpp rename to engine/src/window/plugin.cpp diff --git a/engine/tests/CMakeLists.txt b/engine/tests/CMakeLists.txt index 18426eda3b..7b0edafc9f 100644 --- a/engine/tests/CMakeLists.txt +++ b/engine/tests/CMakeLists.txt @@ -4,6 +4,7 @@ add_executable( cubos-engine-tests main.cpp + transform.cpp ) target_link_libraries(cubos-engine-tests cubos-engine doctest::doctest) diff --git a/engine/tests/transform.cpp b/engine/tests/transform.cpp new file mode 100644 index 0000000000..ee3522c149 --- /dev/null +++ b/engine/tests/transform.cpp @@ -0,0 +1,166 @@ +#include + +#include + +using namespace cubos::engine; + +TEST_CASE("cubos::engine::transformPlugin") +{ + Cubos cubos{}; + cubos.addPlugin(transformPlugin); + + SUBCASE("main components are added automatically") + { + SUBCASE("from Position") + { + cubos.startupSystem("create entity w/Position").call([](Commands cmds) { cmds.create().add(Position{}); }); + } + + SUBCASE("from Rotation") + { + cubos.startupSystem("create entity w/Rotation").call([](Commands cmds) { cmds.create().add(Rotation{}); }); + } + + SUBCASE("from Scale") + { + cubos.startupSystem("create entity w/Scale").call([](Commands cmds) { cmds.create().add(Scale{}); }); + } + + SUBCASE("from LocalToWorld") + { + cubos.startupSystem("create entity w/LocalToWorld").call([](Commands cmds) { + cmds.create().add(LocalToWorld{}); + }); + } + + cubos.system("check if there's a single entity with all of the components") + .after("cubos.transform.update") + .with() + .with() + .with() + .with() + .call([](Query<> query) { CHECK(query.first().contains()); }); + + cubos.run(); + } + + SUBCASE("LocalToParent is added automatically") + { + cubos.startupSystem("create entity w/LocalToWorld, child of another entity w/LocalToWorld") + .call([](Commands cmds) { + auto child = cmds.create().add(LocalToWorld{}).entity(); + auto parent = cmds.create().add(LocalToWorld{}).entity(); + cmds.relate(child, parent, ChildOf{}); + }); + + cubos.system("check if there's a single entity pair with all of the components") + .after("cubos.transform.update") + .with() + .with() + .with() + .with() + .with() + .related() + .with() + .with() + .with() + .with() + .call([](Query<> query) { CHECK(query.first().contains()); }); + + cubos.run(); + } + + SUBCASE("LocalToWorld is calculated correctly for root entities") + { + cubos.startupSystem("create entity with Position, Rotation and Scale").call([](Commands cmds) { + cmds.create() + .add(Position{{1.0F, 0.0F, 0.0F}}) + .add(Rotation{glm::angleAxis(glm::pi() / 2, glm::vec3{0.0F, 1.0F, 0.0F})}) + .add(Scale{2.0F}); + }); + + cubos.system("check if there's a single entity pair with all of the components") + .after("cubos.transform.update") + .call([](Query query) { + REQUIRE(query.first().contains()); + auto [localToWorld] = *query.first(); + + auto point = localToWorld.mat * glm::vec4(0.0F, 0.0F, 0.0F, 1.0F); + CHECK(point.x == doctest::Approx(1.0F)); + CHECK(point.y == doctest::Approx(0.0F)); + CHECK(point.z == doctest::Approx(0.0F)); + CHECK(point.w == doctest::Approx(1.0F)); + + point = localToWorld.mat * glm::vec4(1.0F, 0.0F, 0.0F, 1.0F); + CHECK(point.x == doctest::Approx(1.0F)); + CHECK(point.y == doctest::Approx(0.0F)); + CHECK(point.z == doctest::Approx(-2.0F)); + CHECK(point.w == doctest::Approx(1.0F)); + }); + + cubos.run(); + } + + SUBCASE("LocalToWorld/LocalToParent is calculated correctly for child entities") + { + cubos.startupSystem("create parent and child entities with Position, Rotation and Scale") + .call([](Commands cmds) { + auto child = cmds.create().add(Position{{1.0F, 0.0F, 0.0F}}).entity(); + auto parent = cmds.create().add(Position{{3.0F, 0.0F, 0.0F}}).entity(); + auto grandparent = cmds.create().add(Position{{5.0F, 0.0F, 0.0F}}).entity(); + + cmds.relate(child, parent, ChildOf{}); + cmds.relate(parent, grandparent, ChildOf{}); + }); + + cubos.system("check if both entity pairs are correct") + .after("cubos.transform.update") + .call([](Query, const LocalToWorld&> query) { + for (auto [position, localToParent, localToWorld] : query) + { + if (position.vec.x == doctest::Approx(1.0F)) + { + auto point = localToWorld.mat * glm::vec4(0.0F, 0.0F, 0.0F, 1.0F); + CHECK(point.x == doctest::Approx(9.0F)); + CHECK(point.y == doctest::Approx(0.0F)); + CHECK(point.z == doctest::Approx(0.0F)); + CHECK(point.w == doctest::Approx(1.0F)); + + REQUIRE(localToParent); + point = localToParent->mat * glm::vec4(0.0F, 0.0F, 0.0F, 1.0F); + CHECK(point.x == doctest::Approx(1.0F)); + CHECK(point.y == doctest::Approx(0.0F)); + CHECK(point.z == doctest::Approx(0.0F)); + CHECK(point.w == doctest::Approx(1.0F)); + } + else if (position.vec.x == doctest::Approx(3.0F)) + { + auto point = localToWorld.mat * glm::vec4(0.0F, 0.0F, 0.0F, 1.0F); + CHECK(point.x == doctest::Approx(8.0F)); + CHECK(point.y == doctest::Approx(0.0F)); + CHECK(point.z == doctest::Approx(0.0F)); + CHECK(point.w == doctest::Approx(1.0F)); + + REQUIRE(localToParent); + point = localToParent->mat * glm::vec4(0.0F, 0.0F, 0.0F, 1.0F); + CHECK(point.x == doctest::Approx(3.0F)); + CHECK(point.y == doctest::Approx(0.0F)); + CHECK(point.z == doctest::Approx(0.0F)); + CHECK(point.w == doctest::Approx(1.0F)); + } + else if (position.vec.x == doctest::Approx(5.0F)) + { + auto point = localToWorld.mat * glm::vec4(0.0F, 0.0F, 0.0F, 1.0F); + CHECK(point.x == doctest::Approx(5.0F)); + CHECK(point.y == doctest::Approx(0.0F)); + CHECK(point.z == doctest::Approx(0.0F)); + CHECK(point.w == doctest::Approx(1.0F)); + + CHECK_FALSE(localToParent); + } + } + }); + + cubos.run(); + } +} diff --git a/tools/tesseratos/src/tesseratos/debug_camera/plugin.cpp b/tools/tesseratos/src/tesseratos/debug_camera/plugin.cpp index f0101ddd0e..acb879bcac 100644 --- a/tools/tesseratos/src/tesseratos/debug_camera/plugin.cpp +++ b/tools/tesseratos/src/tesseratos/debug_camera/plugin.cpp @@ -5,6 +5,7 @@ #include #include #include +#include #include #include @@ -30,11 +31,13 @@ void tesseratos::debugCameraPlugin(Cubos& cubos) { cubos.addPlugin(cubos::engine::imguiPlugin); cubos.addPlugin(toolboxPlugin); + cubos.addPlugin(cubos::engine::freeCameraControllerPlugin); cubos.addResource(); cubos.startupSystem("create Debug Camera").call([](Commands commands, DebugCameraInfo& debugCamera) { - debugCamera.ent = commands.create().add(Camera{}).add(Position{{}}).entity(); + debugCamera.ent = + commands.create().add(Camera{}).add(Position{{}}).add(cubos::engine::FreeCameraController{}).entity(); }); cubos.system("show Debug Camera UI") diff --git a/tools/tesseratos/src/tesseratos/entity_selector/plugin.cpp b/tools/tesseratos/src/tesseratos/entity_selector/plugin.cpp index 03f15d639e..bb6f272b53 100644 --- a/tools/tesseratos/src/tesseratos/entity_selector/plugin.cpp +++ b/tools/tesseratos/src/tesseratos/entity_selector/plugin.cpp @@ -57,7 +57,7 @@ void tesseratos::entitySelectorPlugin(Cubos& cubos) { if (std::get(event).button == cubos::core::io::MouseButton::Left) { - if (!std::get(event).pressed) + if (std::get(event).pressed) { uint32_t entityId = screenPicker.at(entitySelector.lastMousePosition.x, entitySelector.lastMousePosition.y); @@ -66,7 +66,7 @@ void tesseratos::entitySelectorPlugin(Cubos& cubos) { entitySelector.selection = Entity{}; } - else + else if (entityId < static_cast(1 << 31)) { entitySelector.selection = Entity{entityId, world.generation(entityId)}; } diff --git a/tools/tesseratos/src/tesseratos/scene_editor/plugin.cpp b/tools/tesseratos/src/tesseratos/scene_editor/plugin.cpp index 88b4ec6c4b..b672c39a37 100644 --- a/tools/tesseratos/src/tesseratos/scene_editor/plugin.cpp +++ b/tools/tesseratos/src/tesseratos/scene_editor/plugin.cpp @@ -85,7 +85,7 @@ static void openScene(const Asset& sceneToSpawn, Commands& commands, cons { closeScene(commands, scene); auto sceneRead = assets.read(sceneToSpawn); - auto builder = commands.spawn(sceneRead->blueprint); + auto builder = commands.spawn(sceneRead->blueprint, true); for (const auto& [entity, name] : sceneRead->blueprint.bimap()) { placeEntity(name, builder.entity(name), scene);