diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs index c18157eb..381ed0d4 100644 --- a/.git-blame-ignore-revs +++ b/.git-blame-ignore-revs @@ -9,3 +9,6 @@ # Rebrand preambles to Redot d3bd3484fc9baad20a7cc4c9371a5f4dd70744cd + +# Style: Replace header guards with `#pragma once` +7056c996dd43ae1aa466c94d95cc2fe63853d8a9 diff --git a/.github/actions/setup-godot-cpp/action.yml b/.github/actions/setup-godot-cpp/action.yml index 287fb238..1be9293c 100644 --- a/.github/actions/setup-godot-cpp/action.yml +++ b/.github/actions/setup-godot-cpp/action.yml @@ -22,10 +22,14 @@ inputs: ndk-version: default: r23c description: Android NDK version. + buildtool: + default: scons + description: scons or cmake scons-version: default: 4.4.0 description: SCons version. + runs: using: composite steps: @@ -55,8 +59,13 @@ runs: version: ${{ inputs.mingw-version }} - name: Setup SCons + if: ${{ inputs.buildtool == 'scons' }} shell: bash run: | python -c "import sys; print(sys.version)" python -m pip install scons==${{ inputs.scons-version }} scons --version + + - name: Install Ninja + if: ${{ inputs.buildtool == 'cmake' }} + uses: ashutoshvarma/setup-ninja@master diff --git a/.github/workflows/ci-cmake.yml b/.github/workflows/ci-cmake.yml new file mode 100644 index 00000000..b39fba9e --- /dev/null +++ b/.github/workflows/ci-cmake.yml @@ -0,0 +1,195 @@ +name: Continuous integration +on: + workflow_call: + +env: + # Only used for the cache key. Increment version to force clean build. + GODOT_BASE_BRANCH: master + # Used to select the version of Godot to run the tests with. + REDOT_TEST_VERSION: master + # Use UTF-8 on Linux. + LANG: en_US.UTF-8 + LC_ALL: en_US.UTF-8 + +concurrency: + group: ci-cmake-${{ github.actor }}-${{ github.head_ref || github.run_number }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + build-cmake: + name: ${{ matrix.name }} + runs-on: ${{ matrix.os }} + env: + EM_VERSION: 3.1.39 + config-flags: + -DCMAKE_C_COMPILER_LAUNCHER=sccache + -DCMAKE_CXX_COMPILER_LAUNCHER=sccache + -DGODOTCPP_ENABLE_TESTING=ON + -DGODOTCPP_BUILD_PROFILE="test/build_profile.json" + SCCACHE_GHA_ENABLED: "true" + + strategy: + fail-fast: false + matrix: + include: + - name: 🐧 Linux (GCC, Makefiles) + os: ubuntu-22.04 + platform: linux + config-flags: -DCMAKE_BUILD_TYPE=Release + artifact-name: godot-cpp-linux-glibc2.27-x86_64-release.cmake + artifact-path: cmake-build/bin/libgodot-cpp.linux.template_release.x86_64.a + run-tests: true + + - name: 🐧 Linux (GCC, Makefiles, Double Precision) + os: ubuntu-22.04 + platform: linux + config-flags: -DCMAKE_BUILD_TYPE=Release -DGODOTCPP_PRECISION=double + artifact-name: godot-cpp-linux-glibc2.27-x86_64-double-release.cmake + artifact-path: cmake-build/bin/libgodot-cpp.linux.template_release.double.x86_64.a + flags: precision=double + run-tests: false + + - name: 🏁 Windows (x86_64, MSVC) + os: windows-2019 + platform: windows + compiler: msvc + build-flags: --config Release + artifact-name: godot-cpp-windows-msvc2019-x86_64-release.cmake + artifact-path: cmake-build/bin/libgodot-cpp.windows.template_release.x86_64.lib + run-tests: false + + - name: 🏁 Windows (x86_64, MinGW, Ninja) + os: windows-2019 + platform: windows + compiler: mingw + config-flags: + -GNinja -DCMAKE_BUILD_TYPE=Release + -DCMAKE_CXX_COMPILER=cc -DCMAKE_CXX_COMPILER=c++ + artifact-name: godot-cpp-linux-mingw-x86_64-release.cmake + artifact-path: cmake-build/bin/libgodot-cpp.windows.template_release.x86_64.a + run-tests: false + + - name: 🍎 macOS (universal, Makefiles) + os: macos-latest + platform: macos + config-flags: -DCMAKE_OSX_ARCHITECTURES="arm64;x86_64" + artifact-name: godot-cpp-macos-universal-release.cmake + artifact-path: cmake-build/bin/libgodot-cpp.macos.template_release.universal.a + run-tests: false + + - name: πŸ€– Android (arm64, Ninja) + os: ubuntu-22.04 + platform: android + config-flags: + -G Ninja -DCMAKE_BUILD_TYPE=Release + --toolchain ${ANDROID_HOME}/ndk/23.2.8568313/build/cmake/android.toolchain.cmake + -DANDROID_PLATFORM=21 -DANDROID_ABI=arm64-v8a + artifact-name: godot-cpp-android-arm64-release.cmake + artifact-path: cmake-build/bin/libgodot-cpp.android.template_release.arm64.a + flags: arch=arm64 + run-tests: false + + - name: 🍏 iOS (arm64, XCode) + os: macos-latest + platform: ios + config-flags: + -G Xcode + --toolchain cmake/ios.toolchain.cmake + -DPLATFORM=OS64 + build-flags: --config Release + artifact-name: godot-cpp-ios-arm64-release.cmake + artifact-path: cmake-build/bin/libgodot-cpp.ios.template_release.arm64.a + flags: arch=arm64 + run-tests: false + + - name: 🌐 Web (wasm32, Ninja) + os: ubuntu-22.04 + platform: web + config-flags: + -G Ninja -DCMAKE_BUILD_TYPE=Release + --toolchain ${EMSDK}/upstream/emscripten/cmake/Modules/Platform/Emscripten.cmake + artifact-name: godot-cpp-web-wasm32-release.cmake + artifact-path: cmake-build/bin/libgodot-cpp.web.template_release.wasm32.a + run-tests: false + + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + submodules: recursive + + - name: Run sccache-cache + uses: mozilla-actions/sccache-action@v0.0.9 + + - name: Setup godot-cpp + uses: ./.github/actions/setup-godot-cpp + with: + platform: ${{ matrix.platform }} + windows-compiler: ${{ matrix.compiler }} + buildtool: cmake + + - name: Configure godot-cpp-test with template_debug + run: > + cmake --log-level=VERBOSE -S . -B cmake-build ${{ env.config-flags }} ${{ matrix.config-flags }} + + - name: Build godot-cpp-test (template_debug) + run: > + cmake --build cmake-build --verbose --target godot-cpp-test ${{ matrix.build-flags }} + + - name: Configure godot-cpp-test with template_release + run: > + cmake --fresh --log-level=VERBOSE -S . -B cmake-build + -DGODOTCPP_TARGET=template_release ${{ env.config-flags }} ${{ matrix.config-flags }} + + - name: Build godot-cpp-test (template_release) + run: > + cmake --build cmake-build --verbose --target godot-cpp-test ${{ matrix.build-flags }} + + - name: Run sccache stat for check + shell: bash + run: ${SCCACHE_PATH} --show-stats + + - name: Download latest Redot artifacts + uses: dsnopek/action-download-artifact@1322f74e2dac9feed2ee76a32d9ae1ca3b4cf4e9 + if: matrix.run-tests && env.REDOT_TEST_VERSION == 'master' + with: + repo: Redot-Engine/redot-engine + branch: master + event: push + workflow: linux_builds.yml + workflow_conclusion: success + name: linux-editor-mono + search_artifacts: true + check_artifacts: true + ensure_latest: true + path: redot-artifacts + + - name: Prepare Redot artifacts for testing + if: matrix.run-tests && env.REDOT_TEST_VERSION == 'master' + run: | + chmod +x ./redot-artifacts/redot.linuxbsd.editor.x86_64.mono + echo "REDOT=$(pwd)/redot-artifacts/redot.linuxbsd.editor.x86_64.mono" >> $GITHUB_ENV + + - name: Download requested Redot version for testing + if: matrix.run-tests && env.REDOT_TEST_VERSION != 'master' + run: | + wget "https://github.com/Redot-Engine/redot-engine/releases/download/redot-${REDOT_TEST_VERSION}/Redot_v${REDOT_TEST_VERSION}_linux.x86_64.zip" -O Redot.zip + unzip -a Redot.zip + chmod +x "Redot_v${REDOT_TEST_VERSION}_linux.x86_64" + echo "REDOT=$(pwd)/Redot_v${REDOT_TEST_VERSION}_linux.x86_64" >> $GITHUB_ENV + + - name: Run tests + if: matrix.run-tests + run: | + $REDOT --headless --version + cd test + # Need to run the editor so .godot is generated... but it crashes! Ignore that :-) + (cd project && (timeout 30 $REDOT --import --headless >/dev/null 2>&1 || true)) + ./run-tests.sh + + - name: Upload artifact + uses: actions/upload-artifact@v4 + with: + name: ${{ matrix.artifact-name }} + path: ${{ matrix.artifact-path }} + if-no-files-found: error diff --git a/.github/workflows/ci.yml b/.github/workflows/ci-scons.yml similarity index 84% rename from .github/workflows/ci.yml rename to .github/workflows/ci-scons.yml index cd8632b0..d151aec1 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci-scons.yml @@ -12,11 +12,11 @@ env: LC_ALL: en_US.UTF-8 concurrency: - group: ci-${{ github.actor }}-${{ github.head_ref || github.run_number }}-${{ github.ref }} + group: ci-scons-${{ github.actor }}-${{ github.head_ref || github.run_number }}-${{ github.ref }} cancel-in-progress: true jobs: - build: + build-scons: name: ${{ matrix.name }} runs-on: ${{ matrix.os }} strategy: @@ -113,6 +113,7 @@ jobs: with: platform: ${{ matrix.platform }} windows-compiler: ${{ contains(matrix.flags, 'use_mingw=yes') && 'mingw' || 'msvc' }} + buildtool: scons - name: Generate redot-cpp sources only run: | @@ -183,40 +184,3 @@ jobs: name: ${{ matrix.artifact-name }} path: ${{ matrix.artifact-path }} if-no-files-found: error - - linux-cmake-ninja: - name: 🐧 Build (Linux, GCC, CMake Ninja) - runs-on: ubuntu-22.04 - steps: - - name: Checkout - uses: actions/checkout@v4 - with: - submodules: recursive - - - name: Install dependencies - run: | - sudo apt-get update -qq - sudo apt-get install -qqq build-essential pkg-config cmake ninja-build - - - name: Build test GDExtension library - run: | - mkdir cmake-build - cd cmake-build - cmake ../ -DGODOTCPP_ENABLE_TESTING=YES - cmake --build . --verbose -j $(nproc) -t godot-cpp.test.template_release --config Release - - windows-msvc-cmake: - name: 🏁 Build (Windows, MSVC, CMake) - runs-on: windows-2019 - steps: - - name: Checkout - uses: actions/checkout@v4 - with: - submodules: recursive - - - name: Build test GDExtension library - run: | - mkdir cmake-build - cd cmake-build - cmake ../ -DGODOTCPP_ENABLE_TESTING=YES - cmake --build . --verbose -t godot-cpp.test.template_release --config Release diff --git a/.github/workflows/runner.yml b/.github/workflows/runner.yml index a2e4f91b..d056236a 100644 --- a/.github/workflows/runner.yml +++ b/.github/workflows/runner.yml @@ -9,13 +9,57 @@ jobs: # First stage: Only static checks, fast and prevent expensive builds from running. static-checks: - if: '!vars.DISABLE_GODOT_CI' name: πŸ“Š Static Checks + if: '!vars.DISABLE_GODOT_CI' uses: ./.github/workflows/static_checks.yml - # Second stage: Run all the builds and some of the tests. - - ci: - name: πŸ› οΈ Continuous Integration + # Second stage: Review code changes + changes: + name: Analyze Changes needs: static-checks - uses: ./.github/workflows/ci.yml + runs-on: ubuntu-latest + outputs: + sources: ${{ steps.filter.outputs.sources_any_changed }} + scons: ${{ steps.filter.outputs.scons_any_changed }} + cmake: ${{ steps.filter.outputs.cmake_any_changed }} + steps: + - uses: actions/checkout@v4 + with: + submodules: recursive + - uses: tj-actions/changed-files@v45 + id: filter + with: + files_yaml: | + sources: + - '.github/workflows/*.yml' + - '**/*.py' + - '**/*.cpp' + - '**/*.h' + - 'test/build_profile.json' + - 'gdextension/extension_api.json' + scons: + - '**/SConstruct' + - '**/SCsub' + - '**/*.py' + cmake: + - '**/CMakeLists.txt' + - '**/*.cmake' + - name: echo sources changed + run: | + echo sources ${{ steps.filter.outputs.sources_any_modified }} + echo scons ${{ steps.filter.outputs.scons_any_modified }} + echo cmake ${{ steps.filter.outputs.cmake_any_modified }} + + # Third stage: Run all the builds and some of the tests. + + ci-scons: + name: πŸ› οΈ SCons CI + needs: changes + if: ${{ needs.changes.outputs.scons == 'true' || needs.changes.outputs.sources == 'true' }} + uses: ./.github/workflows/ci-scons.yml + + ci-cmake: + name: πŸ› οΈ CMake CI + needs: changes + if: ${{ needs.changes.outputs.cmake == 'true' || needs.changes.outputs.sources == 'true' }} + uses: ./.github/workflows/ci-cmake.yml diff --git a/.github/workflows/static_checks.yml b/.github/workflows/static_checks.yml index a3d81322..868e8012 100644 --- a/.github/workflows/static_checks.yml +++ b/.github/workflows/static_checks.yml @@ -17,21 +17,13 @@ jobs: fetch-depth: 2 - name: Get changed files - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: | - if [ "${{ github.event_name }}" == "pull_request" ]; then - files=$(git diff-tree --no-commit-id --name-only -r HEAD^1..HEAD 2> /dev/null || true) - elif [ "${{ github.event_name }}" == "push" -a "${{ github.event.forced }}" == "false" -a "${{ github.event.created }}" == "false" ]; then - files=$(git diff-tree --no-commit-id --name-only -r ${{ github.event.before }}..${{ github.event.after }} 2> /dev/null || true) - fi - files=$(echo "$files" | grep -v 'thirdparty' | xargs -I {} sh -c 'echo "\"./{}\""' | tr '\n' ' ') - echo "CHANGED_FILES=$files" >> $GITHUB_ENV + id: changed-files + uses: tj-actions/changed-files@v45 - name: Style checks via pre-commit uses: pre-commit/action@v3.0.1 with: - extra_args: --verbose --hook-stage manual --files ${{ env.CHANGED_FILES }} + extra_args: --verbose --hook-stage manual --files ${{ steps.changed-files.outputs.all_changed_files }} - name: Check generated files consistency run: diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index e63f1d40..7354ba41 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -33,6 +33,12 @@ repos: - id: codespell additional_dependencies: [tomli] + - repo: https://github.com/BlankSpruce/gersemi + rev: 0.18.2 + hooks: + - id: gersemi + args: ["-i", "--no-warn-about-unknown-commands", "-l", "120"] + - repo: local hooks: - id: copyright-headers diff --git a/CMakeLists.txt b/CMakeLists.txt index 9e4b1f50..4c2be6d8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.17) +cmake_minimum_required(VERSION 3.10...3.17) #[=======================================================================[.rst: @@ -9,7 +9,9 @@ To enable use of the emscripten emsdk hack for pseudo shared library support without polluting options for consumers we need to use the CMAKE_PROJECT__INCLUDE which was introduced in version 3.17 -Scons Compatibility +For more information check cmake/emsdkHack.cmake + +SCons Compatibility ------------------- There is an understandable conflict between build systems as they define @@ -18,6 +20,9 @@ compromises need to be made to resolve those differences. As we are attempting to maintain feature parity, and ease of maintenance, these CMake scripts are built to resemble the SCons build system wherever possible. +Where they are not, we will attempt to document common difference in +doc/cmake.rst and platform specific differences in their respective +cmake/.cmake file. The file structure and file content are made to match, if not in content then in spirit. The closer the two build systems look the easier they will be to @@ -26,8 +31,7 @@ maintain. Where the SCons additional scripts in the tools directory, The CMake scripts are in the cmake directory. -For example, the tools/godotcpp.py is sourced into SCons, and the 'options' -function is run. +For example; the tools/godotcpp.py is matched by the cmake/godotcpp.cmake file .. highlight:: python @@ -36,27 +40,35 @@ function is run. The CMake equivalent is below. ]=======================================================================] - -include( cmake/godotcpp.cmake ) +include(cmake/godotcpp.cmake) godotcpp_options() +#[[ People are compiling godot by itself and expecting template_debug +Replace this with PROJECT_IS_TOP_LEVEL, _IS_TOP_LEVEL when minimum reaches 3.21 +]] +if(NOT PROJECT_NAME) + set(GODOTCPP_IS_TOP_LEVEL ON) +endif() + # Define our project. -project( godot-cpp - VERSION 4.4 - DESCRIPTION "C++ bindings for the Godot Engine's GDExtensions API." - HOMEPAGE_URL "https://github.com/godotengine/godot-cpp" - LANGUAGES CXX) +project( + godot-cpp + VERSION 4.4 + DESCRIPTION "C++ bindings for the Godot Engine's GDExtensions API." + HOMEPAGE_URL "https://github.com/godotengine/godot-cpp" + LANGUAGES CXX +) compiler_detection() godotcpp_generate() # Conditionally enable the godot-cpp.test. integration testing targets -if( GODOTCPP_ENABLE_TESTING ) - add_subdirectory( test ) +if(GODOTCPP_ENABLE_TESTING) + add_subdirectory(test) endif() -# If this is the top level CMakeLists.txt, Generators which honor the -# USE_FOLDERS flag will organize godot-cpp targets under the subfolder -# 'godot-cpp'. This is enable by default from CMake version 3.26 +#[[ If this is the top level CMakeLists.txt, Generators which honor the +USE_FOLDERS flag will organize godot-cpp targets under a subfolder named +'godot-cpp'. This is enable by default from CMake version 3.26 ]] set_property(GLOBAL PROPERTY USE_FOLDERS ON) diff --git a/binding_generator.py b/binding_generator.py index 518b296d..c41cb0f2 100644 --- a/binding_generator.py +++ b/binding_generator.py @@ -51,11 +51,7 @@ def generate_mod_version(argcount, const=False, returns=False): def generate_wrappers(target): max_versions = 12 - txt = """ -#ifndef GDEXTENSION_WRAPPERS_GEN_H -#define GDEXTENSION_WRAPPERS_GEN_H - -""" + txt = "#pragma once" for i in range(max_versions + 1): txt += "\n/* Module Wrapper " + str(i) + " Arguments */\n" @@ -64,8 +60,6 @@ def generate_wrappers(target): txt += generate_mod_version(i, True, False) txt += generate_mod_version(i, True, True) - txt += "\n#endif\n" - with open(target, "w", encoding="utf-8") as f: f.write(txt) @@ -187,8 +181,7 @@ def generate_virtuals(target): max_versions = 12 txt = """/* THIS FILE IS GENERATED DO NOT EDIT */ -#ifndef GDEXTENSION_GDVIRTUAL_GEN_H -#define GDEXTENSION_GDVIRTUAL_GEN_H +#pragma once """ @@ -203,8 +196,6 @@ def generate_virtuals(target): txt += generate_virtual_version(i, True, False, True) txt += generate_virtual_version(i, True, True, True) - txt += "#endif // GDEXTENSION_GDVIRTUAL_GEN_H\n" - with open(target, "w", encoding="utf-8") as f: f.write(txt) @@ -290,14 +281,19 @@ def generate_bindings(api_filepath, use_template_get_node, bits="64", precision= api = {} with open(api_filepath, encoding="utf-8") as api_file: api = json.load(api_file) - _generate_bindings(api, use_template_get_node, bits, precision, output_dir) + _generate_bindings(api, api_filepath, use_template_get_node, bits, precision, output_dir) + +def _generate_bindings(api, api_filepath, use_template_get_node, bits="64", precision="single", output_dir="."): + if "precision" in api["header"] and precision != api["header"]["precision"]: + raise Exception( + f"Cannot do a precision={precision} build using '{api_filepath}' which was generated by Godot built with precision={api['header']['precision']}" + ) -def _generate_bindings(api, use_template_get_node, bits="64", precision="single", output_dir="."): target_dir = Path(output_dir) / "gen" shutil.rmtree(target_dir, ignore_errors=True) - target_dir.mkdir(parents=True) + target_dir.mkdir(parents=True, exist_ok=True) real_t = "double" if precision == "double" else "float" print("Built-in type config: " + real_t + "_" + bits) @@ -359,11 +355,8 @@ def generate_builtin_bindings(api, output_dir, build_config): variant_size_source = [] add_header("variant_size.hpp", variant_size_source) - header_guard = "GODOT_CPP_VARIANT_SIZE_HPP" - variant_size_source.append(f"#ifndef {header_guard}") - variant_size_source.append(f"#define {header_guard}") + variant_size_source.append("#pragma once") variant_size_source.append(f'#define GODOT_CPP_VARIANT_SIZE {builtin_sizes["Variant"]}') - variant_size_source.append(f"#endif // ! {header_guard}") variant_size_file.write("\n".join(variant_size_source)) @@ -443,8 +436,7 @@ def generate_builtin_bindings(api, output_dir, build_config): builtin_header = [] add_header("builtin_types.hpp", builtin_header) - builtin_header.append("#ifndef GODOT_CPP_BUILTIN_TYPES_HPP") - builtin_header.append("#define GODOT_CPP_BUILTIN_TYPES_HPP") + builtin_header.append("#pragma once") builtin_header.append("") @@ -459,8 +451,6 @@ def generate_builtin_bindings(api, output_dir, build_config): builtin_header.append("") - builtin_header.append("#endif // ! GODOT_CPP_BUILTIN_TYPES_HPP") - builtin_header_file.write("\n".join(builtin_header)) # Create a header with bindings for builtin types. @@ -469,8 +459,7 @@ def generate_builtin_bindings(api, output_dir, build_config): builtin_binds = [] add_header("builtin_binds.hpp", builtin_binds) - builtin_binds.append("#ifndef GODOT_CPP_BUILTIN_BINDS_HPP") - builtin_binds.append("#define GODOT_CPP_BUILTIN_BINDS_HPP") + builtin_binds.append("#pragma once") builtin_binds.append("") builtin_binds.append("#include ") builtin_binds.append("") @@ -482,7 +471,6 @@ def generate_builtin_bindings(api, output_dir, build_config): builtin_binds.append(f"VARIANT_ENUM_CAST({builtin_api['name']}::{enum_api['name']});") builtin_binds.append("") - builtin_binds.append("#endif // ! GODOT_CPP_BUILTIN_BINDS_HPP") builtin_binds_file.write("\n".join(builtin_binds)) @@ -498,9 +486,7 @@ def generate_builtin_class_vararg_method_implements_header(builtin_classes): add_header("builtin_vararg_methods.hpp", result) - header_guard = "GODOT_CPP_BUILTIN_VARARG_METHODS_HPP" - result.append(f"#ifndef {header_guard}") - result.append(f"#define {header_guard}") + result.append("#pragma once") result.append("") for builtin_api in builtin_classes: if "methods" not in builtin_api: @@ -515,8 +501,6 @@ def generate_builtin_class_vararg_method_implements_header(builtin_classes): ) result.append("") - result.append(f"#endif // ! {header_guard}") - return "\n".join(result) @@ -526,12 +510,9 @@ def generate_builtin_class_header(builtin_api, size, used_classes, fully_used_cl class_name = builtin_api["name"] snake_class_name = camel_to_snake(class_name).upper() - header_guard = f"GODOT_CPP_{snake_class_name}_HPP" - add_header(f"{snake_class_name.lower()}.hpp", result) - result.append(f"#ifndef {header_guard}") - result.append(f"#define {header_guard}") + result.append("#pragma once") result.append("") result.append("#include ") @@ -560,7 +541,7 @@ def generate_builtin_class_header(builtin_api, size, used_classes, fully_used_cl result.append("#include ") result.append("") - if is_packed_array(class_name): + if is_packed_array(class_name) or class_name == "Array": result.append("#include ") result.append("#include ") result.append("") @@ -661,6 +642,11 @@ def generate_builtin_class_header(builtin_api, size, used_classes, fully_used_cl result.append("") result.append(f"\t{class_name}(const Variant *p_variant);") + if class_name == "Array": + result.append("") + result.append("\tconst Variant *ptr() const;") + result.append("\tVariant *ptrw();") + result.append("") result.append("public:") @@ -926,6 +912,48 @@ def generate_builtin_class_header(builtin_api, size, used_classes, fully_used_cl result.append("\tVariant &operator[](int64_t p_index);") result.append("\tvoid set_typed(uint32_t p_type, const StringName &p_class_name, const Variant &p_script);") result.append("\tvoid _ref(const Array &p_from) const;") + result.append(""" + struct Iterator { + _FORCE_INLINE_ Variant &operator*() const; + _FORCE_INLINE_ Variant *operator->() const; + _FORCE_INLINE_ Iterator &operator++(); + _FORCE_INLINE_ Iterator &operator--(); + + _FORCE_INLINE_ bool operator==(const Iterator &b) const { return elem_ptr == b.elem_ptr; } + _FORCE_INLINE_ bool operator!=(const Iterator &b) const { return elem_ptr != b.elem_ptr; } + + Iterator(Variant *p_ptr) { elem_ptr = p_ptr; } + Iterator() {} + Iterator(const Iterator &p_it) { elem_ptr = p_it.elem_ptr; } + + private: + Variant *elem_ptr = nullptr; + }; + + struct ConstIterator { + _FORCE_INLINE_ const Variant &operator*() const; + _FORCE_INLINE_ const Variant *operator->() const; + _FORCE_INLINE_ ConstIterator &operator++(); + _FORCE_INLINE_ ConstIterator &operator--(); + + _FORCE_INLINE_ bool operator==(const ConstIterator &b) const { return elem_ptr == b.elem_ptr; } + _FORCE_INLINE_ bool operator!=(const ConstIterator &b) const { return elem_ptr != b.elem_ptr; } + + ConstIterator(const Variant *p_ptr) { elem_ptr = p_ptr; } + ConstIterator() {} + ConstIterator(const ConstIterator &p_it) { elem_ptr = p_it.elem_ptr; } + + private: + const Variant *elem_ptr = nullptr; + }; + + _FORCE_INLINE_ Iterator begin(); + _FORCE_INLINE_ Iterator end(); + + _FORCE_INLINE_ ConstIterator begin() const; + _FORCE_INLINE_ ConstIterator end() const; + """) + result.append("\t_FORCE_INLINE_ Array(std::initializer_list p_init);") if class_name == "Dictionary": result.append("\tconst Variant &operator[](const Variant &p_key) const;") @@ -960,8 +988,6 @@ def generate_builtin_class_header(builtin_api, size, used_classes, fully_used_cl result.append("") result.append("} // namespace godot") - result.append("") - result.append(f"#endif // ! {header_guard}") result.append("") return "\n".join(result) @@ -1365,7 +1391,7 @@ def generate_engine_classes_bindings(api, output_dir, use_template_get_node): fully_used_classes.add(dict_type_name) else: used_classes.add(dict_type_name) - dict_type_name = dict_type_names[2] + dict_type_name = dict_type_names[1] if dict_type_name.endswith("*"): dict_type_name = dict_type_name[:-1] if is_included(dict_type_name, class_name): @@ -1420,7 +1446,7 @@ def generate_engine_classes_bindings(api, output_dir, use_template_get_node): fully_used_classes.add(dict_type_name) else: used_classes.add(dict_type_name) - dict_type_name = dict_type_names[2] + dict_type_name = dict_type_names[1] if dict_type_name.endswith("*"): dict_type_name = dict_type_name[:-1] if is_included(dict_type_name, class_name): @@ -1493,9 +1519,7 @@ def generate_engine_classes_bindings(api, output_dir, use_template_get_node): result = [] add_header(f"{snake_struct_name}.hpp", result) - header_guard = f"GODOT_CPP_{snake_struct_name.upper()}_HPP" - result.append(f"#ifndef {header_guard}") - result.append(f"#define {header_guard}") + result.append("#pragma once") used_classes = [] expanded_format = native_struct["format"].replace("(", " ").replace(")", ";").replace(",", ";") @@ -1535,7 +1559,6 @@ def generate_engine_classes_bindings(api, output_dir, use_template_get_node): result.append("") result.append("} // namespace godot") result.append("") - result.append(f"#endif // ! {header_guard}") with header_filename.open("w+", encoding="utf-8") as header_file: header_file.write("\n".join(result)) @@ -1551,11 +1574,7 @@ def generate_engine_class_header(class_api, used_classes, fully_used_classes, us add_header(f"{snake_class_name.lower()}.hpp", result) - header_guard = f"GODOT_CPP_{snake_class_name}_HPP" - - result.append(f"#ifndef {header_guard}") - result.append(f"#define {header_guard}") - + result.append("#pragma once") result.append("") if len(fully_used_classes) > 0: @@ -1844,7 +1863,6 @@ def generate_engine_class_header(class_api, used_classes, fully_used_classes, us result.append("\t") result.append("") - result.append(f"#endif // ! {header_guard}") result.append("") return "\n".join(result) @@ -1937,7 +1955,7 @@ def generate_engine_class_source(class_api, used_classes, fully_used_classes, us if has_return: result.append( - f'\tCHECK_METHOD_BIND_RET(_gde_method_bind, {get_default_value_for_type(method["return_value"]["type"])});' + f'\tCHECK_METHOD_BIND_RET(_gde_method_bind, ({get_default_value_for_type(method["return_value"]["type"])}));' ) else: result.append("\tCHECK_METHOD_BIND(_gde_method_bind);") @@ -2046,9 +2064,7 @@ def generate_global_constants(api, output_dir): header_filename = include_gen_folder / "global_constants.hpp" - header_guard = "GODOT_CPP_GLOBAL_CONSTANTS_HPP" - header.append(f"#ifndef {header_guard}") - header.append(f"#define {header_guard}") + header.append("#pragma once") header.append("") header.append("#include ") header.append("") @@ -2078,7 +2094,6 @@ def generate_global_constants(api, output_dir): header.append("} // namespace godot") header.append("") - header.append(f"#endif // ! {header_guard}") with header_filename.open("w+", encoding="utf-8") as header_file: header_file.write("\n".join(header)) @@ -2094,9 +2109,7 @@ def generate_version_header(api, output_dir): header_file_path = include_gen_folder / header_filename - header_guard = "GODOT_CPP_VERSION_HPP" - header.append(f"#ifndef {header_guard}") - header.append(f"#define {header_guard}") + header.append("#pragma once") header.append("") header.append(f"#define GODOT_VERSION_MAJOR {api['header']['version_major']}") @@ -2106,8 +2119,6 @@ def generate_version_header(api, output_dir): header.append(f"#define GODOT_VERSION_STATUS_VERSION \"{api['header']['version_status_version']}\"") header.append(f"#define GODOT_VERSION_BUILD \"{api['header']['version_build']}\"") - header.append("") - header.append(f"#endif // {header_guard}") header.append("") with header_file_path.open("w+", encoding="utf-8") as header_file: @@ -2128,9 +2139,7 @@ def generate_global_constant_binds(api, output_dir): header_filename = include_gen_folder / "global_constants_binds.hpp" - header_guard = "GODOT_CPP_GLOBAL_CONSTANTS_BINDS_HPP" - header.append(f"#ifndef {header_guard}") - header.append(f"#define {header_guard}") + header.append("#pragma once") header.append("") header.append("#include ") header.append("") @@ -2149,8 +2158,6 @@ def generate_global_constant_binds(api, output_dir): header.append("") - header.append(f"#endif // ! {header_guard}") - with header_filename.open("w+", encoding="utf-8") as header_file: header_file.write("\n".join(header)) @@ -2169,9 +2176,7 @@ def generate_utility_functions(api, output_dir): header_filename = include_gen_folder / "utility_functions.hpp" - header_guard = "GODOT_CPP_UTILITY_FUNCTIONS_HPP" - header.append(f"#ifndef {header_guard}") - header.append(f"#define {header_guard}") + header.append("#pragma once") header.append("") header.append("#include ") header.append("#include ") @@ -2210,7 +2215,6 @@ def generate_utility_functions(api, output_dir): header.append("") header.append("} // namespace godot") header.append("") - header.append(f"#endif // ! {header_guard}") with header_filename.open("w+", encoding="utf-8") as header_file: header_file.write("\n".join(header)) @@ -2246,7 +2250,7 @@ def generate_utility_functions(api, output_dir): has_return = "return_type" in function and function["return_type"] != "void" if has_return: source.append( - f'\tCHECK_METHOD_BIND_RET(_gde_function, {get_default_value_for_type(function["return_type"])});' + f'\tCHECK_METHOD_BIND_RET(_gde_function, ({get_default_value_for_type(function["return_type"])}));' ) else: source.append("\tCHECK_METHOD_BIND(_gde_function);") @@ -2490,7 +2494,7 @@ def make_varargs_template( function_signature += " {" result.append(function_signature) - args_array = f"\tstd::array variant_args{{ " + args_array = f"\tstd::array variant_args{{{{ " for argument in method_arguments: if argument["type"] == "Variant": args_array += escape_argument(argument["name"]) @@ -2498,7 +2502,7 @@ def make_varargs_template( args_array += f'Variant({escape_argument(argument["name"])})' args_array += ", " - args_array += "Variant(p_args)... };" + args_array += "Variant(p_args)... }};" result.append(args_array) result.append(f"\tstd::array call_args;") result.append("\tfor (size_t i = 0; i < variant_args.size(); i++) {") diff --git a/cmake/GodotCPPModule.cmake b/cmake/GodotCPPModule.cmake index ce087468..00e00fe5 100644 --- a/cmake/GodotCPPModule.cmake +++ b/cmake/GodotCPPModule.cmake @@ -26,144 +26,151 @@ The build_profile.py has a __main__ and is used as a tool Its usage is listed as: $ python build_profile.py BUILD_PROFILE INPUT_JSON [OUTPUT_JSON] ]] -function( build_profile_generate_trimmed_api BUILD_PROFILE INPUT_JSON OUTPUT_JSON ) +function(build_profile_generate_trimmed_api BUILD_PROFILE INPUT_JSON OUTPUT_JSON) execute_process( - COMMAND "${Python3_EXECUTABLE}" - "${godot-cpp_SOURCE_DIR}/build_profile.py" - "${BUILD_PROFILE}" - "${INPUT_JSON}" - "${OUTPUT_JSON}" - WORKING_DIRECTORY ${godot-cpp_SOURCE_DIR} + COMMAND + "${Python3_EXECUTABLE}" "${godot-cpp_SOURCE_DIR}/build_profile.py" "${BUILD_PROFILE}" "${INPUT_JSON}" + "${OUTPUT_JSON}" + WORKING_DIRECTORY ${godot-cpp_SOURCE_DIR} ) -endfunction( ) - +endfunction() #[[ Generate File List Use the binding_generator.py Python script to determine the list of files that will be passed to the code generator using extension_api.json. NOTE: This happens for every configure.]] -function( binding_generator_get_file_list OUT_VAR_NAME API_FILEPATH OUTPUT_DIR ) - +function(binding_generator_get_file_list OUT_VAR_NAME API_FILEPATH OUTPUT_DIR) # This code snippet will be squashed into a single line # The two strings make this a list, in CMake lists are semicolon delimited strings. - set( PYTHON_SCRIPT -"from binding_generator import print_file_list" -"print_file_list( api_filepath='${API_FILEPATH}', + set(PYTHON_SCRIPT + "from binding_generator import print_file_list" + "print_file_list( api_filepath='${API_FILEPATH}', output_dir='${OUTPUT_DIR}', headers=True, - sources=True)") - message( DEBUG "Python:\n${PYTHON_SCRIPT}" ) + sources=True)" + ) + message(DEBUG "Python:\n${PYTHON_SCRIPT}") # Strip newlines and whitespace to make it a one-liner. - string( REGEX REPLACE "\n *" " " PYTHON_SCRIPT "${PYTHON_SCRIPT}" ) + string(REGEX REPLACE "\n *" " " PYTHON_SCRIPT "${PYTHON_SCRIPT}") - execute_process( COMMAND "${Python3_EXECUTABLE}" "-c" "${PYTHON_SCRIPT}" - WORKING_DIRECTORY "${godot-cpp_SOURCE_DIR}" - OUTPUT_VARIABLE GENERATED_FILES_LIST - OUTPUT_STRIP_TRAILING_WHITESPACE + execute_process( + COMMAND "${Python3_EXECUTABLE}" "-c" "${PYTHON_SCRIPT}" + WORKING_DIRECTORY "${godot-cpp_SOURCE_DIR}" + OUTPUT_VARIABLE GENERATED_FILES_LIST + OUTPUT_STRIP_TRAILING_WHITESPACE ) # Debug output - message( DEBUG "FileList-Begin" ) - foreach( PATH ${GENERATED_FILES_LIST} ) - message( DEBUG ${PATH} ) + message(DEBUG "FileList-Begin") + foreach(PATH ${GENERATED_FILES_LIST}) + message(DEBUG ${PATH}) endforeach() # Error out if the file list generator returned no files. - list( LENGTH GENERATED_FILES_LIST LIST_LENGTH ) - if( NOT LIST_LENGTH GREATER 0 ) - message( FATAL_ERROR "File List Generation Failed") + list(LENGTH GENERATED_FILES_LIST LIST_LENGTH) + if(NOT LIST_LENGTH GREATER 0) + message(FATAL_ERROR "File List Generation Failed") endif() - message( STATUS "There are ${LIST_LENGTH} Files to generate" ) - - set( ${OUT_VAR_NAME} ${GENERATED_FILES_LIST} PARENT_SCOPE ) -endfunction( ) + message(STATUS "There are ${LIST_LENGTH} Files to generate") + set(${OUT_VAR_NAME} ${GENERATED_FILES_LIST} PARENT_SCOPE) +endfunction() #[[ Generate Bindings Using the generated file list, use the binding_generator.py to generate the godot-cpp bindings. This will run at build time only if there are files missing. ]] -function( binding_generator_generate_bindings API_FILE USE_TEMPLATE_GET_NODE, BITS, PRECISION, OUTPUT_DIR ) +function( + binding_generator_generate_bindings + API_FILE + USE_TEMPLATE_GET_NODE, + BITS, + PRECISION, + OUTPUT_DIR +) # This code snippet will be squashed into a single line - set( PYTHON_SCRIPT -"from binding_generator import generate_bindings" -"generate_bindings( + set(PYTHON_SCRIPT + "from binding_generator import generate_bindings" + "generate_bindings( api_filepath='${API_FILE}', use_template_get_node='${USE_TEMPLATE_GET_NODE}', bits='${BITS}', precision='${PRECISION}', - output_dir='${OUTPUT_DIR}')") + output_dir='${OUTPUT_DIR}')" + ) - message( DEBUG "Python:\n${PYTHON_SCRIPT}" ) + message(DEBUG "Python:\n${PYTHON_SCRIPT}") # Strip newlines and whitespace to make it a one-liner. - string( REGEX REPLACE "\n *" " " PYTHON_SCRIPT "${PYTHON_SCRIPT}" ) - - add_custom_command(OUTPUT ${GENERATED_FILES_LIST} - COMMAND "${Python3_EXECUTABLE}" "-c" "${PYTHON_SCRIPT}" - VERBATIM - WORKING_DIRECTORY ${godot-cpp_SOURCE_DIR} - MAIN_DEPENDENCY ${GODOTCPP_GDEXTENSION_API_FILE} - DEPENDS ${godot-cpp_SOURCE_DIR}/binding_generator.py - COMMENT "Generating bindings" + string(REGEX REPLACE "\n *" " " PYTHON_SCRIPT "${PYTHON_SCRIPT}") + + add_custom_command( + OUTPUT ${GENERATED_FILES_LIST} + COMMAND "${Python3_EXECUTABLE}" "-c" "${PYTHON_SCRIPT}" + VERBATIM + WORKING_DIRECTORY ${godot-cpp_SOURCE_DIR} + MAIN_DEPENDENCY ${GODOTCPP_GDEXTENSION_API_FILE} + DEPENDS ${godot-cpp_SOURCE_DIR}/binding_generator.py + COMMENT "Generating bindings" ) -endfunction( ) + add_custom_target(generate_bindings DEPENDS ${GENERATED_FILES_LIST}) + set_target_properties(generate_bindings PROPERTIES FOLDER "godot-cpp") +endfunction() #[[ Generate doc_data.cpp The documentation displayed in the Godot editor is compiled into the extension. It takes a list of XML source files, and transforms them into a cpp file that is added to the sources list.]] -function( generate_doc_source OUTPUT_PATH SOURCES ) +function(generate_doc_source OUTPUT_PATH SOURCES) # Transform SOURCES CMake LIST # quote each path with '' # join with , to transform into a python list minus the surrounding [] - set( PYTHON_LIST "${SOURCES}") - list( TRANSFORM PYTHON_LIST REPLACE "(.*\.xml)" "'\\1'" ) - list( JOIN PYTHON_LIST "," PYTHON_LIST ) + set(PYTHON_LIST "${SOURCES}") + list(TRANSFORM PYTHON_LIST REPLACE "(.*\.xml)" "'\\1'") + list(JOIN PYTHON_LIST "," PYTHON_LIST) get_filename_component(OUTPUT_DIR "${OUTPUT_PATH}" DIRECTORY) - file(MAKE_DIRECTORY ${OUTPUT_DIR} ) + file(MAKE_DIRECTORY ${OUTPUT_DIR}) # Python one-liner to run our command # lists in CMake are just strings delimited by ';', so this works. - set( PYTHON_SCRIPT "from doc_source_generator import generate_doc_source" - "generate_doc_source( '${OUTPUT_PATH}', [${PYTHON_LIST}] )" ) - - add_custom_command( OUTPUT "${OUTPUT_PATH}" - COMMAND "${Python3_EXECUTABLE}" "-c" "${PYTHON_SCRIPT}" - VERBATIM - WORKING_DIRECTORY "${godot-cpp_SOURCE_DIR}" - DEPENDS + set(PYTHON_SCRIPT + "from doc_source_generator import generate_doc_source" + "generate_doc_source( '${OUTPUT_PATH}', [${PYTHON_LIST}] )" + ) + + add_custom_command( + OUTPUT "${OUTPUT_PATH}" + COMMAND "${Python3_EXECUTABLE}" "-c" "${PYTHON_SCRIPT}" + VERBATIM + WORKING_DIRECTORY "${godot-cpp_SOURCE_DIR}" + DEPENDS # "${godot-cpp_SOURCE_DIR}/doc_source_generator.py" "${SOURCES}" - COMMENT "Generating: ${OUTPUT_PATH}" + COMMENT "Generating: ${OUTPUT_PATH}" ) + add_custom_target(generate_doc_source DEPENDS "${OUTPUT_PATH}") + set_target_properties(generate_doc_source PROPERTIES FOLDER "godot-cpp") endfunction() #[[ target_doc_sources A simpler interface to add xml files as doc source to a output target. TARGET: The gdexension library target -SOURCES: a list of xml files to use for source generation and inclusion. -This function also adds a doc_gen target to test source generation.]] -function( target_doc_sources TARGET SOURCES ) +SOURCES: a list of xml files to use for source generation and inclusion.]] +function(target_doc_sources TARGET SOURCES) # set the generated file name - set( DOC_SOURCE_FILE "${CMAKE_CURRENT_BINARY_DIR}/gen/doc_source.cpp" ) + set(DOC_SOURCE_FILE "${CMAKE_CURRENT_BINARY_DIR}/gen/doc_source.cpp") # Create the file generation target, this won't be triggered unless a target # that depends on DOC_SOURCE_FILE is built generate_doc_source( "${DOC_SOURCE_FILE}" ${SOURCES} ) # Add DOC_SOURCE_FILE as a dependency to TARGET - target_sources( ${TARGET} PRIVATE "${DOC_SOURCE_FILE}" ) + target_sources(${TARGET} PRIVATE "${DOC_SOURCE_FILE}") - # Create a dummy target that depends on the source so that users can - # test the file generation task. - if( TARGET doc_gen ) - else() - add_custom_target( doc_gen ) - endif() - target_sources( doc_gen PRIVATE "${DOC_SOURCE_FILE}" ) + # Without adding this dependency to the doc_source_generator, XCode will complain. + add_dependencies(${TARGET} generate_doc_source) endfunction() diff --git a/cmake/android.cmake b/cmake/android.cmake index d3d95ee5..1d3a93b6 100644 --- a/cmake/android.cmake +++ b/cmake/android.cmake @@ -25,16 +25,25 @@ Android platforms. There is further information and examples in the doc/cmake.rst file. ]=======================================================================] -function( android_options ) - # Android Options + +#[============================[ Android Options ]============================] +function(android_options) + #[[ Options from SCons + + The options below are managed by CMake toolchain files, doc.cmake.rst has + more information + + android_api_level : Target Android API level. + Default = 21 + + ANDROID_HOME : Path to your Android SDK installation. + Default = os.environ.get("ANDROID_HOME", os.environ.get("ANDROID_SDK_ROOT") + ]] endfunction() -function( android_generate ) - target_compile_definitions(${TARGET_NAME} - PUBLIC - ANDROID_ENABLED - UNIX_ENABLED - ) +#[===========================[ Target Generation ]===========================] +function(android_generate) + target_compile_definitions(godot-cpp PUBLIC ANDROID_ENABLED UNIX_ENABLED) common_compiler_flags() endfunction() diff --git a/cmake/common_compiler_flags.cmake b/cmake/common_compiler_flags.cmake index 5a23c012..9d4894f1 100644 --- a/cmake/common_compiler_flags.cmake +++ b/cmake/common_compiler_flags.cmake @@ -7,24 +7,35 @@ configuration. It includes flags like optimization levels, warnings, and features. For target platform specific flags look to each of the ``cmake/.cmake`` files. +The default compile and link options CMake adds can be found in the +platform modules_. When a project is created it initializes its variables from +the ``CMAKE_*`` values. The cleanest way I have found to alter these defaults +is the use of the ``CMAKE_PROJECT__INCLUDE`` as demonstrated by +the emsdkHack.cmake to overcome the limitation on shared library creation. + +So far the emsdkHack is the only modification to the defaults we have made. + +.. _modules: https://github.com/Kitware/CMake/blob/master/Modules/Platform/ + ]=======================================================================] #[[ Compiler Configuration, not to be confused with build targets ]] -set( DEBUG_SYMBOLS "$,$>" ) +set(DEBUG_SYMBOLS "$,$>") #[[ Compiler Identification ]] -set( IS_CLANG "$" ) -set( IS_APPLECLANG "$" ) -set( IS_GNU "$" ) -set( IS_MSVC "$" ) -set( NOT_MSVC "$>" ) - -set( GNU_LT_V8 "$,8>" ) -set( GNU_GE_V9 "$,9>" ) -set( GNU_GT_V11 "$,11>" ) -set( GNU_LT_V11 "$,11>" ) -set( GNU_GE_V12 "$,12>" ) - +set(IS_CLANG "$") +set(IS_APPLECLANG "$") +set(IS_GNU "$") +set(IS_MSVC "$") +set(NOT_MSVC "$>") + +set(LT_V8 "$,8>") +set(GE_V9 "$,9>") +set(GT_V11 "$,11>") +set(LT_V11 "$,11>") +set(GE_V12 "$,12>") + +#[===========================[ compiler_detection ]===========================] #[[ Check for clang-cl with MSVC frontend The compiler is tested and set when the project command is called. The variable CXX_COMPILER_FRONTEND_VARIANT was introduced in 3.14 @@ -33,32 +44,31 @@ until CMake 3.30 so we can't use it yet. So to support clang downloaded from llvm.org which uses the MSVC frontend by default, we need to test for it. ]] -function( compiler_detection ) - if( ${CMAKE_CXX_COMPILER_ID} STREQUAL Clang ) - if( ${CMAKE_CXX_COMPILER_FRONTEND_VARIANT} STREQUAL MSVC ) - message( "Using clang-cl" ) - set( IS_CLANG "0" PARENT_SCOPE ) - set( IS_MSVC "1" PARENT_SCOPE ) - set( NOT_MSVC "0" PARENT_SCOPE ) - endif () - endif () -endfunction( ) - -function( common_compiler_flags ) - - target_compile_features(${TARGET_NAME} - PUBLIC - cxx_std_17 - ) +function(compiler_detection) + if(${CMAKE_CXX_COMPILER_ID} STREQUAL Clang) + if(${CMAKE_CXX_COMPILER_FRONTEND_VARIANT} STREQUAL MSVC) + message("Using clang-cl") + set(IS_CLANG "0" PARENT_SCOPE) + set(IS_MSVC "1" PARENT_SCOPE) + set(NOT_MSVC "0" PARENT_SCOPE) + endif() + endif() +endfunction() +#[=========================[ common_compiler_flags ]=========================] +#[[ This function assumes it is being called from within one of the platform +generate functions, with all the variables from lower scopes defined. ]] +function(common_compiler_flags) + # gersemi: off # These compiler options reflect what is in godot/SConstruct. - target_compile_options( ${TARGET_NAME} + target_compile_options( + godot-cpp + # The public flag tells CMake that the following options are transient, + # and will propagate to consumers. PUBLIC # Disable exception handling. Godot doesn't use exceptions anywhere, and this # saves around 20% of binary size and very significant build time. - $<${DISABLE_EXCEPTIONS}: - $<${NOT_MSVC}:-fno-exceptions> - > + $<${DISABLE_EXCEPTIONS}:$<${NOT_MSVC}:-fno-exceptions>> # Enabling Debug Symbols $<${DEBUG_SYMBOLS}: @@ -70,83 +80,86 @@ function( common_compiler_flags ) > > - $<${IS_DEV_BUILD}: - $<${NOT_MSVC}:-fno-omit-frame-pointer -O0> + $<${IS_DEV_BUILD}:$<${NOT_MSVC}:-fno-omit-frame-pointer -O0>> + + $<${HOT_RELOAD}:$<${IS_GNU}:-fno-gnu-unique>> + + # MSVC only + $<${IS_MSVC}: + # /MP isn't valid for clang-cl with msvc frontend + $<$:/MP${PROC_N}> + + # Interpret source files as utf-8 + /utf-8 + > + + # Warnings below, these do not need to propagate to consumers. + PRIVATE + $<${IS_MSVC}: + /W4 # Warning level 4 (informational) warnings that aren't off by default. + + # Disable warnings which we don't plan to fix. + /wd4100 # C4100 (unreferenced formal parameter): Doesn't play nice with polymorphism. + /wd4127 # C4127 (conditional expression is constant) + /wd4201 # C4201 (non-standard nameless struct/union): Only relevant for C89. + /wd4244 # C4244 C4245 C4267 (narrowing conversions): Unavoidable at this scale. + /wd4245 + /wd4267 + /wd4305 # C4305 (truncation): double to float or real_t, too hard to avoid. + /wd4514 # C4514 (unreferenced inline function has been removed) + /wd4714 # C4714 (function marked as __forceinline not inlined) + /wd4820 # C4820 (padding added after construct) + > + + # Clang and GNU common options + $<$: + -Wall + -Wctor-dtor-privacy + -Wextra + -Wno-unused-parameter + -Wnon-virtual-dtor + -Wwrite-strings > - $<${HOT_RELOAD}: - $<${IS_GNU}:-fno-gnu-unique> + # Clang only + $<${IS_CLANG}: + -Wimplicit-fallthrough + -Wno-ordered-compare-function-pointers > - # MSVC only - $<${IS_MSVC}: - # /MP isn't valid for clang-cl with msvc frontend - $<$:/MP${PROC_N}> - /W4 - - # Disable warnings which we don't plan to fix. - /wd4100 # C4100 (unreferenced formal parameter): Doesn't play nice with polymorphism. - /wd4127 # C4127 (conditional expression is constant) - /wd4201 # C4201 (non-standard nameless struct/union): Only relevant for C89. - /wd4244 # C4244 C4245 C4267 (narrowing conversions): Unavoidable at this scale. - /wd4245 - /wd4267 - /wd4305 # C4305 (truncation): double to float or real_t, too hard to avoid. - /wd4514 # C4514 (unreferenced inline function has been removed) - /wd4714 # C4714 (function marked as __forceinline not inlined) - /wd4820 # C4820 (padding added after construct) - - /utf-8 - > - - # Clang and GNU common options - $<$: - -Wall - -Wctor-dtor-privacy - -Wextra - -Wno-unused-parameter - -Wnon-virtual-dtor - -Wwrite-strings - > - - # Clang only - $<${IS_CLANG}: - -Wimplicit-fallthrough - -Wno-ordered-compare-function-pointers - > - - # GNU only - $<${IS_GNU}: - -Walloc-zero - -Wduplicated-branches - -Wduplicated-cond - -Wno-misleading-indentation - -Wplacement-new=1 - -Wshadow-local - -Wstringop-overflow=4 - - # Bogus warning fixed in 8+. - $<${GNU_LT_V8}:-Wno-strict-overflow> - - $<${GNU_GE_V9}:-Wattribute-alias=2> - - # Broke on MethodBind templates before GCC 11. - $<${GNU_GT_V11}:-Wlogical-op> - - # Regression in GCC 9/10, spams so much in our variadic templates that we need to outright disable it. - $<${GNU_LT_V11}:-Wno-type-limits> - - # False positives in our error macros, see GH-58747. - $<${GNU_GE_V12}:-Wno-return-type> - > + # GNU only + $<${IS_GNU}: + -Walloc-zero + -Wduplicated-branches + -Wduplicated-cond + -Wno-misleading-indentation + -Wplacement-new=1 + -Wshadow-local + -Wstringop-overflow=4 + + # Bogus warning fixed in 8+. + $<${LT_V8}:-Wno-strict-overflow> + + $<${GE_V9}:-Wattribute-alias=2> + + # Broke on MethodBind templates before GCC 11. + $<${GT_V11}:-Wlogical-op> + + # Regression in GCC 9/10, spams so much in our variadic templates that we need to outright disable it. + $<${LT_V11}:-Wno-type-limits> + + # False positives in our error macros, see GH-58747. + $<${GE_V12}:-Wno-return-type> + > ) - target_compile_definitions(${TARGET_NAME} + target_compile_definitions( + godot-cpp PUBLIC GDEXTENSION # features - $<${DEBUG_FEATURES}:DEBUG_ENABLED DEBUG_METHODS_ENABLED> + $<${DEBUG_FEATURES}:DEBUG_ENABLED> $<${IS_DEV_BUILD}:DEV_ENABLED> @@ -159,19 +172,21 @@ function( common_compiler_flags ) $<${THREADS_ENABLED}:THREADS_ENABLED> ) - target_link_options( ${TARGET_NAME} + target_link_options( + godot-cpp PUBLIC - $<${IS_MSVC}: - /WX # treat link warnings as errors. - /MANIFEST:NO # We dont need a manifest - > - $<${DEBUG_SYMBOLS}:$<${IS_MSVC}:/DEBUG:FULL>> + $<$: $<${IS_GNU}:-s> $<${IS_CLANG}:-s> $<${IS_APPLECLANG}:-Wl,-S -Wl,-x -Wl,-dead_strip> > + PRIVATE + $<${IS_MSVC}: + /WX # treat link warnings as errors. + /MANIFEST:NO # We dont need a manifest + > ) - + # gersemi: on endfunction() diff --git a/cmake/emsdkHack.cmake b/cmake/emsdkHack.cmake index 6981a379..c5ccc6fc 100644 --- a/cmake/emsdkHack.cmake +++ b/cmake/emsdkHack.cmake @@ -23,18 +23,18 @@ More information on cmake's `code injection`_ Overwrite Shared Library Properties to allow shared libs to be generated. ]=======================================================================] -if( EMSCRIPTEN ) +if(EMSCRIPTEN) set_property(GLOBAL PROPERTY TARGET_SUPPORTS_SHARED_LIBS TRUE) set(CMAKE_SHARED_LIBRARY_CREATE_C_FLAGS "-sSIDE_MODULE=1") set(CMAKE_SHARED_LIBRARY_CREATE_CXX_FLAGS "-sSIDE_MODULE=1") set(CMAKE_SHARED_LIBRARY_SUFFIX) # remove the suffix from the shared lib - set(CMAKE_STRIP FALSE) # used by default in pybind11 on .so modules + set(CMAKE_STRIP FALSE) # used by default in pybind11 on .so modules # The Emscripten toolchain sets the default value for EMSCRIPTEN_SYSTEM_PROCESSOR to x86 - # and CMAKE_SYSTEM_PROCESSOR to this value. I don't want that. - set(CMAKE_SYSTEM_PROCESSOR "wasm32" ) + # and copies that to CMAKE_SYSTEM_PROCESSOR. We don't want that. + set(CMAKE_SYSTEM_PROCESSOR "wasm32") # the above prevents the need for logic like: #if( ${CMAKE_SYSTEM_NAME} STREQUAL Emscripten ) # set( SYSTEM_ARCH wasm32 ) #endif () -endif () +endif() diff --git a/cmake/godotcpp.cmake b/cmake/godotcpp.cmake index c10d835d..b9328054 100644 --- a/cmake/godotcpp.cmake +++ b/cmake/godotcpp.cmake @@ -8,140 +8,154 @@ C compiler is specified, like in a toolchain, or from an IDE, then it will print a warning stating that the CMAKE_C_COMPILER compiler is unused. This if statement simply silences that warning. ]=======================================================================] -if( CMAKE_C_COMPILER ) -endif () +if(CMAKE_C_COMPILER) +endif() -#[=======================================================================[.rst: -Include Platform Files ----------------------- - -Because these files are included into the top level CMakelists.txt before the +#[[ Include Platform Files +Because these files are included into the top level CMakeLists.txt before the project directive, it means that -* ``CMAKE_CURRENT_SOURCE_DIR`` is the location of godot-cpp's CMakeLists.txt -* ``CMAKE_SOURCE_DIR`` is the location where any prior ``project(...)`` - directive was - -]=======================================================================] -include( ${CMAKE_CURRENT_SOURCE_DIR}/cmake/GodotCPPModule.cmake) -include( ${CMAKE_CURRENT_SOURCE_DIR}/cmake/common_compiler_flags.cmake) -include( ${CMAKE_CURRENT_SOURCE_DIR}/cmake/android.cmake) -include( ${CMAKE_CURRENT_SOURCE_DIR}/cmake/ios.cmake) -include( ${CMAKE_CURRENT_SOURCE_DIR}/cmake/linux.cmake) -include( ${CMAKE_CURRENT_SOURCE_DIR}/cmake/macos.cmake) -include( ${CMAKE_CURRENT_SOURCE_DIR}/cmake/web.cmake) -include( ${CMAKE_CURRENT_SOURCE_DIR}/cmake/windows.cmake) - +CMAKE_CURRENT_SOURCE_DIR is the location of godot-cpp's CMakeLists.txt +CMAKE_SOURCE_DIR is the location where any prior project() directive was ]] +include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/GodotCPPModule.cmake) +include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/common_compiler_flags.cmake) +include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/android.cmake) +include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/ios.cmake) +include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/linux.cmake) +include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/macos.cmake) +include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/web.cmake) +include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/windows.cmake) # Detect number of processors include(ProcessorCount) ProcessorCount(PROC_MAX) -message( "Auto-detected ${PROC_MAX} CPU cores available for build parallelism." ) +message("Auto-detected ${PROC_MAX} CPU cores available for build parallelism.") # List of known platforms -set( PLATFORM_LIST linux macos windows android ios web ) +set(PLATFORM_LIST + linux + macos + windows + android + ios + web +) # List of known architectures -set( ARCH_LIST x86_32 x86_64 arm32 arm64 rv64 ppc32 ppc64 wasm32 ) - -# Function to map processors to known architectures -function( godot_arch_name OUTVAR ) - +set(ARCH_LIST + x86_32 + x86_64 + arm32 + arm64 + rv64 + ppc32 + ppc64 + wasm32 +) + +#[=============================[ godot_arch_name ]=============================] +#[[ Function to map CMAKE_SYSTEM_PROCESSOR names to godot arch equivalents ]] +function(godot_arch_name OUTVAR) # Special case for macos universal builds that target both x86_64 and arm64 - if( DEFINED CMAKE_OSX_ARCHITECTURES) - if( "x86_64" IN_LIST CMAKE_OSX_ARCHITECTURES AND "arm64" IN_LIST CMAKE_OSX_ARCHITECTURES) - set(${OUTVAR} "universal" PARENT_SCOPE ) + if(DEFINED CMAKE_OSX_ARCHITECTURES) + if("x86_64" IN_LIST CMAKE_OSX_ARCHITECTURES AND "arm64" IN_LIST CMAKE_OSX_ARCHITECTURES) + set(${OUTVAR} "universal" PARENT_SCOPE) return() endif() endif() # Direct match early out. - string( TOLOWER "${CMAKE_SYSTEM_PROCESSOR}" ARCH ) - if( ARCH IN_LIST ARCH_LIST ) - set( ${OUTVAR} "${ARCH}" PARENT_SCOPE) + string(TOLOWER "${CMAKE_SYSTEM_PROCESSOR}" ARCH) + if(ARCH IN_LIST ARCH_LIST) + set(${OUTVAR} "${ARCH}" PARENT_SCOPE) return() endif() # Known aliases - set( x86_64 "w64;amd64;x86-64" ) - set( arm32 "armv7;armv7-a" ) - set( arm64 "armv8;arm64v8;aarch64;armv8-a" ) - set( rv64 "rv;riscv;riscv64" ) - set( ppc32 "ppcle;ppc" ) - set( ppc64 "ppc64le" ) - - if( ARCH IN_LIST x86_64 ) - set(${OUTVAR} "x86_64" PARENT_SCOPE ) - - elseif( ARCH IN_LIST arm32 ) - set(${OUTVAR} "arm32" PARENT_SCOPE ) - - elseif( ARCH IN_LIST arm64 ) - set(${OUTVAR} "arm64" PARENT_SCOPE ) - - elseif( ARCH IN_LIST rv64 ) - set(${OUTVAR} "rv64" PARENT_SCOPE ) - - elseif( ARCH IN_LIST ppc32 ) - set(${OUTVAR} "ppc32" PARENT_SCOPE ) - - elseif( ARCH IN_LIST ppc64 ) - set(${OUTVAR} "ppc64" PARENT_SCOPE ) - - elseif( ARCH MATCHES "86") + set(x86_64 "w64;amd64;x86-64") + set(arm32 "armv7;armv7-a") + set(arm64 "armv8;arm64v8;aarch64;armv8-a") + set(rv64 "rv;riscv;riscv64") + set(ppc32 "ppcle;ppc") + set(ppc64 "ppc64le") + + if(ARCH IN_LIST x86_64) + set(${OUTVAR} "x86_64" PARENT_SCOPE) + elseif(ARCH IN_LIST arm32) + set(${OUTVAR} "arm32" PARENT_SCOPE) + elseif(ARCH IN_LIST arm64) + set(${OUTVAR} "arm64" PARENT_SCOPE) + elseif(ARCH IN_LIST rv64) + set(${OUTVAR} "rv64" PARENT_SCOPE) + elseif(ARCH IN_LIST ppc32) + set(${OUTVAR} "ppc32" PARENT_SCOPE) + elseif(ARCH IN_LIST ppc64) + set(${OUTVAR} "ppc64" PARENT_SCOPE) + elseif(ARCH MATCHES "86") # Catches x86, i386, i486, i586, i686, etc. - set(${OUTVAR} "x86_32" PARENT_SCOPE ) - + set(${OUTVAR} "x86_32" PARENT_SCOPE) else() # Default value is whatever the processor is. - set(${OUTVAR} ${CMAKE_SYSTEM_PROCESSOR} PARENT_SCOPE ) - endif () + set(${OUTVAR} ${CMAKE_SYSTEM_PROCESSOR} PARENT_SCOPE) + endif() endfunction() # Function to define all the options. -function( godotcpp_options ) +function(godotcpp_options) #NOTE: platform is managed using toolchain files. #NOTE: arch is managed by using toolchain files. - # Except for macos universal, which can be set by GODOTCPP_MACOS_UNIVERSAL=YES + # To create a universal build for macos, set CMAKE_OSX_ARCHITECTURES + + set(GODOTCPP_TARGET + "template_debug" + CACHE STRING + "Which target to generate. valid values are: template_debug, template_release, and editor" + ) + set_property(CACHE GODOTCPP_TARGET PROPERTY STRINGS "template_debug;template_release;editor") # Input from user for GDExtension interface header and the API JSON file - set( GODOTCPP_GDEXTENSION_DIR "gdextension" CACHE PATH - "Path to a custom directory containing GDExtension interface header and API JSON file ( /path/to/gdextension_dir )" ) - set( GODOTCPP_CUSTOM_API_FILE "" CACHE FILEPATH - "Path to a custom GDExtension API JSON file (takes precedence over `GODOTCPP_GDEXTENSION_DIR`) ( /path/to/custom_api_file )") + set(GODOTCPP_GDEXTENSION_DIR + "gdextension" + CACHE PATH + "Path to a custom directory containing GDExtension interface header and API JSON file ( /path/to/gdextension_dir )" + ) + set(GODOTCPP_CUSTOM_API_FILE + "" + CACHE FILEPATH + "Path to a custom GDExtension API JSON file (takes precedence over `GODOTCPP_GDEXTENSION_DIR`) ( /path/to/custom_api_file )" + ) #TODO generate_bindings - option( GODOTCPP_GENERATE_TEMPLATE_GET_NODE - "Generate a template version of the Node class's get_node. (ON|OFF)" ON) + option(GODOTCPP_GENERATE_TEMPLATE_GET_NODE "Generate a template version of the Node class's get_node. (ON|OFF)" ON) #TODO build_library - set( GODOTCPP_PRECISION "single" CACHE STRING - "Set the floating-point precision level (single|double)") + set(GODOTCPP_PRECISION "single" CACHE STRING "Set the floating-point precision level (single|double)") - set( GODOTCPP_THREADS ON CACHE BOOL "Enable threading support" ) + set(GODOTCPP_THREADS ON CACHE BOOL "Enable threading support") #TODO compiledb #TODO compiledb_file - set( GODOTCPP_BUILD_PROFILE "" CACHE PATH - "Path to a file containing a feature build profile" ) + set(GODOTCPP_BUILD_PROFILE "" CACHE PATH "Path to a file containing a feature build profile") - set( GODOTCPP_USE_HOT_RELOAD "" CACHE BOOL - "Enable the extra accounting required to support hot reload. (ON|OFF)") + set(GODOTCPP_USE_HOT_RELOAD "" CACHE BOOL "Enable the extra accounting required to support hot reload. (ON|OFF)") # Disable exception handling. Godot doesn't use exceptions anywhere, and this # saves around 20% of binary size and very significant build time (GH-80513). - option( GODOTCPP_DISABLE_EXCEPTIONS "Force disabling exception handling code (ON|OFF)" ON ) + option(GODOTCPP_DISABLE_EXCEPTIONS "Force disabling exception handling code (ON|OFF)" ON) - set( GODOTCPP_SYMBOL_VISIBILITY "hidden" CACHE STRING - "Symbols visibility on GNU platforms. Use 'auto' to apply the default value. (auto|visible|hidden)") - set_property( CACHE GODOTCPP_SYMBOL_VISIBILITY PROPERTY STRINGS "auto;visible;hidden" ) + set(GODOTCPP_SYMBOL_VISIBILITY + "hidden" + CACHE STRING + "Symbols visibility on GNU platforms. Use 'auto' to apply the default value. (auto|visible|hidden)" + ) + set_property(CACHE GODOTCPP_SYMBOL_VISIBILITY PROPERTY STRINGS "auto;visible;hidden") #TODO optimize - option( GODOTCPP_DEV_BUILD "Developer build with dev-only debugging code (DEV_ENABLED)" OFF ) + option(GODOTCPP_DEV_BUILD "Developer build with dev-only debugging code (DEV_ENABLED)" OFF) #[[ debug_symbols Debug symbols are enabled by using the Debug or RelWithDebInfo build configurations. @@ -156,11 +170,11 @@ function( godotcpp_options ) ]] # FIXME These options are not present in SCons, and perhaps should be added there. - option( GODOTCPP_SYSTEM_HEADERS "Expose headers as SYSTEM." OFF ) - option( GODOTCPP_WARNING_AS_ERROR "Treat warnings as errors" OFF ) + option(GODOTCPP_SYSTEM_HEADERS "Expose headers as SYSTEM." OFF) + option(GODOTCPP_WARNING_AS_ERROR "Treat warnings as errors" OFF) # Enable Testing - option( GODOTCPP_ENABLE_TESTING "Enable the godot-cpp.test. integration testing targets" OFF ) + option(GODOTCPP_ENABLE_TESTING "Enable the godot-cpp.test. integration testing targets" OFF) #[[ Target Platform Options ]] android_options() @@ -171,8 +185,8 @@ function( godotcpp_options ) windows_options() endfunction() -# Function to configure and generate the targets -function( godotcpp_generate ) +#[===========================[ Target Generation ]===========================] +function(godotcpp_generate) #[[ Multi-Threaded MSVC Compilation When using the MSVC compiler the build command -j only specifies parallel jobs or targets, and not multi-threaded compilation To speed up @@ -181,16 +195,18 @@ function( godotcpp_generate ) MSVC is true when the compiler is some version of Microsoft Visual C++ or another compiler simulating the Visual C++ cl command-line syntax. ]] - if( MSVC ) - math( EXPR PROC_N "(${PROC_MAX}-1) | (${X}-2)>>31 & 1" ) - message( "Using ${PROC_N} cores for multi-threaded compilation.") + if(MSVC) + math(EXPR PROC_N "(${PROC_MAX}-1) | (${X}-2)>>31 & 1") + message("Using ${PROC_N} cores for multi-threaded compilation.") # TODO You can override it at configure time with ...." ) - else () - message( "Using ${CMAKE_BUILD_PARALLEL_LEVEL} cores, You can override" - " it at configure time by using -j or --parallel on the build" - " command.") - message( " eg. cmake --build . -j 7 ...") - endif () + else() + message( + "Using ${CMAKE_BUILD_PARALLEL_LEVEL} cores, You can override" + " it at configure time by using -j or --parallel on the build" + " command." + ) + message(" eg. cmake --build . -j 7 ...") + endif() #[[ GODOTCPP_SYMBOL_VISIBLITY To match the SCons options, the allowed values are "auto", "visible", and "hidden" @@ -200,174 +216,175 @@ function( godotcpp_generate ) TODO: It is probably worth a pull request which changes both to use the compiler values .. _flag:https://gcc.gnu.org/onlinedocs/gcc/Code-Gen-Options.html#index-fvisibility ]] - if( ${GODOTCPP_SYMBOL_VISIBILITY} STREQUAL "auto" OR ${GODOTCPP_SYMBOL_VISIBILITY} STREQUAL "visible" ) - set( GODOTCPP_SYMBOL_VISIBILITY "default" ) - endif () + if(${GODOTCPP_SYMBOL_VISIBILITY} STREQUAL "auto" OR ${GODOTCPP_SYMBOL_VISIBILITY} STREQUAL "visible") + set(GODOTCPP_SYMBOL_VISIBILITY "default") + endif() # Setup variable to optionally mark headers as SYSTEM - set( GODOTCPP_SYSTEM_HEADERS_ATTRIBUTE "") - if( GODOTCPP_SYSTEM_HEADERS) - set( GODOTCPP_SYSTEM_HEADERS_ATTRIBUTE SYSTEM) - endif () + set(GODOTCPP_SYSTEM_HEADERS_ATTRIBUTE "") + if(GODOTCPP_SYSTEM_HEADERS) + set(GODOTCPP_SYSTEM_HEADERS_ATTRIBUTE SYSTEM) + endif() #[[ Configure Binding Variables ]] # Generate Binding Parameters (True|False) - set( USE_TEMPLATE_GET_NODE "False" ) - if( GODOTCPP_GENERATE_TEMPLATE_GET_NODE ) - set( USE_TEMPLATE_GET_NODE "True" ) + set(USE_TEMPLATE_GET_NODE "False") + if(GODOTCPP_GENERATE_TEMPLATE_GET_NODE) + set(USE_TEMPLATE_GET_NODE "True") endif() # Bits (32|64) - math( EXPR BITS "${CMAKE_SIZEOF_VOID_P} * 8" ) # CMAKE_SIZEOF_VOID_P refers to target architecture. + math(EXPR BITS "${CMAKE_SIZEOF_VOID_P} * 8") # CMAKE_SIZEOF_VOID_P refers to target architecture. # API json File - set( GODOTCPP_GDEXTENSION_API_FILE "${GODOTCPP_GDEXTENSION_DIR}/extension_api.json") - if( GODOTCPP_CUSTOM_API_FILE ) # User-defined override. - set( GODOTCPP_GDEXTENSION_API_FILE "${GODOTCPP_CUSTOM_API_FILE}") + set(GODOTCPP_GDEXTENSION_API_FILE "${GODOTCPP_GDEXTENSION_DIR}/extension_api.json") + if(GODOTCPP_CUSTOM_API_FILE) # User-defined override. + set(GODOTCPP_GDEXTENSION_API_FILE "${GODOTCPP_CUSTOM_API_FILE}") endif() # Build Profile - if( GODOTCPP_BUILD_PROFILE ) - message( STATUS "Using build profile to trim api file") - message( "\tBUILD_PROFILE = '${GODOTCPP_BUILD_PROFILE}'") - message( "\tAPI_SOURCE = '${GODOTCPP_GDEXTENSION_API_FILE}'") + if(GODOTCPP_BUILD_PROFILE) + message(STATUS "Using build profile to trim api file") + message("\tBUILD_PROFILE = '${GODOTCPP_BUILD_PROFILE}'") + message("\tAPI_SOURCE = '${GODOTCPP_GDEXTENSION_API_FILE}'") build_profile_generate_trimmed_api( "${GODOTCPP_BUILD_PROFILE}" "${GODOTCPP_GDEXTENSION_API_FILE}" - "${CMAKE_CURRENT_BINARY_DIR}/extension_api.json" ) - set( GODOTCPP_GDEXTENSION_API_FILE "${CMAKE_CURRENT_BINARY_DIR}/extension_api.json" ) + "${CMAKE_CURRENT_BINARY_DIR}/extension_api.json" + ) + set(GODOTCPP_GDEXTENSION_API_FILE "${CMAKE_CURRENT_BINARY_DIR}/extension_api.json") endif() - message( STATUS "GODOTCPP_GDEXTENSION_API_FILE = '${GODOTCPP_GDEXTENSION_API_FILE}'") + message(STATUS "GODOTCPP_GDEXTENSION_API_FILE = '${GODOTCPP_GDEXTENSION_API_FILE}'") # generate the file list to use binding_generator_get_file_list( GENERATED_FILES_LIST "${GODOTCPP_GDEXTENSION_API_FILE}" - "${CMAKE_CURRENT_BINARY_DIR}" ) + "${CMAKE_CURRENT_BINARY_DIR}" + ) binding_generator_generate_bindings( "${GODOTCPP_GDEXTENSION_API_FILE}" "${USE_TEMPLATE_GET_NODE}" "${BITS}" "${GODOTCPP_PRECISION}" - "${CMAKE_CURRENT_BINARY_DIR}" ) - - add_custom_target( godot-cpp.generate_bindings DEPENDS ${GENERATED_FILES_LIST} ) - set_target_properties( godot-cpp.generate_bindings PROPERTIES FOLDER "godot-cpp" ) + "${CMAKE_CURRENT_BINARY_DIR}" + ) ### Platform is derived from the toolchain target # See GeneratorExpressions PLATFORM_ID and CMAKE_SYSTEM_NAME - string( CONCAT SYSTEM_NAME - "$<$:android.${ANDROID_ABI}>" - "$<$:ios>" - "$<$:linux>" - "$<$:macos>" - "$<$:web>" - "$<$:windows>" - "$<$:windows>" + string( + CONCAT + SYSTEM_NAME + "$<$:android>" + "$<$:ios>" + "$<$:linux>" + "$<$:macos>" + "$<$:web>" + "$<$:windows>" + "$<$:windows>" ) # Process CPU architecture argument. godot_arch_name( ARCH_NAME ) # Transform options into generator expressions - set( HOT_RELOAD-UNSET "$") + set(HOT_RELOAD-UNSET "$") - set( DISABLE_EXCEPTIONS "$") + set(DISABLE_EXCEPTIONS "$") - set( THREADS_ENABLED "$" ) + set(THREADS_ENABLED "$") # GODOTCPP_DEV_BUILD - set( RELEASE_TYPES "Release;MinSizeRel") - get_property( IS_MULTI_CONFIG GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG ) - if( IS_MULTI_CONFIG ) - message( NOTICE "=> Default build type is Debug. For other build types add --config to build command") - elseif( GODOTCPP_DEV_BUILD AND CMAKE_BUILD_TYPE IN_LIST RELEASE_TYPES ) - message( WARNING "=> GODOTCPP_DEV_BUILD implies a Debug-like build but CMAKE_BUILD_TYPE is '${CMAKE_BUILD_TYPE}'") - endif () - set( IS_DEV_BUILD "$") - - ### Define our godot-cpp library targets - foreach ( TARGET_ALIAS template_debug template_release editor ) - set( TARGET_NAME "godot-cpp.${TARGET_ALIAS}" ) - - # Generator Expressions that rely on the target - set( DEBUG_FEATURES "$>" ) - set( HOT_RELOAD "$>" ) - - # Suffix - string( CONCAT GODOTCPP_SUFFIX - "$<1:.${SYSTEM_NAME}>" - "$<1:.${TARGET_ALIAS}>" - "$<${IS_DEV_BUILD}:.dev>" - "$<$:.double>" - "$<1:.${ARCH_NAME}>" - # TODO IOS_SIMULATOR - "$<$:.nothreads>" + set(RELEASE_TYPES "Release;MinSizeRel") + get_property(IS_MULTI_CONFIG GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG) + if(IS_MULTI_CONFIG) + message(NOTICE "=> Default build type is Debug. For other build types add --config to build command") + elseif(GODOTCPP_DEV_BUILD AND CMAKE_BUILD_TYPE IN_LIST RELEASE_TYPES) + message( + WARNING + "=> GODOTCPP_DEV_BUILD implies a Debug-like build but CMAKE_BUILD_TYPE is '${CMAKE_BUILD_TYPE}'" ) + endif() + set(IS_DEV_BUILD "$") - # the godot-cpp.* library targets - add_library( ${TARGET_NAME} STATIC EXCLUDE_FROM_ALL ) - add_library( godot-cpp::${TARGET_ALIAS} ALIAS ${TARGET_NAME} ) + ### Define our godot-cpp library targets + # Generator Expressions that rely on the target + set(DEBUG_FEATURES "$>") + set(HOT_RELOAD "$>") + + # Suffix + string( + CONCAT + GODOTCPP_SUFFIX + "$<1:.${SYSTEM_NAME}>" + "$<1:.${GODOTCPP_TARGET}>" + "$<${IS_DEV_BUILD}:.dev>" + "$<$:.double>" + "$<1:.${ARCH_NAME}>" + # TODO IOS_SIMULATOR + "$<$:.nothreads>" + ) - file( GLOB_RECURSE GODOTCPP_SOURCES LIST_DIRECTORIES NO CONFIGURE_DEPENDS src/*.cpp ) + # the godot-cpp.* library targets + add_library(godot-cpp STATIC) - target_sources( ${TARGET_NAME} - PRIVATE - ${GODOTCPP_SOURCES} - ${GENERATED_FILES_LIST} - ) + # Without adding this dependency to the binding generator, XCode will complain. + add_dependencies(godot-cpp generate_bindings) - target_include_directories( ${TARGET_NAME} ${GODOTCPP_SYSTEM_HEADERS_ATTRIBUTE} PUBLIC - include - ${CMAKE_CURRENT_BINARY_DIR}/gen/include - ${GODOTCPP_GDEXTENSION_DIR} - ) + # Added for backwards compatibility with prior cmake solution so that builds dont immediately break + # from a missing target. + add_library(godot::cpp ALIAS godot-cpp) - set_target_properties( ${TARGET_NAME} - PROPERTIES - CXX_STANDARD 17 - CXX_EXTENSIONS OFF - CXX_VISIBILITY_PRESET ${GODOTCPP_SYMBOL_VISIBILITY} + file(GLOB_RECURSE GODOTCPP_SOURCES LIST_DIRECTORIES NO CONFIGURE_DEPENDS src/*.cpp) - COMPILE_WARNING_AS_ERROR ${GODOTCPP_WARNING_AS_ERROR} - POSITION_INDEPENDENT_CODE ON - BUILD_RPATH_USE_ORIGIN ON + target_sources(godot-cpp PRIVATE ${GODOTCPP_SOURCES} ${GENERATED_FILES_LIST}) - PREFIX "lib" - OUTPUT_NAME "${PROJECT_NAME}${GODOTCPP_SUFFIX}" + target_include_directories( + godot-cpp + ${GODOTCPP_SYSTEM_HEADERS_ATTRIBUTE} + PUBLIC include ${CMAKE_CURRENT_BINARY_DIR}/gen/include ${GODOTCPP_GDEXTENSION_DIR} + ) - ARCHIVE_OUTPUT_DIRECTORY "$<1:${CMAKE_BINARY_DIR}/bin>" + # gersemi: off + set_target_properties( + godot-cpp + PROPERTIES + CXX_STANDARD 17 + CXX_EXTENSIONS OFF + CXX_VISIBILITY_PRESET ${GODOTCPP_SYMBOL_VISIBILITY} - # Things that are handy to know for dependent targets - GODOTCPP_PLATFORM "${SYSTEM_NAME}" - GODOTCPP_TARGET "${TARGET_ALIAS}" - GODOTCPP_ARCH "${ARCH_NAME}" - GODOTCPP_PRECISION "${GODOTCPP_PRECISION}" - GODOTCPP_SUFFIX "${GODOTCPP_SUFFIX}" + COMPILE_WARNING_AS_ERROR ${GODOTCPP_WARNING_AS_ERROR} + POSITION_INDEPENDENT_CODE ON + BUILD_RPATH_USE_ORIGIN ON - # Some IDE's respect this property to logically group targets - FOLDER "godot-cpp" - ) + PREFIX "lib" + OUTPUT_NAME "${PROJECT_NAME}${GODOTCPP_SUFFIX}" - if( CMAKE_SYSTEM_NAME STREQUAL Android ) - android_generate() - elseif ( CMAKE_SYSTEM_NAME STREQUAL iOS ) - ios_generate() - elseif ( CMAKE_SYSTEM_NAME STREQUAL Linux ) - linux_generate() - elseif ( CMAKE_SYSTEM_NAME STREQUAL Darwin ) - macos_generate() - elseif ( CMAKE_SYSTEM_NAME STREQUAL Emscripten ) - web_generate() - elseif ( CMAKE_SYSTEM_NAME STREQUAL Windows ) - windows_generate() - endif () - - endforeach () + ARCHIVE_OUTPUT_DIRECTORY "$<1:${CMAKE_BINARY_DIR}/bin>" - # Added for backwards compatibility with prior cmake solution so that builds dont immediately break - # from a missing target. - add_library( godot::cpp ALIAS godot-cpp.template_debug ) + # Things that are handy to know for dependent targets + GODOTCPP_PLATFORM "${SYSTEM_NAME}" + GODOTCPP_TARGET "${GODOTCPP_TARGET}" + GODOTCPP_ARCH "${ARCH_NAME}" + GODOTCPP_PRECISION "${GODOTCPP_PRECISION}" + GODOTCPP_SUFFIX "${GODOTCPP_SUFFIX}" + # Some IDE's respect this property to logically group targets + FOLDER "godot-cpp" + ) + # gersemi: on + if(CMAKE_SYSTEM_NAME STREQUAL Android) + android_generate() + elseif(CMAKE_SYSTEM_NAME STREQUAL iOS) + ios_generate() + elseif(CMAKE_SYSTEM_NAME STREQUAL Linux) + linux_generate() + elseif(CMAKE_SYSTEM_NAME STREQUAL Darwin) + macos_generate() + elseif(CMAKE_SYSTEM_NAME STREQUAL Emscripten) + web_generate() + elseif(CMAKE_SYSTEM_NAME STREQUAL Windows) + windows_generate() + endif() endfunction() diff --git a/cmake/ios.cmake b/cmake/ios.cmake index a4c57057..52b2c012 100644 --- a/cmake/ios.cmake +++ b/cmake/ios.cmake @@ -1,21 +1,36 @@ #[=======================================================================[.rst: -Ios +iOS --- This file contains functions for options and configuration for targeting the -Ios platform +iOS platform ]=======================================================================] + +#[==============================[ iOS Options ]==============================] function(ios_options) - # iOS options + #[[ Options from SCons + + TODO ios_simulator: Target iOS Simulator + Default: False + + TODO ios_min_version: Target minimum iphoneos/iphonesimulator version + Default: 12.0 + + TODO IOS_TOOLCHAIN_PATH: Path to iOS toolchain + Default: "/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain", + + TODO IOS_SDK_PATH: Path to the iOS SDK + Default: '' + + TODO ios_triple: Triple for ios toolchain + Default: if has_ios_osxcross(): 'ios_triple' else '' + ]] endfunction() +#[===========================[ Target Generation ]===========================] function(ios_generate) - target_compile_definitions(${TARGET_NAME} - PUBLIC - IOS_ENABLED - UNIX_ENABLED - ) + target_compile_definitions(godot-cpp PUBLIC IOS_ENABLED UNIX_ENABLED) common_compiler_flags() endfunction() diff --git a/cmake/ios.toolchain.cmake b/cmake/ios.toolchain.cmake new file mode 100644 index 00000000..d8251816 --- /dev/null +++ b/cmake/ios.toolchain.cmake @@ -0,0 +1,1147 @@ +# gersemi: off +# This file is part of the ios-cmake project. It was retrieved from +# https://github.com/leetal/ios-cmake.git, which is a fork of +# https://github.com/gerstrong/ios-cmake.git, which is a fork of +# https://github.com/cristeab/ios-cmake.git, which is a fork of +# https://code.google.com/p/ios-cmake/. Which in turn is based off of +# the Platform/Darwin.cmake and Platform/UnixPaths.cmake files which +# are included with CMake 2.8.4 +# +# The ios-cmake project is licensed under the new BSD license. +# +# Copyright (c) 2014, Bogdan Cristea and LTE Engineering Software, +# Kitware, Inc., Insight Software Consortium. All rights reserved. +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# 3. Neither the name of the copyright holder nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# +# This file is based on the Platform/Darwin.cmake and +# Platform/UnixPaths.cmake files which are included with CMake 2.8.4 +# It has been altered for iOS development. +# +# Updated by Alex Stewart (alexs.mac@gmail.com) +# +# ***************************************************************************** +# Now maintained by Alexander Widerberg (widerbergaren [at] gmail.com) +# under the BSD-3-Clause license +# https://github.com/leetal/ios-cmake +# ***************************************************************************** +# +# INFORMATION / HELP +# +############################################################################### +# OPTIONS # +############################################################################### +# +# PLATFORM: (default "OS64") +# OS = Build for iPhoneOS. +# OS64 = Build for arm64 iphoneOS. +# OS64COMBINED = Build for arm64 x86_64 iphoneOS + iphoneOS Simulator. Combined into FAT STATIC lib (only supported on 3.14+ of CMake with "-G Xcode" argument in combination with the "cmake --install" CMake build step) +# SIMULATOR = Build for x86 i386 iphoneOS Simulator. +# SIMULATOR64 = Build for x86_64 iphoneOS Simulator. +# SIMULATORARM64 = Build for arm64 iphoneOS Simulator. +# SIMULATOR64COMBINED = Build for arm64 x86_64 iphoneOS Simulator. Combined into FAT STATIC lib (supported on 3.14+ of CMakewith "-G Xcode" argument ONLY) +# TVOS = Build for arm64 tvOS. +# TVOSCOMBINED = Build for arm64 x86_64 tvOS + tvOS Simulator. Combined into FAT STATIC lib (only supported on 3.14+ of CMake with "-G Xcode" argument in combination with the "cmake --install" CMake build step) +# SIMULATOR_TVOS = Build for x86_64 tvOS Simulator. +# SIMULATORARM64_TVOS = Build for arm64 tvOS Simulator. +# VISIONOSCOMBINED = Build for arm64 visionOS + visionOS Simulator. Combined into FAT STATIC lib (only supported on 3.14+ of CMake with "-G Xcode" argument in combination with the "cmake --install" CMake build step) +# VISIONOS = Build for arm64 visionOS. +# SIMULATOR_VISIONOS = Build for arm64 visionOS Simulator. +# WATCHOS = Build for armv7k arm64_32 for watchOS. +# WATCHOSCOMBINED = Build for armv7k arm64_32 x86_64 watchOS + watchOS Simulator. Combined into FAT STATIC lib (only supported on 3.14+ of CMake with "-G Xcode" argument in combination with the "cmake --install" CMake build step) +# SIMULATOR_WATCHOS = Build for x86_64 for watchOS Simulator. +# SIMULATORARM64_WATCHOS = Build for arm64 for watchOS Simulator. +# MAC = Build for x86_64 macOS. +# MAC_ARM64 = Build for Apple Silicon macOS. +# MAC_UNIVERSAL = Combined build for x86_64 and Apple Silicon on macOS. +# MAC_CATALYST = Build for x86_64 macOS with Catalyst support (iOS toolchain on macOS). +# Note: The build argument "MACOSX_DEPLOYMENT_TARGET" can be used to control min-version of macOS +# MAC_CATALYST_ARM64 = Build for Apple Silicon macOS with Catalyst support (iOS toolchain on macOS). +# Note: The build argument "MACOSX_DEPLOYMENT_TARGET" can be used to control min-version of macOS +# MAC_CATALYST_UNIVERSAL = Combined build for x86_64 and Apple Silicon on Catalyst. +# +# CMAKE_OSX_SYSROOT: Path to the SDK to use. By default this is +# automatically determined from PLATFORM and xcodebuild, but +# can also be manually specified (although this should not be required). +# +# CMAKE_DEVELOPER_ROOT: Path to the Developer directory for the platform +# being compiled for. By default, this is automatically determined from +# CMAKE_OSX_SYSROOT, but can also be manually specified (although this should +# not be required). +# +# DEPLOYMENT_TARGET: Minimum SDK version to target. Default 6.0 on watchOS, 13.0 on tvOS+iOS/iPadOS, 11.0 on macOS, 1.0 on visionOS +# +# NAMED_LANGUAGE_SUPPORT: +# ON (default) = Will require "enable_language(OBJC) and/or enable_language(OBJCXX)" for full OBJC|OBJCXX support +# OFF = Will embed the OBJC and OBJCXX flags into the CMAKE_C_FLAGS and CMAKE_CXX_FLAGS (legacy behavior, CMake version < 3.16) +# +# ENABLE_BITCODE: (ON|OFF) Enables or disables bitcode support. Default OFF +# +# ENABLE_ARC: (ON|OFF) Enables or disables ARC support. Default ON (ARC enabled by default) +# +# ENABLE_VISIBILITY: (ON|OFF) Enables or disables symbol visibility support. Default OFF (visibility hidden by default) +# +# ENABLE_STRICT_TRY_COMPILE: (ON|OFF) Enables or disables strict try_compile() on all Check* directives (will run linker +# to actually check if linking is possible). Default OFF (will set CMAKE_TRY_COMPILE_TARGET_TYPE to STATIC_LIBRARY) +# +# ARCHS: (armv7 armv7s armv7k arm64 arm64_32 i386 x86_64) If specified, will override the default architectures for the given PLATFORM +# OS = armv7 armv7s arm64 (if applicable) +# OS64 = arm64 (if applicable) +# SIMULATOR = i386 +# SIMULATOR64 = x86_64 +# SIMULATORARM64 = arm64 +# TVOS = arm64 +# SIMULATOR_TVOS = x86_64 (i386 has since long been deprecated) +# SIMULATORARM64_TVOS = arm64 +# WATCHOS = armv7k arm64_32 (if applicable) +# SIMULATOR_WATCHOS = x86_64 (i386 has since long been deprecated) +# SIMULATORARM64_WATCHOS = arm64 +# MAC = x86_64 +# MAC_ARM64 = arm64 +# MAC_UNIVERSAL = x86_64 arm64 +# MAC_CATALYST = x86_64 +# MAC_CATALYST_ARM64 = arm64 +# MAC_CATALYST_UNIVERSAL = x86_64 arm64 +# +# NOTE: When manually specifying ARCHS, put a semi-colon between the entries. E.g., -DARCHS="armv7;arm64" +# +############################################################################### +# END OPTIONS # +############################################################################### +# +# This toolchain defines the following properties (available via get_property()) for use externally: +# +# PLATFORM: The currently targeted platform. +# XCODE_VERSION: Version number (not including Build version) of Xcode detected. +# SDK_VERSION: Version of SDK being used. +# OSX_ARCHITECTURES: Architectures being compiled for (generated from PLATFORM). +# APPLE_TARGET_TRIPLE: Used by autoconf build systems. NOTE: If "ARCHS" is overridden, this will *NOT* be set! +# +# This toolchain defines the following macros for use externally: +# +# set_xcode_property (TARGET XCODE_PROPERTY XCODE_VALUE XCODE_VARIANT) +# A convenience macro for setting xcode specific properties on targets. +# Available variants are: All, Release, RelWithDebInfo, Debug, MinSizeRel +# example: set_xcode_property (myioslib IPHONEOS_DEPLOYMENT_TARGET "3.1" "all"). +# +# find_host_package (PROGRAM ARGS) +# A macro used to find executable programs on the host system, not within the +# environment. Thanks to the android-cmake project for providing the +# command. +# + +cmake_minimum_required(VERSION 3.8.0) + +# CMake invokes the toolchain file twice during the first build, but only once during subsequent rebuilds. +# NOTE: To improve single-library build-times, provide the flag "OS_SINGLE_BUILD" as a build argument. +if(DEFINED OS_SINGLE_BUILD AND DEFINED ENV{_IOS_TOOLCHAIN_HAS_RUN}) + return() +endif() +set(ENV{_IOS_TOOLCHAIN_HAS_RUN} true) + +# List of supported platform values +list(APPEND _supported_platforms + "OS" "OS64" "OS64COMBINED" "SIMULATOR" "SIMULATOR64" "SIMULATORARM64" "SIMULATOR64COMBINED" + "TVOS" "TVOSCOMBINED" "SIMULATOR_TVOS" "SIMULATORARM64_TVOS" + "WATCHOS" "WATCHOSCOMBINED" "SIMULATOR_WATCHOS" "SIMULATORARM64_WATCHOS" + "MAC" "MAC_ARM64" "MAC_UNIVERSAL" + "VISIONOS" "SIMULATOR_VISIONOS" "VISIONOSCOMBINED" + "MAC_CATALYST" "MAC_CATALYST_ARM64" "MAC_CATALYST_UNIVERSAL") + +# Cache what generator is used +set(USED_CMAKE_GENERATOR "${CMAKE_GENERATOR}") + +# Check if using a CMake version capable of building combined FAT builds (simulator and target slices combined in one static lib) +if(${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.14") + set(MODERN_CMAKE YES) +endif() + +# Get the Xcode version being used. +# Problem: CMake runs toolchain files multiple times, but can't read cache variables on some runs. +# Workaround: On the first run (in which cache variables are always accessible), set an intermediary environment variable. +# +# NOTE: This pattern is used in many places in this toolchain to speed up checks of all sorts +if(DEFINED XCODE_VERSION_INT) + # Environment variables are always preserved. + set(ENV{_XCODE_VERSION_INT} "${XCODE_VERSION_INT}") +elseif(DEFINED ENV{_XCODE_VERSION_INT}) + set(XCODE_VERSION_INT "$ENV{_XCODE_VERSION_INT}") +elseif(NOT DEFINED XCODE_VERSION_INT) + find_program(XCODEBUILD_EXECUTABLE xcodebuild) + if(NOT XCODEBUILD_EXECUTABLE) + message(FATAL_ERROR "xcodebuild not found. Please install either the standalone commandline tools or Xcode.") + endif() + execute_process(COMMAND ${XCODEBUILD_EXECUTABLE} -version + OUTPUT_VARIABLE XCODE_VERSION_INT + ERROR_QUIET + OUTPUT_STRIP_TRAILING_WHITESPACE) + string(REGEX MATCH "Xcode [0-9\\.]+" XCODE_VERSION_INT "${XCODE_VERSION_INT}") + string(REGEX REPLACE "Xcode ([0-9\\.]+)" "\\1" XCODE_VERSION_INT "${XCODE_VERSION_INT}") + set(XCODE_VERSION_INT "${XCODE_VERSION_INT}" CACHE INTERNAL "") +endif() + +# Assuming that xcode 12.0 is installed you most probably have ios sdk 14.0 or later installed (tested on Big Sur) +# if you don't set a deployment target it will be set the way you only get 64-bit builds +#if(NOT DEFINED DEPLOYMENT_TARGET AND XCODE_VERSION_INT VERSION_GREATER 12.0) +# Temporarily fix the arm64 issues in CMake install-combined by excluding arm64 for simulator builds (needed for Apple Silicon...) +# set(CMAKE_XCODE_ATTRIBUTE_EXCLUDED_ARCHS[sdk=iphonesimulator*] "arm64") +#endif() + +# Check if the platform variable is set +if(DEFINED PLATFORM) + # Environment variables are always preserved. + set(ENV{_PLATFORM} "${PLATFORM}") +elseif(DEFINED ENV{_PLATFORM}) + set(PLATFORM "$ENV{_PLATFORM}") +elseif(NOT DEFINED PLATFORM) + message(FATAL_ERROR "PLATFORM argument not set. Bailing configure since I don't know what target you want to build for!") +endif () + +if(PLATFORM MATCHES ".*COMBINED" AND NOT CMAKE_GENERATOR MATCHES "Xcode") + message(FATAL_ERROR "The combined builds support requires Xcode to be used as a generator via '-G Xcode' command-line argument in CMake") +endif() + +# Safeguard that the platform value is set and is one of the supported values +list(FIND _supported_platforms ${PLATFORM} contains_PLATFORM) +if("${contains_PLATFORM}" EQUAL "-1") + string(REPLACE ";" "\n * " _supported_platforms_formatted "${_supported_platforms}") + message(FATAL_ERROR " Invalid PLATFORM specified! Current value: ${PLATFORM}.\n" + " Supported PLATFORM values: \n * ${_supported_platforms_formatted}") +endif() + +# Check if Apple Silicon is supported +if(PLATFORM MATCHES "^(MAC_ARM64)$|^(MAC_CATALYST_ARM64)$|^(MAC_UNIVERSAL)$|^(MAC_CATALYST_UNIVERSAL)$" AND ${CMAKE_VERSION} VERSION_LESS "3.19.5") + message(FATAL_ERROR "Apple Silicon builds requires a minimum of CMake 3.19.5") +endif() + +# Touch the toolchain variable to suppress the "unused variable" warning. +# This happens if CMake is invoked with the same command line the second time. +if(CMAKE_TOOLCHAIN_FILE) +endif() + +# Fix for PThread library not in path +set(CMAKE_THREAD_LIBS_INIT "-lpthread") +set(CMAKE_HAVE_THREADS_LIBRARY 1) +set(CMAKE_USE_WIN32_THREADS_INIT 0) +set(CMAKE_USE_PTHREADS_INIT 1) + +# Specify named language support defaults. +if(NOT DEFINED NAMED_LANGUAGE_SUPPORT AND ${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.16") + set(NAMED_LANGUAGE_SUPPORT ON) + message(STATUS "[DEFAULTS] Using explicit named language support! E.g., enable_language(CXX) is needed in the project files.") +elseif(NOT DEFINED NAMED_LANGUAGE_SUPPORT AND ${CMAKE_VERSION} VERSION_LESS "3.16") + set(NAMED_LANGUAGE_SUPPORT OFF) + message(STATUS "[DEFAULTS] Disabling explicit named language support. Falling back to legacy behavior.") +elseif(DEFINED NAMED_LANGUAGE_SUPPORT AND ${CMAKE_VERSION} VERSION_LESS "3.16") + message(FATAL_ERROR "CMake named language support for OBJC and OBJCXX was added in CMake 3.16.") +endif() +set(NAMED_LANGUAGE_SUPPORT_INT ${NAMED_LANGUAGE_SUPPORT} CACHE BOOL + "Whether or not to enable explicit named language support" FORCE) + +# Specify the minimum version of the deployment target. +if(NOT DEFINED DEPLOYMENT_TARGET) + if (PLATFORM MATCHES "WATCHOS") + # Unless specified, SDK version 4.0 is used by default as minimum target version (watchOS). + set(DEPLOYMENT_TARGET "6.0") + elseif(PLATFORM STREQUAL "MAC") + # Unless specified, SDK version 10.13 (High Sierra) is used by default as the minimum target version (macos). + set(DEPLOYMENT_TARGET "11.0") + elseif(PLATFORM STREQUAL "VISIONOS" OR PLATFORM STREQUAL "SIMULATOR_VISIONOS" OR PLATFORM STREQUAL "VISIONOSCOMBINED") + # Unless specified, SDK version 1.0 is used by default as minimum target version (visionOS). + set(DEPLOYMENT_TARGET "1.0") + elseif(PLATFORM STREQUAL "MAC_ARM64") + # Unless specified, SDK version 11.0 (Big Sur) is used by default as the minimum target version (macOS on arm). + set(DEPLOYMENT_TARGET "11.0") + elseif(PLATFORM STREQUAL "MAC_UNIVERSAL") + # Unless specified, SDK version 11.0 (Big Sur) is used by default as minimum target version for universal builds. + set(DEPLOYMENT_TARGET "11.0") + elseif(PLATFORM STREQUAL "MAC_CATALYST" OR PLATFORM STREQUAL "MAC_CATALYST_ARM64" OR PLATFORM STREQUAL "MAC_CATALYST_UNIVERSAL") + # Unless specified, SDK version 13.0 is used by default as the minimum target version (mac catalyst minimum requirement). + set(DEPLOYMENT_TARGET "13.1") + else() + # Unless specified, SDK version 11.0 is used by default as the minimum target version (iOS, tvOS). + set(DEPLOYMENT_TARGET "13.0") + endif() + message(STATUS "[DEFAULTS] Using the default min-version since DEPLOYMENT_TARGET not provided!") +elseif(DEFINED DEPLOYMENT_TARGET AND PLATFORM MATCHES "^MAC_CATALYST" AND ${DEPLOYMENT_TARGET} VERSION_LESS "13.1") + message(FATAL_ERROR "Mac Catalyst builds requires a minimum deployment target of 13.1!") +endif() + +# Store the DEPLOYMENT_TARGET in the cache +set(DEPLOYMENT_TARGET "${DEPLOYMENT_TARGET}" CACHE INTERNAL "") + +# Handle the case where we are targeting iOS and a version above 10.3.4 (32-bit support dropped officially) +if(PLATFORM STREQUAL "OS" AND DEPLOYMENT_TARGET VERSION_GREATER_EQUAL 10.3.4) + set(PLATFORM "OS64") + message(STATUS "Targeting minimum SDK version ${DEPLOYMENT_TARGET}. Dropping 32-bit support.") +elseif(PLATFORM STREQUAL "SIMULATOR" AND DEPLOYMENT_TARGET VERSION_GREATER_EQUAL 10.3.4) + set(PLATFORM "SIMULATOR64") + message(STATUS "Targeting minimum SDK version ${DEPLOYMENT_TARGET}. Dropping 32-bit support.") +endif() + +set(PLATFORM_INT "${PLATFORM}") + +if(DEFINED ARCHS) + string(REPLACE ";" "-" ARCHS_SPLIT "${ARCHS}") +endif() + +# Determine the platform name and architectures for use in xcodebuild commands +# from the specified PLATFORM_INT name. +if(PLATFORM_INT STREQUAL "OS") + set(SDK_NAME iphoneos) + if(NOT ARCHS) + set(ARCHS armv7 armv7s arm64) + set(APPLE_TARGET_TRIPLE_INT arm-apple-ios${DEPLOYMENT_TARGET}) + else() + set(APPLE_TARGET_TRIPLE_INT ${ARCHS_SPLIT}-apple-ios${DEPLOYMENT_TARGET}) + endif() +elseif(PLATFORM_INT STREQUAL "OS64") + set(SDK_NAME iphoneos) + if(NOT ARCHS) + if (XCODE_VERSION_INT VERSION_GREATER 10.0) + set(ARCHS arm64) # FIXME: Add arm64e when Apple has fixed the integration issues with it, libarclite_iphoneos.a is currently missing bitcode markers for example + else() + set(ARCHS arm64) + endif() + set(APPLE_TARGET_TRIPLE_INT arm64-apple-ios${DEPLOYMENT_TARGET}) + else() + set(APPLE_TARGET_TRIPLE_INT ${ARCHS_SPLIT}-apple-ios${DEPLOYMENT_TARGET}) + endif() +elseif(PLATFORM_INT STREQUAL "OS64COMBINED") + set(SDK_NAME iphoneos) + if(MODERN_CMAKE) + if(NOT ARCHS) + if (XCODE_VERSION_INT VERSION_GREATER 12.0) + set(ARCHS arm64 x86_64) + set(CMAKE_XCODE_ATTRIBUTE_ARCHS[sdk=iphoneos*] "arm64") + set(CMAKE_XCODE_ATTRIBUTE_ARCHS[sdk=iphonesimulator*] "x86_64 arm64") + set(CMAKE_XCODE_ATTRIBUTE_VALID_ARCHS[sdk=iphoneos*] "arm64") + set(CMAKE_XCODE_ATTRIBUTE_VALID_ARCHS[sdk=iphonesimulator*] "x86_64 arm64") + else() + set(ARCHS arm64 x86_64) + set(CMAKE_XCODE_ATTRIBUTE_ARCHS[sdk=iphoneos*] "arm64") + set(CMAKE_XCODE_ATTRIBUTE_ARCHS[sdk=iphonesimulator*] "x86_64") + set(CMAKE_XCODE_ATTRIBUTE_VALID_ARCHS[sdk=iphoneos*] "arm64") + set(CMAKE_XCODE_ATTRIBUTE_VALID_ARCHS[sdk=iphonesimulator*] "x86_64") + endif() + set(APPLE_TARGET_TRIPLE_INT arm64-x86_64-apple-ios${DEPLOYMENT_TARGET}) + else() + set(APPLE_TARGET_TRIPLE_INT ${ARCHS_SPLIT}-apple-ios${DEPLOYMENT_TARGET}) + endif() + else() + message(FATAL_ERROR "Please make sure that you are running CMake 3.14+ to make the OS64COMBINED setting work") + endif() +elseif(PLATFORM_INT STREQUAL "SIMULATOR64COMBINED") + set(SDK_NAME iphonesimulator) + if(MODERN_CMAKE) + if(NOT ARCHS) + if (XCODE_VERSION_INT VERSION_GREATER 12.0) + set(ARCHS arm64 x86_64) # FIXME: Add arm64e when Apple have fixed the integration issues with it, libarclite_iphoneos.a is currently missing bitcode markers for example + set(CMAKE_XCODE_ATTRIBUTE_ARCHS[sdk=iphoneos*] "") + set(CMAKE_XCODE_ATTRIBUTE_ARCHS[sdk=iphonesimulator*] "x86_64 arm64") + set(CMAKE_XCODE_ATTRIBUTE_VALID_ARCHS[sdk=iphoneos*] "") + set(CMAKE_XCODE_ATTRIBUTE_VALID_ARCHS[sdk=iphonesimulator*] "x86_64 arm64") + else() + set(ARCHS arm64 x86_64) + set(CMAKE_XCODE_ATTRIBUTE_ARCHS[sdk=iphoneos*] "") + set(CMAKE_XCODE_ATTRIBUTE_ARCHS[sdk=iphonesimulator*] "x86_64") + set(CMAKE_XCODE_ATTRIBUTE_VALID_ARCHS[sdk=iphoneos*] "") + set(CMAKE_XCODE_ATTRIBUTE_VALID_ARCHS[sdk=iphonesimulator*] "x86_64") + endif() + set(APPLE_TARGET_TRIPLE_INT aarch64-x86_64-apple-ios${DEPLOYMENT_TARGET}-simulator) + else() + set(APPLE_TARGET_TRIPLE_INT ${ARCHS_SPLIT}-apple-ios${DEPLOYMENT_TARGET}-simulator) + endif() + else() + message(FATAL_ERROR "Please make sure that you are running CMake 3.14+ to make the SIMULATOR64COMBINED setting work") + endif() +elseif(PLATFORM_INT STREQUAL "SIMULATOR") + set(SDK_NAME iphonesimulator) + if(NOT ARCHS) + set(ARCHS i386) + set(APPLE_TARGET_TRIPLE_INT i386-apple-ios${DEPLOYMENT_TARGET}-simulator) + else() + set(APPLE_TARGET_TRIPLE_INT ${ARCHS_SPLIT}-apple-ios${DEPLOYMENT_TARGET}-simulator) + endif() + message(DEPRECATION "SIMULATOR IS DEPRECATED. Consider using SIMULATOR64 instead.") +elseif(PLATFORM_INT STREQUAL "SIMULATOR64") + set(SDK_NAME iphonesimulator) + if(NOT ARCHS) + set(ARCHS x86_64) + set(APPLE_TARGET_TRIPLE_INT x86_64-apple-ios${DEPLOYMENT_TARGET}-simulator) + else() + set(APPLE_TARGET_TRIPLE_INT ${ARCHS_SPLIT}-apple-ios${DEPLOYMENT_TARGET}-simulator) + endif() +elseif(PLATFORM_INT STREQUAL "SIMULATORARM64") + set(SDK_NAME iphonesimulator) + if(NOT ARCHS) + set(ARCHS arm64) + set(APPLE_TARGET_TRIPLE_INT arm64-apple-ios${DEPLOYMENT_TARGET}-simulator) + else() + set(APPLE_TARGET_TRIPLE_INT ${ARCHS_SPLIT}-apple-ios${DEPLOYMENT_TARGET}-simulator) + endif() +elseif(PLATFORM_INT STREQUAL "TVOS") + set(SDK_NAME appletvos) + if(NOT ARCHS) + set(ARCHS arm64) + set(APPLE_TARGET_TRIPLE_INT arm64-apple-tvos${DEPLOYMENT_TARGET}) + else() + set(APPLE_TARGET_TRIPLE_INT ${ARCHS_SPLIT}-apple-tvos${DEPLOYMENT_TARGET}) + endif() +elseif (PLATFORM_INT STREQUAL "TVOSCOMBINED") + set(SDK_NAME appletvos) + if(MODERN_CMAKE) + if(NOT ARCHS) + set(ARCHS arm64 x86_64) + set(APPLE_TARGET_TRIPLE_INT arm64-x86_64-apple-tvos${DEPLOYMENT_TARGET}) + set(CMAKE_XCODE_ATTRIBUTE_ARCHS[sdk=appletvos*] "arm64") + set(CMAKE_XCODE_ATTRIBUTE_ARCHS[sdk=appletvsimulator*] "x86_64 arm64") + set(CMAKE_XCODE_ATTRIBUTE_VALID_ARCHS[sdk=appletvos*] "arm64") + set(CMAKE_XCODE_ATTRIBUTE_VALID_ARCHS[sdk=appletvsimulator*] "x86_64 arm64") + else() + set(APPLE_TARGET_TRIPLE_INT ${ARCHS_SPLIT}-apple-tvos${DEPLOYMENT_TARGET}) + endif() + else() + message(FATAL_ERROR "Please make sure that you are running CMake 3.14+ to make the TVOSCOMBINED setting work") + endif() +elseif(PLATFORM_INT STREQUAL "SIMULATOR_TVOS") + set(SDK_NAME appletvsimulator) + if(NOT ARCHS) + set(ARCHS x86_64) + set(APPLE_TARGET_TRIPLE_INT x86_64-apple-tvos${DEPLOYMENT_TARGET}-simulator) + else() + set(APPLE_TARGET_TRIPLE_INT ${ARCHS_SPLIT}-apple-tvos${DEPLOYMENT_TARGET}-simulator) + endif() +elseif(PLATFORM_INT STREQUAL "SIMULATORARM64_TVOS") + set(SDK_NAME appletvsimulator) + if(NOT ARCHS) + set(ARCHS arm64) + set(APPLE_TARGET_TRIPLE_INT arm64-apple-tvos${DEPLOYMENT_TARGET}-simulator) + else() + set(APPLE_TARGET_TRIPLE_INT ${ARCHS_SPLIT}-apple-tvos${DEPLOYMENT_TARGET}-simulator) + endif() +elseif(PLATFORM_INT STREQUAL "WATCHOS") + set(SDK_NAME watchos) + if(NOT ARCHS) + if (XCODE_VERSION_INT VERSION_GREATER 10.0) + set(ARCHS armv7k arm64_32) + set(APPLE_TARGET_TRIPLE_INT arm64_32-apple-watchos${DEPLOYMENT_TARGET}) + else() + set(ARCHS armv7k) + set(APPLE_TARGET_TRIPLE_INT arm-apple-watchos${DEPLOYMENT_TARGET}) + endif() + else() + set(APPLE_TARGET_TRIPLE_INT ${ARCHS_SPLIT}-apple-watchos${DEPLOYMENT_TARGET}) + endif() +elseif(PLATFORM_INT STREQUAL "WATCHOSCOMBINED") + set(SDK_NAME watchos) + if(MODERN_CMAKE) + if(NOT ARCHS) + if (XCODE_VERSION_INT VERSION_GREATER 10.0) + set(ARCHS armv7k arm64_32 i386) + set(APPLE_TARGET_TRIPLE_INT arm64_32-i386-apple-watchos${DEPLOYMENT_TARGET}) + set(CMAKE_XCODE_ATTRIBUTE_ARCHS[sdk=watchos*] "armv7k arm64_32") + set(CMAKE_XCODE_ATTRIBUTE_ARCHS[sdk=watchsimulator*] "i386") + set(CMAKE_XCODE_ATTRIBUTE_VALID_ARCHS[sdk=watchos*] "armv7k arm64_32") + set(CMAKE_XCODE_ATTRIBUTE_VALID_ARCHS[sdk=watchsimulator*] "i386") + else() + set(ARCHS armv7k i386) + set(APPLE_TARGET_TRIPLE_INT arm-i386-apple-watchos${DEPLOYMENT_TARGET}) + set(CMAKE_XCODE_ATTRIBUTE_ARCHS[sdk=watchos*] "armv7k") + set(CMAKE_XCODE_ATTRIBUTE_ARCHS[sdk=watchsimulator*] "i386") + set(CMAKE_XCODE_ATTRIBUTE_VALID_ARCHS[sdk=watchos*] "armv7k") + set(CMAKE_XCODE_ATTRIBUTE_VALID_ARCHS[sdk=watchsimulator*] "i386") + endif() + else() + set(APPLE_TARGET_TRIPLE_INT ${ARCHS_SPLIT}-apple-watchos${DEPLOYMENT_TARGET}) + endif() + else() + message(FATAL_ERROR "Please make sure that you are running CMake 3.14+ to make the WATCHOSCOMBINED setting work") + endif() +elseif(PLATFORM_INT STREQUAL "SIMULATOR_WATCHOS") + set(SDK_NAME watchsimulator) + if(NOT ARCHS) + set(ARCHS i386) + set(APPLE_TARGET_TRIPLE_INT i386-apple-watchos${DEPLOYMENT_TARGET}-simulator) + else() + set(APPLE_TARGET_TRIPLE_INT ${ARCHS_SPLIT}-apple-watchos${DEPLOYMENT_TARGET}-simulator) + endif() +elseif(PLATFORM_INT STREQUAL "SIMULATORARM64_WATCHOS") + set(SDK_NAME watchsimulator) + if(NOT ARCHS) + set(ARCHS arm64) + set(APPLE_TARGET_TRIPLE_INT arm64-apple-watchos${DEPLOYMENT_TARGET}-simulator) + else() + set(APPLE_TARGET_TRIPLE_INT ${ARCHS_SPLIT}-apple-watchos${DEPLOYMENT_TARGET}-simulator) + endif() +elseif(PLATFORM_INT STREQUAL "SIMULATOR_VISIONOS") + set(SDK_NAME xrsimulator) + if(NOT ARCHS) + set(ARCHS arm64) + set(APPLE_TARGET_TRIPLE_INT arm64-apple-xros${DEPLOYMENT_TARGET}-simulator) + else() + set(APPLE_TARGET_TRIPLE_INT ${ARCHS_SPLIT}-apple-xros${DEPLOYMENT_TARGET}-simulator) + endif() +elseif(PLATFORM_INT STREQUAL "VISIONOS") + set(SDK_NAME xros) + if(NOT ARCHS) + set(ARCHS arm64) + set(APPLE_TARGET_TRIPLE_INT arm64-apple-xros${DEPLOYMENT_TARGET}) + else() + set(APPLE_TARGET_TRIPLE_INT ${ARCHS_SPLIT}-apple-xros${DEPLOYMENT_TARGET}) + endif() +elseif(PLATFORM_INT STREQUAL "VISIONOSCOMBINED") + set(SDK_NAME xros) + if(MODERN_CMAKE) + if(NOT ARCHS) + set(ARCHS arm64) + set(APPLE_TARGET_TRIPLE_INT arm64-apple-xros${DEPLOYMENT_TARGET}) + set(CMAKE_XCODE_ATTRIBUTE_ARCHS[sdk=xros*] "arm64") + set(CMAKE_XCODE_ATTRIBUTE_ARCHS[sdk=xrsimulator*] "arm64") + else() + set(APPLE_TARGET_TRIPLE_INT ${ARCHS_SPLIT}-apple-xros${DEPLOYMENT_TARGET}) + endif() + else() + message(FATAL_ERROR "Please make sure that you are running CMake 3.14+ to make the VISIONOSCOMBINED setting work") + endif() +elseif(PLATFORM_INT STREQUAL "MAC" OR PLATFORM_INT STREQUAL "MAC_CATALYST") + set(SDK_NAME macosx) + if(NOT ARCHS) + set(ARCHS x86_64) + endif() + string(REPLACE ";" "-" ARCHS_SPLIT "${ARCHS}") + if(PLATFORM_INT STREQUAL "MAC") + set(APPLE_TARGET_TRIPLE_INT ${ARCHS_SPLIT}-apple-macosx${DEPLOYMENT_TARGET}) + elseif(PLATFORM_INT STREQUAL "MAC_CATALYST") + set(APPLE_TARGET_TRIPLE_INT ${ARCHS_SPLIT}-apple-ios${DEPLOYMENT_TARGET}-macabi) + endif() +elseif(PLATFORM_INT MATCHES "^(MAC_ARM64)$|^(MAC_CATALYST_ARM64)$") + set(SDK_NAME macosx) + if(NOT ARCHS) + set(ARCHS arm64) + endif() + string(REPLACE ";" "-" ARCHS_SPLIT "${ARCHS}") + if(PLATFORM_INT STREQUAL "MAC_ARM64") + set(APPLE_TARGET_TRIPLE_INT ${ARCHS_SPLIT}-apple-macosx${DEPLOYMENT_TARGET}) + elseif(PLATFORM_INT STREQUAL "MAC_CATALYST_ARM64") + set(APPLE_TARGET_TRIPLE_INT ${ARCHS_SPLIT}-apple-ios${DEPLOYMENT_TARGET}-macabi) + endif() +elseif(PLATFORM_INT STREQUAL "MAC_UNIVERSAL") + set(SDK_NAME macosx) + if(NOT ARCHS) + set(ARCHS "x86_64;arm64") + endif() + string(REPLACE ";" "-" ARCHS_SPLIT "${ARCHS}") + set(APPLE_TARGET_TRIPLE_INT ${ARCHS_SPLIT}-apple-macosx${DEPLOYMENT_TARGET}) +elseif(PLATFORM_INT STREQUAL "MAC_CATALYST_UNIVERSAL") + set(SDK_NAME macosx) + if(NOT ARCHS) + set(ARCHS "x86_64;arm64") + endif() + string(REPLACE ";" "-" ARCHS_SPLIT "${ARCHS}") + set(APPLE_TARGET_TRIPLE_INT ${ARCHS_SPLIT}-apple-ios${DEPLOYMENT_TARGET}-macabi) +else() + message(FATAL_ERROR "Invalid PLATFORM: ${PLATFORM_INT}") +endif() + +string(REPLACE ";" " " ARCHS_SPACED "${ARCHS}") + +if(MODERN_CMAKE AND PLATFORM_INT MATCHES ".*COMBINED" AND NOT CMAKE_GENERATOR MATCHES "Xcode") + message(FATAL_ERROR "The COMBINED options only work with Xcode generator, -G Xcode") +endif() + +if(CMAKE_GENERATOR MATCHES "Xcode" AND PLATFORM_INT MATCHES "^MAC_CATALYST") + set(CMAKE_XCODE_ATTRIBUTE_CLANG_CXX_LIBRARY "libc++") + set(CMAKE_XCODE_ATTRIBUTE_SUPPORTED_PLATFORMS "macosx") + set(CMAKE_XCODE_ATTRIBUTE_SUPPORTS_MACCATALYST "YES") + if(NOT DEFINED MACOSX_DEPLOYMENT_TARGET) + set(CMAKE_XCODE_ATTRIBUTE_MACOSX_DEPLOYMENT_TARGET "10.15") + else() + set(CMAKE_XCODE_ATTRIBUTE_MACOSX_DEPLOYMENT_TARGET "${MACOSX_DEPLOYMENT_TARGET}") + endif() +elseif(CMAKE_GENERATOR MATCHES "Xcode") + set(CMAKE_XCODE_ATTRIBUTE_CLANG_CXX_LIBRARY "libc++") + set(CMAKE_XCODE_ATTRIBUTE_IPHONEOS_DEPLOYMENT_TARGET "${DEPLOYMENT_TARGET}") + if(NOT PLATFORM_INT MATCHES ".*COMBINED") + set(CMAKE_XCODE_ATTRIBUTE_ARCHS[sdk=${SDK_NAME}*] "${ARCHS_SPACED}") + set(CMAKE_XCODE_ATTRIBUTE_VALID_ARCHS[sdk=${SDK_NAME}*] "${ARCHS_SPACED}") + endif() +endif() + +# If the user did not specify the SDK root to use, then query xcodebuild for it. +if(DEFINED CMAKE_OSX_SYSROOT_INT) + # Environment variables are always preserved. + set(ENV{_CMAKE_OSX_SYSROOT_INT} "${CMAKE_OSX_SYSROOT_INT}") +elseif(DEFINED ENV{_CMAKE_OSX_SYSROOT_INT}) + set(CMAKE_OSX_SYSROOT_INT "$ENV{_CMAKE_OSX_SYSROOT_INT}") +elseif(NOT DEFINED CMAKE_OSX_SYSROOT_INT) + execute_process(COMMAND ${XCODEBUILD_EXECUTABLE} -version -sdk ${SDK_NAME} Path + OUTPUT_VARIABLE CMAKE_OSX_SYSROOT_INT + ERROR_QUIET + OUTPUT_STRIP_TRAILING_WHITESPACE) +endif() + +if (NOT DEFINED CMAKE_OSX_SYSROOT_INT AND NOT DEFINED CMAKE_OSX_SYSROOT) + message(SEND_ERROR "Please make sure that Xcode is installed and that the toolchain" + "is pointing to the correct path. Please run:" + "sudo xcode-select -s /Applications/Xcode.app/Contents/Developer" + "and see if that fixes the problem for you.") + message(FATAL_ERROR "Invalid CMAKE_OSX_SYSROOT: ${CMAKE_OSX_SYSROOT} " + "does not exist.") +elseif(DEFINED CMAKE_OSX_SYSROOT_INT) + set(CMAKE_OSX_SYSROOT_INT "${CMAKE_OSX_SYSROOT_INT}" CACHE INTERNAL "") + # Specify the location or name of the platform SDK to be used in CMAKE_OSX_SYSROOT. + set(CMAKE_OSX_SYSROOT "${CMAKE_OSX_SYSROOT_INT}" CACHE INTERNAL "") +endif() + +# Use bitcode or not +if(NOT DEFINED ENABLE_BITCODE) + message(STATUS "[DEFAULTS] Disabling bitcode support by default. ENABLE_BITCODE not provided for override!") + set(ENABLE_BITCODE OFF) +endif() +set(ENABLE_BITCODE_INT ${ENABLE_BITCODE} CACHE BOOL + "Whether or not to enable bitcode" FORCE) +# Use ARC or not +if(NOT DEFINED ENABLE_ARC) + # Unless specified, enable ARC support by default + set(ENABLE_ARC ON) + message(STATUS "[DEFAULTS] Enabling ARC support by default. ENABLE_ARC not provided!") +endif() +set(ENABLE_ARC_INT ${ENABLE_ARC} CACHE BOOL "Whether or not to enable ARC" FORCE) +# Use hidden visibility or not +if(NOT DEFINED ENABLE_VISIBILITY) + # Unless specified, disable symbols visibility by default + set(ENABLE_VISIBILITY OFF) + message(STATUS "[DEFAULTS] Hiding symbols visibility by default. ENABLE_VISIBILITY not provided!") +endif() +set(ENABLE_VISIBILITY_INT ${ENABLE_VISIBILITY} CACHE BOOL "Whether or not to hide symbols from the dynamic linker (-fvisibility=hidden)" FORCE) +# Set strict compiler checks or not +if(NOT DEFINED ENABLE_STRICT_TRY_COMPILE) + # Unless specified, disable strict try_compile() + set(ENABLE_STRICT_TRY_COMPILE OFF) + message(STATUS "[DEFAULTS] Using NON-strict compiler checks by default. ENABLE_STRICT_TRY_COMPILE not provided!") +endif() +set(ENABLE_STRICT_TRY_COMPILE_INT ${ENABLE_STRICT_TRY_COMPILE} CACHE BOOL + "Whether or not to use strict compiler checks" FORCE) + +# Get the SDK version information. +if(DEFINED SDK_VERSION) + # Environment variables are always preserved. + set(ENV{_SDK_VERSION} "${SDK_VERSION}") +elseif(DEFINED ENV{_SDK_VERSION}) + set(SDK_VERSION "$ENV{_SDK_VERSION}") +elseif(NOT DEFINED SDK_VERSION) + execute_process(COMMAND ${XCODEBUILD_EXECUTABLE} -sdk ${CMAKE_OSX_SYSROOT_INT} -version SDKVersion + OUTPUT_VARIABLE SDK_VERSION + ERROR_QUIET + OUTPUT_STRIP_TRAILING_WHITESPACE) +endif() + +# Find the Developer root for the specific iOS platform being compiled for +# from CMAKE_OSX_SYSROOT. Should be ../../ from SDK specified in +# CMAKE_OSX_SYSROOT. There does not appear to be a direct way to obtain +# this information from xcrun or xcodebuild. +if (NOT DEFINED CMAKE_DEVELOPER_ROOT AND NOT CMAKE_GENERATOR MATCHES "Xcode") + get_filename_component(PLATFORM_SDK_DIR ${CMAKE_OSX_SYSROOT_INT} PATH) + get_filename_component(CMAKE_DEVELOPER_ROOT ${PLATFORM_SDK_DIR} PATH) + if (NOT EXISTS "${CMAKE_DEVELOPER_ROOT}") + message(FATAL_ERROR "Invalid CMAKE_DEVELOPER_ROOT: ${CMAKE_DEVELOPER_ROOT} does not exist.") + endif() +endif() + +# Find the C & C++ compilers for the specified SDK. +if(DEFINED CMAKE_C_COMPILER) + # Environment variables are always preserved. + set(ENV{_CMAKE_C_COMPILER} "${CMAKE_C_COMPILER}") +elseif(DEFINED ENV{_CMAKE_C_COMPILER}) + set(CMAKE_C_COMPILER "$ENV{_CMAKE_C_COMPILER}") + set(CMAKE_ASM_COMPILER ${CMAKE_C_COMPILER}) +elseif(NOT DEFINED CMAKE_C_COMPILER) + execute_process(COMMAND xcrun -sdk ${CMAKE_OSX_SYSROOT_INT} -find clang + OUTPUT_VARIABLE CMAKE_C_COMPILER + ERROR_QUIET + OUTPUT_STRIP_TRAILING_WHITESPACE) + set(CMAKE_ASM_COMPILER ${CMAKE_C_COMPILER}) +endif() +if(DEFINED CMAKE_CXX_COMPILER) + # Environment variables are always preserved. + set(ENV{_CMAKE_CXX_COMPILER} "${CMAKE_CXX_COMPILER}") +elseif(DEFINED ENV{_CMAKE_CXX_COMPILER}) + set(CMAKE_CXX_COMPILER "$ENV{_CMAKE_CXX_COMPILER}") +elseif(NOT DEFINED CMAKE_CXX_COMPILER) + execute_process(COMMAND xcrun -sdk ${CMAKE_OSX_SYSROOT_INT} -find clang++ + OUTPUT_VARIABLE CMAKE_CXX_COMPILER + ERROR_QUIET + OUTPUT_STRIP_TRAILING_WHITESPACE) +endif() +# Find (Apple's) libtool. +if(DEFINED BUILD_LIBTOOL) + # Environment variables are always preserved. + set(ENV{_BUILD_LIBTOOL} "${BUILD_LIBTOOL}") +elseif(DEFINED ENV{_BUILD_LIBTOOL}) + set(BUILD_LIBTOOL "$ENV{_BUILD_LIBTOOL}") +elseif(NOT DEFINED BUILD_LIBTOOL) + execute_process(COMMAND xcrun -sdk ${CMAKE_OSX_SYSROOT_INT} -find libtool + OUTPUT_VARIABLE BUILD_LIBTOOL + ERROR_QUIET + OUTPUT_STRIP_TRAILING_WHITESPACE) +endif() +# Find the toolchain's provided install_name_tool if none is found on the host +if(DEFINED CMAKE_INSTALL_NAME_TOOL) + # Environment variables are always preserved. + set(ENV{_CMAKE_INSTALL_NAME_TOOL} "${CMAKE_INSTALL_NAME_TOOL}") +elseif(DEFINED ENV{_CMAKE_INSTALL_NAME_TOOL}) + set(CMAKE_INSTALL_NAME_TOOL "$ENV{_CMAKE_INSTALL_NAME_TOOL}") +elseif(NOT DEFINED CMAKE_INSTALL_NAME_TOOL) + execute_process(COMMAND xcrun -sdk ${CMAKE_OSX_SYSROOT_INT} -find install_name_tool + OUTPUT_VARIABLE CMAKE_INSTALL_NAME_TOOL_INT + ERROR_QUIET + OUTPUT_STRIP_TRAILING_WHITESPACE) + set(CMAKE_INSTALL_NAME_TOOL ${CMAKE_INSTALL_NAME_TOOL_INT} CACHE INTERNAL "") +endif() + +# Configure libtool to be used instead of ar + ranlib to build static libraries. +# This is required on Xcode 7+, but should also work on previous versions of +# Xcode. +get_property(languages GLOBAL PROPERTY ENABLED_LANGUAGES) +foreach(lang ${languages}) + set(CMAKE_${lang}_CREATE_STATIC_LIBRARY "${BUILD_LIBTOOL} -static -o " CACHE INTERNAL "") +endforeach() + +# CMake 3.14+ support building for iOS, watchOS, and tvOS out of the box. +if(MODERN_CMAKE) + if(SDK_NAME MATCHES "iphone") + set(CMAKE_SYSTEM_NAME iOS) + elseif(SDK_NAME MATCHES "xros") + set(CMAKE_SYSTEM_NAME visionOS) + elseif(SDK_NAME MATCHES "xrsimulator") + set(CMAKE_SYSTEM_NAME visionOS) + elseif(SDK_NAME MATCHES "macosx") + set(CMAKE_SYSTEM_NAME Darwin) + elseif(SDK_NAME MATCHES "appletv") + set(CMAKE_SYSTEM_NAME tvOS) + elseif(SDK_NAME MATCHES "watch") + set(CMAKE_SYSTEM_NAME watchOS) + endif() + # Provide flags for a combined FAT library build on newer CMake versions + if(PLATFORM_INT MATCHES ".*COMBINED") + set(CMAKE_IOS_INSTALL_COMBINED YES) + if(CMAKE_GENERATOR MATCHES "Xcode") + # Set the SDKROOT Xcode properties to a Xcode-friendly value (the SDK_NAME, E.g, iphoneos) + # This way, Xcode will automatically switch between the simulator and device SDK when building. + set(CMAKE_XCODE_ATTRIBUTE_SDKROOT "${SDK_NAME}") + # Force to not build just one ARCH, but all! + set(CMAKE_XCODE_ATTRIBUTE_ONLY_ACTIVE_ARCH "NO") + endif() + endif() +elseif(NOT DEFINED CMAKE_SYSTEM_NAME AND ${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.10") + # Legacy code path prior to CMake 3.14 or fallback if no CMAKE_SYSTEM_NAME specified + set(CMAKE_SYSTEM_NAME iOS) +elseif(NOT DEFINED CMAKE_SYSTEM_NAME) + # Legacy code path before CMake 3.14 or fallback if no CMAKE_SYSTEM_NAME specified + set(CMAKE_SYSTEM_NAME Darwin) +endif() +# Standard settings. +set(CMAKE_SYSTEM_VERSION ${SDK_VERSION} CACHE INTERNAL "") +set(UNIX ON CACHE BOOL "") +set(APPLE ON CACHE BOOL "") +if(PLATFORM STREQUAL "MAC" OR PLATFORM STREQUAL "MAC_ARM64" OR PLATFORM STREQUAL "MAC_UNIVERSAL") + set(IOS OFF CACHE BOOL "") + set(MACOS ON CACHE BOOL "") +elseif(PLATFORM STREQUAL "MAC_CATALYST" OR PLATFORM STREQUAL "MAC_CATALYST_ARM64" OR PLATFORM STREQUAL "MAC_CATALYST_UNIVERSAL") + set(IOS ON CACHE BOOL "") + set(MACOS ON CACHE BOOL "") +elseif(PLATFORM STREQUAL "VISIONOS" OR PLATFORM STREQUAL "SIMULATOR_VISIONOS" OR PLATFORM STREQUAL "VISIONOSCOMBINED") + set(IOS OFF CACHE BOOL "") + set(VISIONOS ON CACHE BOOL "") +else() + set(IOS ON CACHE BOOL "") +endif() +# Set the architectures for which to build. +set(CMAKE_OSX_ARCHITECTURES ${ARCHS} CACHE INTERNAL "") +# Change the type of target generated for try_compile() so it'll work when cross-compiling, weak compiler checks +if(NOT ENABLE_STRICT_TRY_COMPILE_INT) + set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY) +endif() +# All iOS/Darwin specific settings - some may be redundant. +if (NOT DEFINED CMAKE_MACOSX_BUNDLE) + set(CMAKE_MACOSX_BUNDLE YES) +endif() +set(CMAKE_XCODE_ATTRIBUTE_CODE_SIGNING_REQUIRED "NO") +set(CMAKE_XCODE_ATTRIBUTE_CODE_SIGNING_ALLOWED "NO") +set(CMAKE_SHARED_LIBRARY_PREFIX "lib") +set(CMAKE_SHARED_LIBRARY_SUFFIX ".dylib") +set(CMAKE_EXTRA_SHARED_LIBRARY_SUFFIXES ".tbd" ".so") +set(CMAKE_SHARED_MODULE_PREFIX "lib") +set(CMAKE_SHARED_MODULE_SUFFIX ".so") +set(CMAKE_C_COMPILER_ABI ELF) +set(CMAKE_CXX_COMPILER_ABI ELF) +set(CMAKE_C_HAS_ISYSROOT 1) +set(CMAKE_CXX_HAS_ISYSROOT 1) +set(CMAKE_MODULE_EXISTS 1) +set(CMAKE_DL_LIBS "") +set(CMAKE_C_OSX_COMPATIBILITY_VERSION_FLAG "-compatibility_version ") +set(CMAKE_C_OSX_CURRENT_VERSION_FLAG "-current_version ") +set(CMAKE_CXX_OSX_COMPATIBILITY_VERSION_FLAG "${CMAKE_C_OSX_COMPATIBILITY_VERSION_FLAG}") +set(CMAKE_CXX_OSX_CURRENT_VERSION_FLAG "${CMAKE_C_OSX_CURRENT_VERSION_FLAG}") + +if(ARCHS MATCHES "((^|;|, )(arm64|arm64e|x86_64))+") + set(CMAKE_C_SIZEOF_DATA_PTR 8) + set(CMAKE_CXX_SIZEOF_DATA_PTR 8) + if(ARCHS MATCHES "((^|;|, )(arm64|arm64e))+") + set(CMAKE_SYSTEM_PROCESSOR "aarch64") + else() + set(CMAKE_SYSTEM_PROCESSOR "x86_64") + endif() +else() + set(CMAKE_C_SIZEOF_DATA_PTR 4) + set(CMAKE_CXX_SIZEOF_DATA_PTR 4) + set(CMAKE_SYSTEM_PROCESSOR "arm") +endif() + +# Note that only Xcode 7+ supports the newer more specific: +# -m${SDK_NAME}-version-min flags, older versions of Xcode use: +# -m(ios/ios-simulator)-version-min instead. +if(${CMAKE_VERSION} VERSION_LESS "3.11") + if(PLATFORM_INT STREQUAL "OS" OR PLATFORM_INT STREQUAL "OS64") + if(XCODE_VERSION_INT VERSION_LESS 7.0) + set(SDK_NAME_VERSION_FLAGS + "-mios-version-min=${DEPLOYMENT_TARGET}") + else() + # Xcode 7.0+ uses flags we can build directly from SDK_NAME. + set(SDK_NAME_VERSION_FLAGS + "-m${SDK_NAME}-version-min=${DEPLOYMENT_TARGET}") + endif() + elseif(PLATFORM_INT STREQUAL "TVOS") + set(SDK_NAME_VERSION_FLAGS + "-mtvos-version-min=${DEPLOYMENT_TARGET}") + elseif(PLATFORM_INT STREQUAL "SIMULATOR_TVOS") + set(SDK_NAME_VERSION_FLAGS + "-mtvos-simulator-version-min=${DEPLOYMENT_TARGET}") +elseif(PLATFORM_INT STREQUAL "SIMULATORARM64_TVOS") + set(SDK_NAME_VERSION_FLAGS + "-mtvos-simulator-version-min=${DEPLOYMENT_TARGET}") + elseif(PLATFORM_INT STREQUAL "WATCHOS") + set(SDK_NAME_VERSION_FLAGS + "-mwatchos-version-min=${DEPLOYMENT_TARGET}") + elseif(PLATFORM_INT STREQUAL "SIMULATOR_WATCHOS") + set(SDK_NAME_VERSION_FLAGS + "-mwatchos-simulator-version-min=${DEPLOYMENT_TARGET}") + elseif(PLATFORM_INT STREQUAL "SIMULATORARM64_WATCHOS") + set(SDK_NAME_VERSION_FLAGS + "-mwatchos-simulator-version-min=${DEPLOYMENT_TARGET}") + elseif(PLATFORM_INT STREQUAL "MAC") + set(SDK_NAME_VERSION_FLAGS + "-mmacosx-version-min=${DEPLOYMENT_TARGET}") + else() + # SIMULATOR or SIMULATOR64 both use -mios-simulator-version-min. + set(SDK_NAME_VERSION_FLAGS + "-mios-simulator-version-min=${DEPLOYMENT_TARGET}") + endif() +elseif(NOT PLATFORM_INT MATCHES "^MAC_CATALYST") + # Newer versions of CMake sets the version min flags correctly, skip this for Mac Catalyst targets + set(CMAKE_OSX_DEPLOYMENT_TARGET ${DEPLOYMENT_TARGET} CACHE INTERNAL "Minimum OS X deployment version") +endif() + +if(DEFINED APPLE_TARGET_TRIPLE_INT) + set(APPLE_TARGET_TRIPLE ${APPLE_TARGET_TRIPLE_INT} CACHE INTERNAL "") + set(CMAKE_C_COMPILER_TARGET ${APPLE_TARGET_TRIPLE}) + set(CMAKE_CXX_COMPILER_TARGET ${APPLE_TARGET_TRIPLE}) + set(CMAKE_ASM_COMPILER_TARGET ${APPLE_TARGET_TRIPLE}) +endif() + +if(PLATFORM_INT MATCHES "^MAC_CATALYST") + set(C_TARGET_FLAGS "-isystem ${CMAKE_OSX_SYSROOT_INT}/System/iOSSupport/usr/include -iframework ${CMAKE_OSX_SYSROOT_INT}/System/iOSSupport/System/Library/Frameworks") +endif() + +if(ENABLE_BITCODE_INT) + set(BITCODE "-fembed-bitcode") + set(CMAKE_XCODE_ATTRIBUTE_BITCODE_GENERATION_MODE "bitcode") + set(CMAKE_XCODE_ATTRIBUTE_ENABLE_BITCODE "YES") +else() + set(BITCODE "") + set(CMAKE_XCODE_ATTRIBUTE_ENABLE_BITCODE "NO") +endif() + +if(ENABLE_ARC_INT) + set(FOBJC_ARC "-fobjc-arc") + set(CMAKE_XCODE_ATTRIBUTE_CLANG_ENABLE_OBJC_ARC "YES") +else() + set(FOBJC_ARC "-fno-objc-arc") + set(CMAKE_XCODE_ATTRIBUTE_CLANG_ENABLE_OBJC_ARC "NO") +endif() + +if(NAMED_LANGUAGE_SUPPORT_INT) + set(OBJC_VARS "-fobjc-abi-version=2 -DOBJC_OLD_DISPATCH_PROTOTYPES=0") + set(OBJC_LEGACY_VARS "") +else() + set(OBJC_VARS "") + set(OBJC_LEGACY_VARS "-fobjc-abi-version=2 -DOBJC_OLD_DISPATCH_PROTOTYPES=0") +endif() + +if(NOT ENABLE_VISIBILITY_INT) + foreach(lang ${languages}) + set(CMAKE_${lang}_VISIBILITY_PRESET "hidden" CACHE INTERNAL "") + endforeach() + set(CMAKE_XCODE_ATTRIBUTE_GCC_SYMBOLS_PRIVATE_EXTERN "YES") + set(VISIBILITY "-fvisibility=hidden -fvisibility-inlines-hidden") +else() + foreach(lang ${languages}) + set(CMAKE_${lang}_VISIBILITY_PRESET "default" CACHE INTERNAL "") + endforeach() + set(CMAKE_XCODE_ATTRIBUTE_GCC_SYMBOLS_PRIVATE_EXTERN "NO") + set(VISIBILITY "-fvisibility=default") +endif() + +if(DEFINED APPLE_TARGET_TRIPLE) + set(APPLE_TARGET_TRIPLE_FLAG "-target ${APPLE_TARGET_TRIPLE}") +endif() + +#Check if Xcode generator is used since that will handle these flags automagically +if(CMAKE_GENERATOR MATCHES "Xcode") + message(STATUS "Not setting any manual command-line buildflags, since Xcode is selected as the generator. Modifying the Xcode build-settings directly instead.") +else() + set(CMAKE_C_FLAGS "${C_TARGET_FLAGS} ${APPLE_TARGET_TRIPLE_FLAG} ${SDK_NAME_VERSION_FLAGS} ${OBJC_LEGACY_VARS} ${BITCODE} ${VISIBILITY} ${CMAKE_C_FLAGS}" CACHE INTERNAL + "Flags used by the compiler during all C build types.") + set(CMAKE_C_FLAGS_DEBUG "-O0 -g ${CMAKE_C_FLAGS_DEBUG}") + set(CMAKE_C_FLAGS_MINSIZEREL "-DNDEBUG -Os ${CMAKE_C_FLAGS_MINSIZEREL}") + set(CMAKE_C_FLAGS_RELWITHDEBINFO "-DNDEBUG -O2 -g ${CMAKE_C_FLAGS_RELWITHDEBINFO}") + set(CMAKE_C_FLAGS_RELEASE "-DNDEBUG -O3 ${CMAKE_C_FLAGS_RELEASE}") + set(CMAKE_CXX_FLAGS "${C_TARGET_FLAGS} ${APPLE_TARGET_TRIPLE_FLAG} ${SDK_NAME_VERSION_FLAGS} ${OBJC_LEGACY_VARS} ${BITCODE} ${VISIBILITY} ${CMAKE_CXX_FLAGS}" CACHE INTERNAL + "Flags used by the compiler during all CXX build types.") + set(CMAKE_CXX_FLAGS_DEBUG "-O0 -g ${CMAKE_CXX_FLAGS_DEBUG}") + set(CMAKE_CXX_FLAGS_MINSIZEREL "-DNDEBUG -Os ${CMAKE_CXX_FLAGS_MINSIZEREL}") + set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "-DNDEBUG -O2 -g ${CMAKE_CXX_FLAGS_RELWITHDEBINFO}") + set(CMAKE_CXX_FLAGS_RELEASE "-DNDEBUG -O3 ${CMAKE_CXX_FLAGS_RELEASE}") + if(NAMED_LANGUAGE_SUPPORT_INT) + set(CMAKE_OBJC_FLAGS "${C_TARGET_FLAGS} ${APPLE_TARGET_TRIPLE_FLAG} ${SDK_NAME_VERSION_FLAGS} ${BITCODE} ${VISIBILITY} ${FOBJC_ARC} ${OBJC_VARS} ${CMAKE_OBJC_FLAGS}" CACHE INTERNAL + "Flags used by the compiler during all OBJC build types.") + set(CMAKE_OBJC_FLAGS_DEBUG "-O0 -g ${CMAKE_OBJC_FLAGS_DEBUG}") + set(CMAKE_OBJC_FLAGS_MINSIZEREL "-DNDEBUG -Os ${CMAKE_OBJC_FLAGS_MINSIZEREL}") + set(CMAKE_OBJC_FLAGS_RELWITHDEBINFO "-DNDEBUG -O2 -g ${CMAKE_OBJC_FLAGS_RELWITHDEBINFO}") + set(CMAKE_OBJC_FLAGS_RELEASE "-DNDEBUG -O3 ${CMAKE_OBJC_FLAGS_RELEASE}") + set(CMAKE_OBJCXX_FLAGS "${C_TARGET_FLAGS} ${APPLE_TARGET_TRIPLE_FLAG} ${SDK_NAME_VERSION_FLAGS} ${BITCODE} ${VISIBILITY} ${FOBJC_ARC} ${OBJC_VARS} ${CMAKE_OBJCXX_FLAGS}" CACHE INTERNAL + "Flags used by the compiler during all OBJCXX build types.") + set(CMAKE_OBJCXX_FLAGS_DEBUG "-O0 -g ${CMAKE_OBJCXX_FLAGS_DEBUG}") + set(CMAKE_OBJCXX_FLAGS_MINSIZEREL "-DNDEBUG -Os ${CMAKE_OBJCXX_FLAGS_MINSIZEREL}") + set(CMAKE_OBJCXX_FLAGS_RELWITHDEBINFO "-DNDEBUG -O2 -g ${CMAKE_OBJCXX_FLAGS_RELWITHDEBINFO}") + set(CMAKE_OBJCXX_FLAGS_RELEASE "-DNDEBUG -O3 ${CMAKE_OBJCXX_FLAGS_RELEASE}") + endif() + set(CMAKE_C_LINK_FLAGS "${C_TARGET_FLAGS} ${SDK_NAME_VERSION_FLAGS} -Wl,-search_paths_first ${CMAKE_C_LINK_FLAGS}" CACHE INTERNAL + "Flags used by the compiler for all C link types.") + set(CMAKE_CXX_LINK_FLAGS "${C_TARGET_FLAGS} ${SDK_NAME_VERSION_FLAGS} -Wl,-search_paths_first ${CMAKE_CXX_LINK_FLAGS}" CACHE INTERNAL + "Flags used by the compiler for all CXX link types.") + if(NAMED_LANGUAGE_SUPPORT_INT) + set(CMAKE_OBJC_LINK_FLAGS "${C_TARGET_FLAGS} ${SDK_NAME_VERSION_FLAGS} -Wl,-search_paths_first ${CMAKE_OBJC_LINK_FLAGS}" CACHE INTERNAL + "Flags used by the compiler for all OBJC link types.") + set(CMAKE_OBJCXX_LINK_FLAGS "${C_TARGET_FLAGS} ${SDK_NAME_VERSION_FLAGS} -Wl,-search_paths_first ${CMAKE_OBJCXX_LINK_FLAGS}" CACHE INTERNAL + "Flags used by the compiler for all OBJCXX link types.") + endif() + set(CMAKE_ASM_FLAGS "${CMAKE_C_FLAGS} -x assembler-with-cpp -arch ${CMAKE_OSX_ARCHITECTURES} ${APPLE_TARGET_TRIPLE_FLAG}" CACHE INTERNAL + "Flags used by the compiler for all ASM build types.") +endif() + +## Print status messages to inform of the current state +message(STATUS "Configuring ${SDK_NAME} build for platform: ${PLATFORM_INT}, architecture(s): ${ARCHS}") +message(STATUS "Using SDK: ${CMAKE_OSX_SYSROOT_INT}") +message(STATUS "Using C compiler: ${CMAKE_C_COMPILER}") +message(STATUS "Using CXX compiler: ${CMAKE_CXX_COMPILER}") +message(STATUS "Using libtool: ${BUILD_LIBTOOL}") +message(STATUS "Using install name tool: ${CMAKE_INSTALL_NAME_TOOL}") +if(DEFINED APPLE_TARGET_TRIPLE) + message(STATUS "Autoconf target triple: ${APPLE_TARGET_TRIPLE}") +endif() +message(STATUS "Using minimum deployment version: ${DEPLOYMENT_TARGET}" + " (SDK version: ${SDK_VERSION})") +if(MODERN_CMAKE) + message(STATUS "Merging integrated CMake 3.14+ iOS,tvOS,watchOS,macOS toolchain(s) with this toolchain!") + if(PLATFORM_INT MATCHES ".*COMBINED") + message(STATUS "Will combine built (static) artifacts into FAT lib...") + endif() +endif() +if(CMAKE_GENERATOR MATCHES "Xcode") + message(STATUS "Using Xcode version: ${XCODE_VERSION_INT}") +endif() +message(STATUS "CMake version: ${CMAKE_VERSION}") +if(DEFINED SDK_NAME_VERSION_FLAGS) + message(STATUS "Using version flags: ${SDK_NAME_VERSION_FLAGS}") +endif() +message(STATUS "Using a data_ptr size of: ${CMAKE_CXX_SIZEOF_DATA_PTR}") +if(ENABLE_BITCODE_INT) + message(STATUS "Bitcode: Enabled") +else() + message(STATUS "Bitcode: Disabled") +endif() + +if(ENABLE_ARC_INT) + message(STATUS "ARC: Enabled") +else() + message(STATUS "ARC: Disabled") +endif() + +if(ENABLE_VISIBILITY_INT) + message(STATUS "Hiding symbols: Disabled") +else() + message(STATUS "Hiding symbols: Enabled") +endif() + +# Set global properties +set_property(GLOBAL PROPERTY PLATFORM "${PLATFORM}") +set_property(GLOBAL PROPERTY APPLE_TARGET_TRIPLE "${APPLE_TARGET_TRIPLE_INT}") +set_property(GLOBAL PROPERTY SDK_VERSION "${SDK_VERSION}") +set_property(GLOBAL PROPERTY XCODE_VERSION "${XCODE_VERSION_INT}") +set_property(GLOBAL PROPERTY OSX_ARCHITECTURES "${CMAKE_OSX_ARCHITECTURES}") + +# Export configurable variables for the try_compile() command. +set(CMAKE_TRY_COMPILE_PLATFORM_VARIABLES + PLATFORM + XCODE_VERSION_INT + SDK_VERSION + NAMED_LANGUAGE_SUPPORT + DEPLOYMENT_TARGET + CMAKE_DEVELOPER_ROOT + CMAKE_OSX_SYSROOT_INT + ENABLE_BITCODE + ENABLE_ARC + CMAKE_ASM_COMPILER + CMAKE_C_COMPILER + CMAKE_C_COMPILER_TARGET + CMAKE_CXX_COMPILER + CMAKE_CXX_COMPILER_TARGET + BUILD_LIBTOOL + CMAKE_INSTALL_NAME_TOOL + CMAKE_C_FLAGS + CMAKE_C_DEBUG + CMAKE_C_MINSIZEREL + CMAKE_C_RELWITHDEBINFO + CMAKE_C_RELEASE + CMAKE_CXX_FLAGS + CMAKE_CXX_FLAGS_DEBUG + CMAKE_CXX_FLAGS_MINSIZEREL + CMAKE_CXX_FLAGS_RELWITHDEBINFO + CMAKE_CXX_FLAGS_RELEASE + CMAKE_C_LINK_FLAGS + CMAKE_CXX_LINK_FLAGS + CMAKE_ASM_FLAGS +) + +if(NAMED_LANGUAGE_SUPPORT_INT) + list(APPEND CMAKE_TRY_COMPILE_PLATFORM_VARIABLES + CMAKE_OBJC_FLAGS + CMAKE_OBJC_DEBUG + CMAKE_OBJC_MINSIZEREL + CMAKE_OBJC_RELWITHDEBINFO + CMAKE_OBJC_RELEASE + CMAKE_OBJCXX_FLAGS + CMAKE_OBJCXX_DEBUG + CMAKE_OBJCXX_MINSIZEREL + CMAKE_OBJCXX_RELWITHDEBINFO + CMAKE_OBJCXX_RELEASE + CMAKE_OBJC_LINK_FLAGS + CMAKE_OBJCXX_LINK_FLAGS + ) +endif() + +set(CMAKE_PLATFORM_HAS_INSTALLNAME 1) +set(CMAKE_SHARED_LINKER_FLAGS "-rpath @executable_path/Frameworks -rpath @loader_path/Frameworks") +set(CMAKE_SHARED_LIBRARY_CREATE_C_FLAGS "-dynamiclib -Wl,-headerpad_max_install_names") +set(CMAKE_SHARED_MODULE_CREATE_C_FLAGS "-bundle -Wl,-headerpad_max_install_names") +set(CMAKE_SHARED_MODULE_LOADER_C_FLAG "-Wl,-bundle_loader,") +set(CMAKE_SHARED_MODULE_LOADER_CXX_FLAG "-Wl,-bundle_loader,") +set(CMAKE_FIND_LIBRARY_SUFFIXES ".tbd" ".dylib" ".so" ".a") +set(CMAKE_SHARED_LIBRARY_SONAME_C_FLAG "-install_name") + +# Set the find root to the SDK developer roots. +# Note: CMAKE_FIND_ROOT_PATH is only useful when cross-compiling. Thus, do not set on macOS builds. +if(NOT PLATFORM_INT MATCHES "^MAC.*$") + list(APPEND CMAKE_FIND_ROOT_PATH "${CMAKE_OSX_SYSROOT_INT}" CACHE INTERNAL "") + set(CMAKE_IGNORE_PATH "/System/Library/Frameworks;/usr/local/lib;/opt/homebrew" CACHE INTERNAL "") +endif() + +# Default to searching for frameworks first. +IF(NOT DEFINED CMAKE_FIND_FRAMEWORK) + set(CMAKE_FIND_FRAMEWORK FIRST) +ENDIF(NOT DEFINED CMAKE_FIND_FRAMEWORK) + +# Set up the default search directories for frameworks. +if(PLATFORM_INT MATCHES "^MAC_CATALYST") + set(CMAKE_FRAMEWORK_PATH + ${CMAKE_DEVELOPER_ROOT}/Library/PrivateFrameworks + ${CMAKE_OSX_SYSROOT_INT}/System/Library/Frameworks + ${CMAKE_OSX_SYSROOT_INT}/System/iOSSupport/System/Library/Frameworks + ${CMAKE_FRAMEWORK_PATH} CACHE INTERNAL "") +else() + set(CMAKE_FRAMEWORK_PATH + ${CMAKE_DEVELOPER_ROOT}/Library/PrivateFrameworks + ${CMAKE_OSX_SYSROOT_INT}/System/Library/Frameworks + ${CMAKE_FRAMEWORK_PATH} CACHE INTERNAL "") +endif() + +# By default, search both the specified iOS SDK and the remainder of the host filesystem. +if(NOT CMAKE_FIND_ROOT_PATH_MODE_PROGRAM) + set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM BOTH CACHE INTERNAL "") +endif() +if(NOT CMAKE_FIND_ROOT_PATH_MODE_LIBRARY) + set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY BOTH CACHE INTERNAL "") +endif() +if(NOT CMAKE_FIND_ROOT_PATH_MODE_INCLUDE) + set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE BOTH CACHE INTERNAL "") +endif() +if(NOT CMAKE_FIND_ROOT_PATH_MODE_PACKAGE) + set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE BOTH CACHE INTERNAL "") +endif() + +# +# Some helper-macros below to simplify and beautify the CMakeFile +# + +# This little macro lets you set any Xcode specific property. +macro(set_xcode_property TARGET XCODE_PROPERTY XCODE_VALUE XCODE_RELVERSION) + set(XCODE_RELVERSION_I "${XCODE_RELVERSION}") + if(XCODE_RELVERSION_I STREQUAL "All") + set_property(TARGET ${TARGET} PROPERTY XCODE_ATTRIBUTE_${XCODE_PROPERTY} "${XCODE_VALUE}") + else() + set_property(TARGET ${TARGET} PROPERTY XCODE_ATTRIBUTE_${XCODE_PROPERTY}[variant=${XCODE_RELVERSION_I}] "${XCODE_VALUE}") + endif() +endmacro(set_xcode_property) + +# This macro lets you find executable programs on the host system. +macro(find_host_package) + set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) + set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY NEVER) + set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE NEVER) + set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE NEVER) + set(_TOOLCHAIN_IOS ${IOS}) + set(IOS OFF) + find_package(${ARGN}) + set(IOS ${_TOOLCHAIN_IOS}) + set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM BOTH) + set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY BOTH) + set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE BOTH) + set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE BOTH) +endmacro(find_host_package) +# gersemi: on diff --git a/cmake/linux.cmake b/cmake/linux.cmake index 15855099..f01d75da 100644 --- a/cmake/linux.cmake +++ b/cmake/linux.cmake @@ -6,16 +6,33 @@ This file contains functions for options and configuration for targeting the Linux platform ]=======================================================================] -function( linux_options ) - # Linux Options + +#[=============================[ Linux Options ]=============================] +function(linux_options) + #[[ Options from SCons + use_llvm : Use the LLVM compiler + Not implemented as compiler selection is managed by CMake. Look to + doc/cmake.rst for examples. + ]] + option(GODOTCPP_USE_STATIC_CPP "Link libgcc and libstdc++ statically for better portability" ON) endfunction() -function( linux_generate ) - target_compile_definitions( ${TARGET_NAME} - PUBLIC - LINUX_ENABLED - UNIX_ENABLED +#[===========================[ Target Generation ]===========================] +function(linux_generate) + set(STATIC_CPP "$") + + target_compile_definitions(godot-cpp PUBLIC LINUX_ENABLED UNIX_ENABLED) + + # gersemi: off + target_link_options( + godot-cpp + PUBLIC + $<${STATIC_CPP}: + -static-libgcc + -static-libstdc++ + > ) + # gersemi: on common_compiler_flags() endfunction() diff --git a/cmake/macos.cmake b/cmake/macos.cmake index d3271ad1..33db862d 100644 --- a/cmake/macos.cmake +++ b/cmake/macos.cmake @@ -5,42 +5,37 @@ MacOS This file contains functions for options and configuration for targeting the MacOS platform -# To build universal binaries, ie targeting both x86_64 and arm64, use -# the CMAKE_OSX_ARCHITECTURES variable prior to any project calls. -# https://cmake.org/cmake/help/latest/variable/CMAKE_OSX_ARCHITECTURES.html +Universal Builds +---------------- + +To build universal binaries, ie targeting both x86_64 and arm64, use +the CMAKE_OSX_ARCHITECTURES variable prior to any project calls. +https://cmake.org/cmake/help/latest/variable/CMAKE_OSX_ARCHITECTURES.html ]=======================================================================] # Find Requirements -IF(APPLE) - set( CMAKE_OSX_SYSROOT $ENV{SDKROOT} ) - find_library( COCOA_LIBRARY REQUIRED - NAMES Cocoa - PATHS ${CMAKE_OSX_SYSROOT}/System/Library - PATH_SUFFIXES Frameworks - NO_DEFAULT_PATH) -ENDIF (APPLE) - -function( macos_options ) +if(APPLE) + set(CMAKE_OSX_SYSROOT $ENV{SDKROOT}) +endif(APPLE) + +#[=============================[ MacOS Options ]=============================] +function(macos_options) + #[[ Options from SCons + TODO macos_deployment_target: macOS deployment target + Default: 'default' + + TODO macos_sdk_path: macOS SDK path + Default: '' + + TODO osxcross_sdk: OSXCross SDK version + Default: if has_osxcross(): "darwin16" else None + ]] endfunction() -function( macos_generate ) - - target_compile_definitions(${TARGET_NAME} - PUBLIC - MACOS_ENABLED - UNIX_ENABLED - ) - - target_link_options( ${TARGET_NAME} - PUBLIC - -Wl,-undefined,dynamic_lookup - ) - - target_link_libraries( ${TARGET_NAME} - INTERFACE - ${COCOA_LIBRARY} - ) +#[===========================[ Target Generation ]===========================] +function(macos_generate) + target_compile_definitions(godot-cpp PUBLIC MACOS_ENABLED UNIX_ENABLED) common_compiler_flags() endfunction() diff --git a/cmake/web.cmake b/cmake/web.cmake index 996a1e52..819aa89a 100644 --- a/cmake/web.cmake +++ b/cmake/web.cmake @@ -8,30 +8,27 @@ Web platform ]=======================================================================] # Emscripten requires this hack for use of the SHARED option -set( CMAKE_PROJECT_godot-cpp_INCLUDE cmake/emsdkHack.cmake ) +set(CMAKE_PROJECT_godot-cpp_INCLUDE cmake/emsdkHack.cmake) -function( web_options ) - # web options +#[==============================[ Web Options ]==============================] +function(web_options) endfunction() +#[===========================[ Target Generation ]===========================] +function(web_generate) + target_compile_definitions(godot-cpp PUBLIC WEB_ENABLED UNIX_ENABLED) -function( web_generate ) - target_compile_definitions(${TARGET_NAME} - PUBLIC - WEB_ENABLED - UNIX_ENABLED - ) - - target_compile_options( ${TARGET_NAME} - PUBLIC + target_compile_options( + godot-cpp + PUBLIC # -sSIDE_MODULE -sSUPPORT_LONGJMP=wasm - -fno-exceptions $<${THREADS_ENABLED}:-sUSE_PTHREADS=1> ) - target_link_options( ${TARGET_NAME} - INTERFACE + target_link_options( + godot-cpp + INTERFACE # -sWASM_BIGINT -sSUPPORT_LONGJMP=wasm -fvisibility=hidden diff --git a/cmake/windows.cmake b/cmake/windows.cmake index 8e37e7e4..75ae4707 100644 --- a/cmake/windows.cmake +++ b/cmake/windows.cmake @@ -53,40 +53,52 @@ documentation. .. _issues: https://github.com/godotengine/godot-cpp/issues/1699 ]=======================================================================] -function( windows_options ) - option( GODOTCPP_USE_STATIC_CPP "Link MinGW/MSVC C++ runtime libraries statically" ON ) - option( GODOTCPP_DEBUG_CRT "Compile with MSVC's debug CRT (/MDd)" OFF ) - message( STATUS "If not already cached, setting CMAKE_MSVC_RUNTIME_LIBRARY.\n" - "\tFor more information please read godot-cpp/cmake/windows.cmake") +#[============================[ Windows Options ]============================] +function(windows_options) + #[[ Options from SCons - set( CMAKE_MSVC_RUNTIME_LIBRARY - "MultiThreaded$,DebugDLL,$<$>:DLL>>" - CACHE STRING "Select the MSVC runtime library for use by compilers targeting the MSVC ABI.") -endfunction() + TODO silence_msvc: Silence MSVC's cl/link stdout bloat, redirecting errors to stderr + Default: True + These three options will not implemented as compiler selection is managed + by CMake toolchain files. Look to doc/cmake.rst for examples. + use_mingw: Use the MinGW compiler instead of MSVC - only effective on Windows + use_llvm: Use the LLVM compiler (MVSC or MinGW depending on the use_mingw flag + mingw_prefix: MinGW prefix + ]] -#[===========================[ Target Generation ]===========================] -function( windows_generate ) - set( STATIC_CPP "$") + option(GODOTCPP_USE_STATIC_CPP "Link MinGW/MSVC C++ runtime libraries statically" ON) + option(GODOTCPP_DEBUG_CRT "Compile with MSVC's debug CRT (/MDd)" OFF) - set_target_properties( ${TARGET_NAME} - PROPERTIES - PDB_OUTPUT_DIRECTORY "$<1:${CMAKE_SOURCE_DIR}/bin>" + message( + STATUS + "If not already cached, setting CMAKE_MSVC_RUNTIME_LIBRARY.\n" + "\tFor more information please read godot-cpp/cmake/windows.cmake" ) - target_compile_definitions( ${TARGET_NAME} - PUBLIC - WINDOWS_ENABLED - $<${IS_MSVC}: - TYPED_METHOD_BIND - NOMINMAX - > + set(CMAKE_MSVC_RUNTIME_LIBRARY + "MultiThreaded$,DebugDLL,$<$>:DLL>>" + CACHE STRING + "Select the MSVC runtime library for use by compilers targeting the MSVC ABI." ) +endfunction() - target_link_options( ${TARGET_NAME} - PUBLIC +#[===========================[ Target Generation ]===========================] +function(windows_generate) + set(STATIC_CPP "$") + + set_target_properties(godot-cpp PROPERTIES PDB_OUTPUT_DIRECTORY "$<1:${CMAKE_SOURCE_DIR}/bin>") + target_compile_definitions( + godot-cpp + PUBLIC WINDOWS_ENABLED $<${IS_MSVC}: TYPED_METHOD_BIND NOMINMAX > + ) + + # gersemi: off + target_link_options( + godot-cpp + PUBLIC $<${NOT_MSVC}: -Wl,--no-undefined $<${STATIC_CPP}: @@ -98,6 +110,7 @@ function( windows_generate ) $<${IS_CLANG}:-lstdc++> ) + # gersemi: on common_compiler_flags() endfunction() diff --git a/doc/cmake.rst b/doc/cmake.rst index 8045aa64..760d4561 100644 --- a/doc/cmake.rst +++ b/doc/cmake.rst @@ -24,6 +24,38 @@ Configuration examples are listed at the bottom of the page. .. _godot-cpp-template: https://github.com/godotengine/godot-cpp-template +Debug vs template_debug +----------------------- + +Something I've seen come up many times is the conflation of a compilation of c++ +source code with debug symbols enabled, and compiling a Godot extension with +debug features enabled. The two concepts are not mutually inclusive. + +- debug_features + Enables a pre-processor definition to selectively compile code to help + users of a Godot extension with their own project. + + debug features are enabled in editor and template_debug builds, which can be specified during the configure phase like so + + ``cmake -S . -B cmake-build -DGODOTCPP_TARGET=`` + +- Debug + Sets compiler flags so that debug symbols are generated to help godot + extension developers debug their extension. + + ``Debug`` is the default build type for CMake projects, to select another it depends on the generator used + + For single configuration generators, add to the configure command: + + ``-DCMAKE_BUILD_TYPE=`` + + For multi-config generators add to the build command: + + ``--config `` + + where ```` is one of ``Debug``, ``Release``, ``RelWithDebInfo``, ``MinSizeRel`` + + SCons Deviations ---------------- @@ -32,21 +64,23 @@ the notable differences. - debug_symbols No longer has an explicit option, and is enabled via Debug-like CMake - build configurations; Debug, RelWithDebInfo. + build configurations; ``Debug``, ``RelWithDebInfo``. - dev_build - Does not define NDEBUG when disabled, NDEBUG is set via Release-like - CMake build configurations; Release, MinSizeRel. + Does not define ``NDEBUG`` when disabled, ``NDEBUG`` is set via Release-like + CMake build configurations; ``Release``, ``MinSizeRel``. + +- arch + CMake sets the architecture via the toolchain files, macos universal is controlled vua the ``CMAKE_OSX_ARCHITECTURES`` + property which is copied to targets when they are defined. + +- debug_crt + CMake controls linking to windows runtime libraries by copying the value of ``CMAKE_MSVC_RUNTIME_LIBRARIES`` to targets as they are defined. + godot-cpp will set this variable if it isn't already set. so include it before other dependencies to have the value propagate across the projects. Testing Integration ------------------- -When consuming a third party CMake project into yours, an unfortunate side -effect is that the targets of the consumed project appear in the list of -available targets, and are by default included in the ALL meta target -created by most build systems. For this reason, all the targets specified -in godot-cpp are marked with the ``EXCLUDE_FROM_ALL`` tag to prevent -unnecessary compilation. The testing targets ``godot-cpp.test.`` -are also guarded by ``GODOTCPP_ENABLE_TESTING`` which is off by default. +The testing target ``godot-cpp-test`` is guarded by ``GODOTCPP_ENABLE_TESTING`` which is off by default. To configure and build the godot-cpp project to enable the integration testing targets the command will look something like: @@ -54,10 +88,8 @@ testing targets the command will look something like: .. code-block:: # Assuming our current directory is the godot-cpp source root - mkdir cmake-build - cd cmake-build - cmake .. -DGODOTCPP_ENABLE_TESTING=YES - cmake --build . --target godot-cpp.test.template_debug + cmake -S . -B cmake-build -DGODOTCPP_ENABLE_TESTING=YES + cmake --build cmake-build --target godot-cpp-test Basic walkthrough ----------------- @@ -71,30 +103,7 @@ Basic walkthrough ... cd godot-cpp - -.. topic:: Out-of-tree build directory - - Create a build directory for CMake to put caches and build artifacts in and - change directory to it. This is typically as a sub-directory of the project - root but can be outside the source tree. This is so that generated files do - not clutter up the source tree. - - .. code-block:: - - mkdir cmake-build - cd cmake-build - -.. topic:: Configure the build - - CMake doesn't build the code, it generates the files that another tool uses - to build the code. To see the list of generators run ``cmake --help``. The - first phase of which is running through the configuration scripts. - - Configure and generate Ninja build files. - - .. code-block:: - - cmake .. -G "Ninja" +.. topic:: Options To list the available options CMake use the ``-L[AH]`` option. ``A`` is for advanced, and ``H`` is for help strings. @@ -103,7 +112,7 @@ Basic walkthrough cmake .. -LH - Options are specified on the command line when configuring + Options are specified on the command line when configuring eg. .. code-block:: @@ -129,36 +138,38 @@ Basic walkthrough // Path to a custom directory containing GDExtension interface header and API JSON file ( /path/to/gdextension_dir ) GODOTCPP_GDEXTENSION_DIR:PATH=gdextension - // Generate a template version of the Node class's get_node. (ON|OFF) - GODOTCPP_GENERATE_TEMPLATE_GET_NODE:BOOL=ON - // Set the floating-point precision level (single|double) GODOTCPP_PRECISION:STRING=single - // Symbols visibility on GNU platforms. Use 'auto' to apply the default value. (auto|visible|hidden) - GODOTCPP_SYMBOL_VISIBILITY:STRING=hidden - - // Expose headers as SYSTEM. - GODOTCPP_SYSTEM_HEADERS:BOOL=ON - // Enable the extra accounting required to support hot reload. (ON|OFF) GODOTCPP_USE_HOT_RELOAD:BOOL= - // Treat warnings as errors - GODOTCPP_WARNING_AS_ERROR:BOOL=OFF +.. topic:: Configure the build + + .. code-block:: + + cmake -S . -B cmake-build -G Ninja + + ``-S .`` Specifies the source directory + ``-B cmake-build`` Specifies the build directory + + ``-G Ninja`` Specifies the Generator + + The source directory in this example is the source code for godot-cpp. + The build directory is so that generated files do not clutter up the source tree. + CMake doesn't build the code, it generates the files that another tool uses + to build the code, in this case Ninja. + To see the list of generators run ``cmake --help``. .. topic:: Compiling - A target and a configuration is required, as the default ``all`` target does - not include anything and when using multi-config generators like ``Ninja - Multi-Config``, ``Visual Studio *`` or ``Xcode`` the build configuration - needs to be specified at build time. Build in Release mode unless you need - debug symbols. + Tell cmake to invoke the build system it generated in the specified directory. + The default target is template_debug and the default build configuration is Debug. .. code-block:: - cmake --build . -t template_debug --config Debug + cmake --build cmake-build Examples -------- @@ -169,25 +180,23 @@ So long as CMake is installed from the `CMake Downloads`_ page and in the PATH, and Microsoft Visual Studio is installed with c++ support, CMake will detect the MSVC compiler. -Remembering that Visual Studio is a Multi-Config Generator so the build type -needs to be specified at build time. +Note that Visual Studio is a Multi-Config Generator so the build configuration +needs to be specified at build time ie ``--config Release`` .. _CMake downloads: https://cmake.org/download/ .. code-block:: # Assuming our current directory is the godot-cpp source root - mkdir build-msvc - cd build-msvc - cmake .. -DGODOTCPP_ENABLE_TESTING=YES - cmake --build . -t godot-cpp.test.template_debug --config Debug + cmake -S . -B cmake-build -DGODOTCPP_ENABLE_TESTING=YES + cmake --build cmake-build -t godot-cpp-test --config Release MSys2/clang64, "Ninja" - Debug ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Assumes the ming-w64-clang-x86_64-toolchain is installed -Remembering that Ninja is a Single-Config Generator so the build type +Note that Ninja is a Single-Config Generator so the build type needs to be specified at Configure time. Using the msys2/clang64 shell @@ -195,10 +204,8 @@ Using the msys2/clang64 shell .. code-block:: # Assuming our current directory is the godot-cpp source root - mkdir build-clang - cd build-clang - cmake .. -G"Ninja" -DGODOTCPP_ENABLE_TESTING=YES -DCMAKE_BUILD_TYPE=Debug - cmake --build . -t godot-cpp.test.template_debug + cmake -S . -B cmake-build -G"Ninja" -DGODOTCPP_ENABLE_TESTING=YES -DCMAKE_BUILD_TYPE=Release + cmake --build cmake-build -t godot-cpp-test MSys2/clang64, "Ninja Multi-Config" - dev_build, Debug Symbols ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -212,10 +219,8 @@ Using the msys2/clang64 shell .. code-block:: # Assuming our current directory is the godot-cpp source root - mkdir build-clang - cd build-clang - cmake .. -G"Ninja Multi-Config" -DGODOTCPP_ENABLE_TESTING=YES -DGODOTCPP_DEV_BUILD:BOOL=ON - cmake --build . -t godot-cpp.test.template_debug --config Debug + cmake -S . -B cmake-build -G"Ninja Multi-Config" -DGODOTCPP_ENABLE_TESTING=YES -DGODOTCPP_DEV_BUILD:BOOL=ON + cmake --build cmake-build -t godot-cpp-test --config Debug Emscripten for web platform ~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -228,15 +233,14 @@ I've been using ``C:\emsdk\emsdk.ps1 activate latest`` to enable the environment from powershell in the current shell. The ``emcmake.bat`` utility adds the emscripten toolchain to the CMake command +It can also be added manually, the location is listed inside the emcmake.bat file .. code-block:: # Assuming our current directory is the godot-cpp source root C:\emsdk\emsdk.ps1 activate latest - mkdir build-wasm32 - cd build-wasm32 - emcmake.bat cmake ../ - cmake --build . --target template_release + emcmake.bat cmake -S . -B cmake-build-web -DCMAKE_BUILD_TYPE=Release + cmake --build cmake-build-web Android Cross Compile from Windows ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -263,24 +267,20 @@ is for android sdk platform, (tested with ``android-29``) .. code-block:: # Assuming our current directory is the godot-cpp source root - mkdir build-android - cd build-android - cmake .. --toolchain my_toolchain.cmake - cmake --build . -t template_release + cmake -S . -B cmake-build --toolchain my_toolchain.cmake + cmake --build cmake-build -t template_release Doing the equivalent on just using the command line .. code-block:: # Assuming our current directory is the godot-cpp source root - mkdir build-android - cd build-android - cmake .. \ + cmake -S . -B cmake-build \ -DCMAKE_SYSTEM_NAME=Android \ -DCMAKE_SYSTEM_VERSION= \ -DCMAKE_ANDROID_ARCH_ABI= \ -DCMAKE_ANDROID_NDK=/path/to/android-ndk - cmake --build . -t template_release + cmake --build cmake-build .. topic:: Using the toolchain file from the Android SDK @@ -289,22 +289,18 @@ is for android sdk platform, (tested with ``android-29``) .. code-block:: # Assuming our current directory is the godot-cpp source root - mkdir build-android - cd build-android - cmake .. --toolchain $ANDROID_HOME/ndk//build/cmake/android.toolchain.cmake - cmake --build . -t template_release + cmake -S . -B cmake-build --toolchain $ANDROID_HOME/ndk//build/cmake/android.toolchain.cmake + cmake --build cmake-build Specify Android platform and ABI .. code-block:: # Assuming our current directory is the godot-cpp source root - mkdir build-android - cd build-android - cmake .. --toolchain $ANDROID_HOME/ndk//build/cmake/android.toolchain.cmake \ + cmake -S . -B cmake-build --toolchain $ANDROID_HOME/ndk//build/cmake/android.toolchain.cmake \ -DANDROID_PLATFORM:STRING=android-29 \ -DANDROID_ABI:STRING=armeabi-v7a - cmake --build . -t template_release + cmake --build cmake-build Toolchains @@ -312,22 +308,9 @@ Toolchains This section attempts to list the host and target combinations that have been at tested. -Info on cross compiling triplets indicates that the naming is a little more -freeform that expected, and tailored to its use case. Triplets tend to have the -format ``[sub][-vendor][-OS][-env]`` - -* `osdev.org `_ -* `stack overflow `_ -* `LLVM `_ -* `clang target triple `_ -* `vcpkg `_ -* `wasm32-unknown-emscripten `_ - Linux Host ~~~~~~~~~~ -:Target: x86_64-linux - Macos Host ~~~~~~~~~~ @@ -335,43 +318,36 @@ Macos Host :OS Name: Sequoia 15.0.1 :Processor: Apple M2 +* AppleClang + Windows Host ~~~~~~~~~~~~ -:OS Name: Microsoft Windows 11 Home, 10.0.22631 N/A Build 22631 +:OS Name: Windows 11 :Processor: AMD Ryzen 7 6800HS Creator Edition -`Microsoft Visual Studio 17 2022 `_ - :Target: x86_64-w64 - -`LLVM `_ - :Target: x86_64-pc-windows-msvc - -`AndroidSDK `_ - armv7-none-linux-androideabi16 - -`Emscripten `_ - :Compiler: Emscripten - :Target: wasm32-unknown-emscripten - -`MinGW-w64 `_ based toolchains - `MSYS2 `_ - Necessary reading about MSYS2 `environments `_ +* `Microsoft Visual Studio 17 2022 `_ +* `LLVM `_ +* `LLVM-MinGW `_ - ucrt64 - :Compiler: gcc version 14.2.0 (Rev1, Built by MSYS2 project) - :Target: x86_64-w64-mingw32 + * aarch64-w64-mingw32 + * armv7-w64-mingw32 + * i686-w64-mingw32 + * x86_64-w64-mingw32 - clang64 - :Compiler: clang version 18.1.8 - :Target: x86_64-w64-windows-gnu +* `AndroidSDK `_ +* `Emscripten `_ +* `MinGW-W64-builds `_ +* `Jetbrains-CLion `_ - `LLVM-MinGW `_ + Jetbrains builtin compiler is just the MingW64 above. - `MinGW-W64-builds `_ - :Compiler: gcc - :Target: x86_64-w64-mingw32-ucrt +* `MSYS2 `_ + Necessary reading about MSYS2 `environments `_ - `Jetbrains-CLion `_ - :Target: x86_64-w64-mingw32-msvcrt + * ucrt64 + * clang64 + * mingw32 + * mingw64 + * clangarm64 diff --git a/gdextension/gdextension_interface.h b/gdextension/gdextension_interface.h index 971d0632..93ada27f 100644 --- a/gdextension/gdextension_interface.h +++ b/gdextension/gdextension_interface.h @@ -30,8 +30,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ -#ifndef GDEXTENSION_INTERFACE_H -#define GDEXTENSION_INTERFACE_H +#pragma once /* This is a C class header, you can copy it and use it directly in your own binders. * Together with the JSON file, you should be able to generate any binder. @@ -403,6 +402,9 @@ typedef struct { typedef void *GDExtensionClassLibraryPtr; +/* Passed a pointer to a PackedStringArray that should be filled with the classes that may be used by the GDExtension. */ +typedef void (*GDExtensionEditorGetClassesUsedCallback)(GDExtensionTypePtr p_packed_string_array); + /* Method */ typedef enum { @@ -3103,8 +3105,22 @@ typedef void (*GDExtensionsInterfaceEditorHelpLoadXmlFromUtf8Chars)(const char * */ typedef void (*GDExtensionsInterfaceEditorHelpLoadXmlFromUtf8CharsAndLen)(const char *p_data, GDExtensionInt p_size); +/** + * @name editor_register_get_classes_used_callback + * @since 4.5 + * + * Registers a callback that Godot can call to get the list of all classes (from ClassDB) that may be used by the calling GDExtension. + * + * This is used by the editor to generate a build profiles (in "Tools" > "Engine Compilation Configuration Editor..." > "Detect from project"), + * in order to recompile Godot with only the classes used. + * In the provided callback, the GDExtension should provide the list of classes that _may_ be used statically, thus the time of invocation shouldn't matter. + * If a GDExtension doesn't register a callback, Godot will assume that it could be using any classes. + * + * @param p_library A pointer the library received by the GDExtension's entry point function. + * @param p_callback The callback to retrieve the list of classes used. + */ +typedef void (*GDExtensionInterfaceEditorRegisterGetClassesUsedCallback)(GDExtensionClassLibraryPtr p_library, GDExtensionEditorGetClassesUsedCallback p_callback); + #ifdef __cplusplus } #endif - -#endif // GDEXTENSION_INTERFACE_H diff --git a/include/godot_cpp/classes/editor_plugin_registration.hpp b/include/godot_cpp/classes/editor_plugin_registration.hpp index cac987db..7baf9bcc 100644 --- a/include/godot_cpp/classes/editor_plugin_registration.hpp +++ b/include/godot_cpp/classes/editor_plugin_registration.hpp @@ -30,8 +30,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ -#ifndef GODOT_EDITOR_PLUGIN_REGISTRATION_HPP -#define GODOT_EDITOR_PLUGIN_REGISTRATION_HPP +#pragma once #include @@ -60,5 +59,3 @@ class EditorPlugins { }; } // namespace godot - -#endif // GODOT_EDITOR_PLUGIN_REGISTRATION_HPP diff --git a/include/godot_cpp/classes/ref.hpp b/include/godot_cpp/classes/ref.hpp index c92509a1..ae0757f8 100644 --- a/include/godot_cpp/classes/ref.hpp +++ b/include/godot_cpp/classes/ref.hpp @@ -30,8 +30,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ -#ifndef GODOT_REF_HPP -#define GODOT_REF_HPP +#pragma once #include @@ -73,6 +72,10 @@ class Ref { } public: + static _FORCE_INLINE_ String get_class_static() { + return T::get_class_static(); + } + _FORCE_INLINE_ bool operator==(const T *p_ptr) const { return reference == p_ptr; } @@ -286,5 +289,3 @@ struct GetTypeInfo &, typename EnableIf }; } // namespace godot - -#endif // GODOT_REF_HPP diff --git a/include/godot_cpp/classes/wrapped.hpp b/include/godot_cpp/classes/wrapped.hpp index 938f1451..f95f1c78 100644 --- a/include/godot_cpp/classes/wrapped.hpp +++ b/include/godot_cpp/classes/wrapped.hpp @@ -30,8 +30,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ -#ifndef GODOT_WRAPPED_HPP -#define GODOT_WRAPPED_HPP +#pragma once #include @@ -513,5 +512,3 @@ public: #define GDVIRTUAL_BIND(m_name, ...) ::godot::ClassDB::add_virtual_method(get_class_static(), _gdvirtual_##m_name##_get_method_info(), ::godot::snarray(__VA_ARGS__)); #define GDVIRTUAL_IS_OVERRIDDEN(m_name) _gdvirtual_##m_name##_overridden() #define GDVIRTUAL_IS_OVERRIDDEN_PTR(m_obj, m_name) m_obj->_gdvirtual_##m_name##_overridden() - -#endif // GODOT_WRAPPED_HPP diff --git a/include/godot_cpp/core/binder_common.hpp b/include/godot_cpp/core/binder_common.hpp index 672369c4..6bd46c4a 100644 --- a/include/godot_cpp/core/binder_common.hpp +++ b/include/godot_cpp/core/binder_common.hpp @@ -30,11 +30,11 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ -#ifndef GODOT_BINDER_COMMON_HPP -#define GODOT_BINDER_COMMON_HPP +#pragma once #include +#include #include #include @@ -694,5 +694,3 @@ void call_with_ptr_args_static_method_ret(R (*p_method)(P...), const GDExtension #include #include - -#endif // GODOT_BINDER_COMMON_HPP diff --git a/include/godot_cpp/core/builtin_ptrcall.hpp b/include/godot_cpp/core/builtin_ptrcall.hpp index 62f677ac..420e2261 100644 --- a/include/godot_cpp/core/builtin_ptrcall.hpp +++ b/include/godot_cpp/core/builtin_ptrcall.hpp @@ -30,8 +30,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ -#ifndef GODOT_BUILTIN_PTRCALL_HPP -#define GODOT_BUILTIN_PTRCALL_HPP +#pragma once #include #include @@ -90,5 +89,3 @@ T _call_builtin_ptr_getter(const GDExtensionPtrGetter getter, GDExtensionConstTy } // namespace internal } // namespace godot - -#endif // GODOT_BUILTIN_PTRCALL_HPP diff --git a/include/godot_cpp/core/class_db.hpp b/include/godot_cpp/core/class_db.hpp index 6906aa7b..65ab38a5 100644 --- a/include/godot_cpp/core/class_db.hpp +++ b/include/godot_cpp/core/class_db.hpp @@ -30,8 +30,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ -#ifndef GODOT_CLASS_DB_HPP -#define GODOT_CLASS_DB_HPP +#pragma once #include @@ -170,6 +169,8 @@ class ClassDB { instance_binding_callbacks[p_name] = p_callbacks; } + static void _editor_get_classes_used_callback(GDExtensionTypePtr p_packed_string_array); + static void _register_engine_singleton(const StringName &p_class_name, Object *p_singleton) { std::lock_guard lock(engine_singletons_mutex); std::unordered_map::const_iterator i = engine_singletons.find(p_class_name); @@ -372,5 +373,3 @@ MethodBind *ClassDB::bind_vararg_method(uint32_t p_flags, StringName p_name, M p } // namespace godot CLASSDB_SINGLETON_VARIANT_CAST; - -#endif // GODOT_CLASS_DB_HPP diff --git a/include/godot_cpp/core/defs.hpp b/include/godot_cpp/core/defs.hpp index f0699394..9d61c1cd 100644 --- a/include/godot_cpp/core/defs.hpp +++ b/include/godot_cpp/core/defs.hpp @@ -30,12 +30,11 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ -#ifndef GODOT_DEFS_HPP -#define GODOT_DEFS_HPP +#pragma once #include #include -#include +#include namespace godot { @@ -67,15 +66,33 @@ namespace godot { #endif #endif -// Should always inline, except in debug builds because it makes debugging harder. +// Should always inline, except in dev builds because it makes debugging harder, +// or `size_enabled` builds where inlining is actively avoided. #ifndef _FORCE_INLINE_ -#ifdef DISABLE_FORCED_INLINE +#if defined(DEV_ENABLED) || defined(SIZE_EXTRA) #define _FORCE_INLINE_ inline #else #define _FORCE_INLINE_ _ALWAYS_INLINE_ #endif #endif +// Should never inline. +#ifndef _NO_INLINE_ +#if defined(__GNUC__) +#define _NO_INLINE_ __attribute__((noinline)) +#elif defined(_MSC_VER) +#define _NO_INLINE_ __declspec(noinline) +#else +#define _NO_INLINE_ +#endif +#endif + +// In some cases [[nodiscard]] will get false positives, +// we can prevent the warning in specific cases by preceding the call with a cast. +#ifndef _ALLOW_DISCARD_ +#define _ALLOW_DISCARD_ (void) +#endif + // Windows badly defines a lot of stuff we'll never use. Undefine it. #ifdef _WIN32 #undef min // override standard definition @@ -83,14 +100,182 @@ namespace godot { #undef ERROR // override (really stupid) wingdi.h standard definition #undef DELETE // override (another really stupid) winnt.h standard definition #undef MessageBox // override winuser.h standard definition -#undef MIN // override standard definition -#undef MAX // override standard definition -#undef CLAMP // override standard definition #undef Error #undef OK #undef CONNECT_DEFERRED // override from Windows SDK, clashes with Object enum +#undef MemoryBarrier +#undef MONO_FONT #endif +// Make room for our constexpr's below by overriding potential system-specific macros. +#undef SIGN +#undef MIN +#undef MAX +#undef CLAMP + +template +constexpr const T SIGN(const T m_v) { + return m_v > 0 ? +1.0f : (m_v < 0 ? -1.0f : 0.0f); +} + +template +constexpr auto MIN(const T m_a, const T2 m_b) { + return m_a < m_b ? m_a : m_b; +} + +template +constexpr auto MAX(const T m_a, const T2 m_b) { + return m_a > m_b ? m_a : m_b; +} + +template +constexpr auto CLAMP(const T m_a, const T2 m_min, const T3 m_max) { + return m_a < m_min ? m_min : (m_a > m_max ? m_max : m_a); +} + +// Generic swap template. +#ifndef SWAP +#define SWAP(m_x, m_y) std::swap((m_x), (m_y)) +#endif // SWAP + +/* Functions to handle powers of 2 and shifting. */ + +// Returns `true` if a positive integer is a power of 2, `false` otherwise. +template +inline bool is_power_of_2(const T x) { + return x && ((x & (x - 1)) == 0); +} + +// Function to find the next power of 2 to an integer. +static _FORCE_INLINE_ unsigned int next_power_of_2(unsigned int x) { + if (x == 0) { + return 0; + } + + --x; + x |= x >> 1; + x |= x >> 2; + x |= x >> 4; + x |= x >> 8; + x |= x >> 16; + + return ++x; +} + +// Function to find the previous power of 2 to an integer. +static _FORCE_INLINE_ unsigned int previous_power_of_2(unsigned int x) { + x |= x >> 1; + x |= x >> 2; + x |= x >> 4; + x |= x >> 8; + x |= x >> 16; + return x - (x >> 1); +} + +// Function to find the closest power of 2 to an integer. +static _FORCE_INLINE_ unsigned int closest_power_of_2(unsigned int x) { + unsigned int nx = next_power_of_2(x); + unsigned int px = previous_power_of_2(x); + return (nx - x) > (x - px) ? px : nx; +} + +// Get a shift value from a power of 2. +static inline int get_shift_from_power_of_2(unsigned int p_bits) { + for (unsigned int i = 0; i < 32; i++) { + if (p_bits == (unsigned int)(1 << i)) { + return i; + } + } + + return -1; +} + +template +static _FORCE_INLINE_ T nearest_power_of_2_templated(T x) { + --x; + + // The number of operations on x is the base two logarithm + // of the number of bits in the type. Add three to account + // for sizeof(T) being in bytes. + size_t num = get_shift_from_power_of_2(sizeof(T)) + 3; + + // If the compiler is smart, it unrolls this loop. + // If it's dumb, this is a bit slow. + for (size_t i = 0; i < num; i++) { + x |= x >> (1 << i); + } + + return ++x; +} + +// Function to find the nearest (bigger) power of 2 to an integer. +static inline unsigned int nearest_shift(unsigned int p_number) { + for (int i = 30; i >= 0; i--) { + if (p_number & (1 << i)) { + return i + 1; + } + } + + return 0; +} + +// constexpr function to find the floored log2 of a number +template +constexpr T floor_log2(T x) { + return x < 2 ? x : 1 + floor_log2(x >> 1); +} + +// Get the number of bits needed to represent the number. +// IE, if you pass in 8, you will get 4. +// If you want to know how many bits are needed to store 8 values however, pass in (8 - 1). +template +constexpr T get_num_bits(T x) { + return floor_log2(x); +} + +// Swap 16, 32 and 64 bits value for endianness. +#if defined(__GNUC__) +#define BSWAP16(x) __builtin_bswap16(x) +#define BSWAP32(x) __builtin_bswap32(x) +#define BSWAP64(x) __builtin_bswap64(x) +#elif defined(_MSC_VER) +#define BSWAP16(x) _byteswap_ushort(x) +#define BSWAP32(x) _byteswap_ulong(x) +#define BSWAP64(x) _byteswap_uint64(x) +#else +static inline uint16_t BSWAP16(uint16_t x) { + return (x >> 8) | (x << 8); +} + +static inline uint32_t BSWAP32(uint32_t x) { + return ((x << 24) | ((x << 8) & 0x00FF0000) | ((x >> 8) & 0x0000FF00) | (x >> 24)); +} + +static inline uint64_t BSWAP64(uint64_t x) { + x = (x & 0x00000000FFFFFFFF) << 32 | (x & 0xFFFFFFFF00000000) >> 32; + x = (x & 0x0000FFFF0000FFFF) << 16 | (x & 0xFFFF0000FFFF0000) >> 16; + x = (x & 0x00FF00FF00FF00FF) << 8 | (x & 0xFF00FF00FF00FF00) >> 8; + return x; +} +#endif + +// Generic comparator used in Map, List, etc. +template +struct Comparator { + _ALWAYS_INLINE_ bool operator()(const T &p_a, const T &p_b) const { return (p_a < p_b); } +}; + +// Global lock macro, relies on the static Mutex::_global_mutex. +void _global_lock(); +void _global_unlock(); + +struct _GlobalLock { + _GlobalLock() { _global_lock(); } + ~_GlobalLock() { _global_unlock(); } +}; + +#define GLOBAL_LOCK_FUNCTION _GlobalLock _global_lock_; + #if defined(__GNUC__) #define likely(x) __builtin_expect(!!(x), 1) #define unlikely(x) __builtin_expect(!!(x), 0) @@ -99,22 +284,17 @@ namespace godot { #define unlikely(x) x #endif -#ifdef REAL_T_IS_DOUBLE -typedef double real_t; +#if defined(__GNUC__) +#define _PRINTF_FORMAT_ATTRIBUTE_2_0 __attribute__((format(printf, 2, 0))) +#define _PRINTF_FORMAT_ATTRIBUTE_2_3 __attribute__((format(printf, 2, 3))) #else -typedef float real_t; +#define _PRINTF_FORMAT_ATTRIBUTE_2_0 +#define _PRINTF_FORMAT_ATTRIBUTE_2_3 #endif -// Generic swap template. -#ifndef SWAP -#define SWAP(m_x, m_y) __swap_tmpl((m_x), (m_y)) -template -inline void __swap_tmpl(T &x, T &y) { - T aux = x; - x = y; - y = aux; -} -#endif // SWAP +// This is needed due to a strange OpenGL API that expects a pointer +// type for an argument that is actually an offset. +#define CAST_INT_TO_UCHAR_PTR(ptr) ((uint8_t *)(uintptr_t)(ptr)) // Home-made index sequence trick, so it can be used everywhere without the costly include of std::tuple. // https://stackoverflow.com/questions/15014096/c-index-of-type-during-variadic-template-expansion @@ -127,10 +307,36 @@ struct BuildIndexSequence : BuildIndexSequence {}; template struct BuildIndexSequence<0, Is...> : IndexSequence {}; -} //namespace godot +// Limit the depth of recursive algorithms when dealing with Array/Dictionary +#define MAX_RECURSION 100 -// To maintain compatibility an alias is defined outside the namespace. -// Consider it deprecated. -using real_t = godot::real_t; +#ifdef DEBUG_ENABLED +#define DEBUG_METHODS_ENABLED +#endif -#endif // GODOT_DEFS_HPP +// Macro GD_IS_DEFINED() allows to check if a macro is defined. It needs to be defined to anything (say 1) to work. +#define __GDARG_PLACEHOLDER_1 false, +#define __gd_take_second_arg(__ignored, val, ...) val +#define ____gd_is_defined(arg1_or_junk) __gd_take_second_arg(arg1_or_junk true, false) +#define ___gd_is_defined(val) ____gd_is_defined(__GDARG_PLACEHOLDER_##val) +#define GD_IS_DEFINED(x) ___gd_is_defined(x) + +// Whether the default value of a type is just all-0 bytes. +// This can most commonly be exploited by using memset for these types instead of loop-construct. +// Trivially constructible types are also zero-constructible. +template +struct is_zero_constructible : std::is_trivially_constructible {}; + +template +struct is_zero_constructible : is_zero_constructible {}; + +template +struct is_zero_constructible : is_zero_constructible {}; + +template +struct is_zero_constructible : is_zero_constructible {}; + +template +inline constexpr bool is_zero_constructible_v = is_zero_constructible::value; + +} //namespace godot diff --git a/include/godot_cpp/core/engine_ptrcall.hpp b/include/godot_cpp/core/engine_ptrcall.hpp index ac03297a..0eb3300b 100644 --- a/include/godot_cpp/core/engine_ptrcall.hpp +++ b/include/godot_cpp/core/engine_ptrcall.hpp @@ -30,8 +30,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ -#ifndef GODOT_ENGINE_PTRCALL_HPP -#define GODOT_ENGINE_PTRCALL_HPP +#pragma once #include @@ -58,10 +57,10 @@ O *_call_native_mb_ret_obj(const GDExtensionMethodBindPtr mb, void *instance, co template R _call_native_mb_ret(const GDExtensionMethodBindPtr mb, void *instance, const Args &...args) { - R ret; + typename PtrToArg::EncodeT ret; std::array mb_args = { { (GDExtensionConstTypePtr)args... } }; internal::gdextension_interface_object_method_bind_ptrcall(mb, instance, mb_args.data(), &ret); - return ret; + return static_cast(ret); } template @@ -72,10 +71,10 @@ void _call_native_mb_no_ret(const GDExtensionMethodBindPtr mb, void *instance, c template R _call_utility_ret(GDExtensionPtrUtilityFunction func, const Args &...args) { - R ret; + typename PtrToArg::EncodeT ret; std::array mb_args = { { (GDExtensionConstTypePtr)args... } }; func(&ret, mb_args.data(), mb_args.size()); - return ret; + return static_cast(ret); } template @@ -95,5 +94,3 @@ void _call_utility_no_ret(const GDExtensionPtrUtilityFunction func, const Args & } // namespace internal } // namespace godot - -#endif // GODOT_ENGINE_PTRCALL_HPP diff --git a/include/godot_cpp/core/error_macros.hpp b/include/godot_cpp/core/error_macros.hpp index 6f4878a9..3d7c9c66 100644 --- a/include/godot_cpp/core/error_macros.hpp +++ b/include/godot_cpp/core/error_macros.hpp @@ -30,8 +30,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ -#ifndef GODOT_ERROR_MACROS_HPP -#define GODOT_ERROR_MACROS_HPP +#pragma once #include @@ -804,5 +803,3 @@ void _err_flush_stdout(); #define CHECK_METHOD_BIND_RET(m_mb, m_ret) #define CHECK_METHOD_BIND(m_mb) #endif - -#endif // GODOT_ERROR_MACROS_HPP diff --git a/include/godot_cpp/core/math.compat.inc b/include/godot_cpp/core/math.compat.inc new file mode 100644 index 00000000..3a3e2072 --- /dev/null +++ b/include/godot_cpp/core/math.compat.inc @@ -0,0 +1,53 @@ +/**************************************************************************/ +/* math.compat.inc */ +/**************************************************************************/ +/* This file is part of: */ +/* REDOT ENGINE */ +/* https://redotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2024-present Redot Engine contributors */ +/* (see REDOT_AUTHORS.md) */ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/**************************************************************************/ + + +#ifndef DISABLE_DEPRECATED + +namespace godot { + +#undef ABS + +// Generic ABS function, for math uses please use Math::abs. +template +[[deprecated("Use Math::abs instead")]] +constexpr T ABS(T m_v) { + return m_v < 0 ? -m_v : m_v; +} + +} + +// To maintain compatibility an alias is defined outside the namespace. +// Consider it deprecated. +using real_t = godot::real_t; + +#endif diff --git a/include/godot_cpp/core/math.hpp b/include/godot_cpp/core/math.hpp index f95b8977..1185933f 100644 --- a/include/godot_cpp/core/math.hpp +++ b/include/godot_cpp/core/math.hpp @@ -30,10 +30,10 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ -#ifndef GODOT_MATH_HPP -#define GODOT_MATH_HPP +#pragma once #include +#include #include @@ -41,185 +41,8 @@ namespace godot { -#define Math_SQRT12 0.7071067811865475244008443621048490 -#define Math_SQRT2 1.4142135623730950488016887242 -#define Math_LN2 0.6931471805599453094172321215 -#define Math_PI 3.1415926535897932384626433833 -#define Math_TAU 6.2831853071795864769252867666 -#define Math_E 2.7182818284590452353602874714 -#define Math_INF INFINITY -#define Math_NAN NAN - -// Make room for our constexpr's below by overriding potential system-specific macros. -#undef ABS -#undef SIGN -#undef MIN -#undef MAX -#undef CLAMP - -// Generic ABS function, for math uses please use Math::abs. -template -constexpr T ABS(T m_v) { - return m_v < 0 ? -m_v : m_v; -} - -template -constexpr const T SIGN(const T m_v) { - return m_v == 0 ? 0.0f : (m_v < 0 ? -1.0f : +1.0f); -} - -template -constexpr auto MIN(const T m_a, const T2 m_b) { - return m_a < m_b ? m_a : m_b; -} - -template -constexpr auto MAX(const T m_a, const T2 m_b) { - return m_a > m_b ? m_a : m_b; -} - -template -constexpr auto CLAMP(const T m_a, const T2 m_min, const T3 m_max) { - return m_a < m_min ? m_min : (m_a > m_max ? m_max : m_a); -} - -// Generic swap template. -#ifndef SWAP -#define SWAP(m_x, m_y) __swap_tmpl((m_x), (m_y)) -template -inline void __swap_tmpl(T &x, T &y) { - T aux = x; - x = y; - y = aux; -} -#endif // SWAP - -/* Functions to handle powers of 2 and shifting. */ - -// Function to find the next power of 2 to an integer. -static _FORCE_INLINE_ unsigned int next_power_of_2(unsigned int x) { - if (x == 0) { - return 0; - } - - --x; - x |= x >> 1; - x |= x >> 2; - x |= x >> 4; - x |= x >> 8; - x |= x >> 16; - - return ++x; -} - -// Function to find the previous power of 2 to an integer. -static _FORCE_INLINE_ unsigned int previous_power_of_2(unsigned int x) { - x |= x >> 1; - x |= x >> 2; - x |= x >> 4; - x |= x >> 8; - x |= x >> 16; - return x - (x >> 1); -} - -// Function to find the closest power of 2 to an integer. -static _FORCE_INLINE_ unsigned int closest_power_of_2(unsigned int x) { - unsigned int nx = next_power_of_2(x); - unsigned int px = previous_power_of_2(x); - return (nx - x) > (x - px) ? px : nx; -} - -// Get a shift value from a power of 2. -static inline int get_shift_from_power_of_2(unsigned int p_bits) { - for (unsigned int i = 0; i < 32; i++) { - if (p_bits == (unsigned int)(1 << i)) { - return i; - } - } - - return -1; -} - -template -static _FORCE_INLINE_ T nearest_power_of_2_templated(T x) { - --x; - - // The number of operations on x is the base two logarithm - // of the number of bits in the type. Add three to account - // for sizeof(T) being in bytes. - size_t num = get_shift_from_power_of_2(sizeof(T)) + 3; - - // If the compiler is smart, it unrolls this loop. - // If it's dumb, this is a bit slow. - for (size_t i = 0; i < num; i++) { - x |= x >> (1 << i); - } - - return ++x; -} - -// Function to find the nearest (bigger) power of 2 to an integer. -static inline unsigned int nearest_shift(unsigned int p_number) { - for (int i = 30; i >= 0; i--) { - if (p_number & (1 << i)) { - return i + 1; - } - } - - return 0; -} - -// constexpr function to find the floored log2 of a number -template -constexpr T floor_log2(T x) { - return x < 2 ? x : 1 + floor_log2(x >> 1); -} - -// Get the number of bits needed to represent the number. -// IE, if you pass in 8, you will get 4. -// If you want to know how many bits are needed to store 8 values however, pass in (8 - 1). -template -constexpr T get_num_bits(T x) { - return floor_log2(x); -} - -// Swap 16, 32 and 64 bits value for endianness. -#if defined(__GNUC__) -#define BSWAP16(x) __builtin_bswap16(x) -#define BSWAP32(x) __builtin_bswap32(x) -#define BSWAP64(x) __builtin_bswap64(x) -#else -static inline uint16_t BSWAP16(uint16_t x) { - return (x >> 8) | (x << 8); -} - -static inline uint32_t BSWAP32(uint32_t x) { - return ((x << 24) | ((x << 8) & 0x00FF0000) | ((x >> 8) & 0x0000FF00) | (x >> 24)); -} - -static inline uint64_t BSWAP64(uint64_t x) { - x = (x & 0x00000000FFFFFFFF) << 32 | (x & 0xFFFFFFFF00000000) >> 32; - x = (x & 0x0000FFFF0000FFFF) << 16 | (x & 0xFFFF0000FFFF0000) >> 16; - x = (x & 0x00FF00FF00FF00FF) << 8 | (x & 0xFF00FF00FF00FF00) >> 8; - return x; -} -#endif - namespace Math { -// This epsilon should match the one used by Godot for consistency. -// Using `f` when `real_t` is float. -#define CMP_EPSILON 0.00001f -#define CMP_EPSILON2 (CMP_EPSILON * CMP_EPSILON) - -// This epsilon is for values related to a unit size (scalar or vector len). -#ifdef PRECISE_MATH_CHECKS -#define UNIT_EPSILON 0.00001 -#else -// Tolerate some more floating point error normally. -#define UNIT_EPSILON 0.001 -#endif - // Functions reproduced as in Godot's source code `math_funcs.h`. // Some are overloads to automatically support changing real_t into either double or float in the way Godot does. @@ -540,6 +363,26 @@ inline float bezier_interpolate(float p_start, float p_control_1, float p_contro return p_start * omt3 + p_control_1 * omt2 * p_t * 3.0f + p_control_2 * omt * t2 * 3.0f + p_end * t3; } +inline double bezier_derivative(double p_start, double p_control_1, double p_control_2, double p_end, double p_t) { + /* Formula from Wikipedia article on Bezier curves. */ + double omt = (1.0 - p_t); + double omt2 = omt * omt; + double t2 = p_t * p_t; + + double d = (p_control_1 - p_start) * 3.0 * omt2 + (p_control_2 - p_control_1) * 6.0 * omt * p_t + (p_end - p_control_2) * 3.0 * t2; + return d; +} + +inline float bezier_derivative(float p_start, float p_control_1, float p_control_2, float p_end, float p_t) { + /* Formula from Wikipedia article on Bezier curves. */ + float omt = (1.0f - p_t); + float omt2 = omt * omt; + float t2 = p_t * p_t; + + float d = (p_control_1 - p_start) * 3.0f * omt2 + (p_control_2 - p_control_1) * 6.0f * omt * p_t + (p_end - p_control_2) * 3.0f * t2; + return d; +} + template inline T clamp(T x, T minv, T maxv) { if (x < minv) { @@ -818,4 +661,4 @@ inline float snap_scalar_separation(float p_offset, float p_step, float p_target } // namespace Math } // namespace godot -#endif // GODOT_MATH_HPP +#include "math.compat.inc" diff --git a/include/godot_cpp/core/math_defs.hpp b/include/godot_cpp/core/math_defs.hpp new file mode 100644 index 00000000..8af85ee0 --- /dev/null +++ b/include/godot_cpp/core/math_defs.hpp @@ -0,0 +1,74 @@ +/**************************************************************************/ +/* math_defs.hpp */ +/**************************************************************************/ +/* This file is part of: */ +/* REDOT ENGINE */ +/* https://redotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2024-present Redot Engine contributors */ +/* (see REDOT_AUTHORS.md) */ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/**************************************************************************/ + +#pragma once + +namespace godot { + +#define CMP_EPSILON 0.00001 +#define CMP_EPSILON2 (CMP_EPSILON * CMP_EPSILON) + +#define CMP_NORMALIZE_TOLERANCE 0.000001 +#define CMP_POINT_IN_PLANE_EPSILON 0.00001 + +#define Math_SQRT12 0.7071067811865475244008443621048490 +#define Math_SQRT2 1.4142135623730950488016887242 +#define Math_LN2 0.6931471805599453094172321215 +#define Math_TAU 6.2831853071795864769252867666 +#define Math_PI 3.1415926535897932384626433833 +#define Math_E 2.7182818284590452353602874714 + +#ifdef DEBUG_ENABLED +#define MATH_CHECKS +#endif + +//this epsilon is for values related to a unit size (scalar or vector len) +#ifdef PRECISE_MATH_CHECKS +#define UNIT_EPSILON 0.00001 +#else +//tolerate some more floating point error normally +#define UNIT_EPSILON 0.001 +#endif + +#define USEC_TO_SEC(m_usec) ((m_usec) / 1000000.0) + +/** + * The "Real" type is an abstract type used for real numbers, such as 1.5, + * in contrast to integer numbers. Precision can be controlled with the + * presence or absence of the REAL_T_IS_DOUBLE define. + */ +#ifdef REAL_T_IS_DOUBLE +typedef double real_t; +#else +typedef float real_t; +#endif +} // namespace godot diff --git a/include/godot_cpp/core/memory.hpp b/include/godot_cpp/core/memory.hpp index 2c7a690b..8a9a2a9a 100644 --- a/include/godot_cpp/core/memory.hpp +++ b/include/godot_cpp/core/memory.hpp @@ -30,8 +30,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ -#ifndef GODOT_MEMORY_HPP -#define GODOT_MEMORY_HPP +#pragma once #include #include @@ -104,12 +103,6 @@ _ALWAYS_INLINE_ T *_post_initialize(T *p_obj) { #define memnew_allocator(m_class, m_allocator) (::godot::_pre_initialize>(), ::godot::_post_initialize(new ("", m_allocator::alloc) m_class)) #define memnew_placement(m_placement, m_class) (::godot::_pre_initialize>(), ::godot::_post_initialize(new ("", m_placement, sizeof(m_class), "") m_class)) -// Generic comparator used in Map, List, etc. -template -struct Comparator { - _ALWAYS_INLINE_ bool operator()(const T &p_a, const T &p_b) const { return (p_a < p_b); } -}; - template void memdelete(T *p_class, typename std::enable_if>::type * = nullptr) { if constexpr (!std::is_trivially_destructible_v) { @@ -218,5 +211,3 @@ struct _GlobalNilClass { }; } // namespace godot - -#endif // GODOT_MEMORY_HPP diff --git a/include/godot_cpp/core/method_bind.hpp b/include/godot_cpp/core/method_bind.hpp index c322ca7e..e5291f45 100644 --- a/include/godot_cpp/core/method_bind.hpp +++ b/include/godot_cpp/core/method_bind.hpp @@ -30,8 +30,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ -#ifndef GODOT_METHOD_BIND_HPP -#define GODOT_METHOD_BIND_HPP +#pragma once #include #include @@ -733,5 +732,3 @@ MethodBind *create_static_method_bind(R (*p_method)(P...)) { } } // namespace godot - -#endif // GODOT_METHOD_BIND_HPP diff --git a/include/godot_cpp/core/method_ptrcall.hpp b/include/godot_cpp/core/method_ptrcall.hpp index 75ba9d4b..f7445104 100644 --- a/include/godot_cpp/core/method_ptrcall.hpp +++ b/include/godot_cpp/core/method_ptrcall.hpp @@ -30,8 +30,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ -#ifndef GODOT_METHOD_PTRCALL_HPP -#define GODOT_METHOD_PTRCALL_HPP +#pragma once #include @@ -124,6 +123,9 @@ MAKE_PTRARGCONV(uint16_t, int64_t); MAKE_PTRARGCONV(int16_t, int64_t); MAKE_PTRARGCONV(uint32_t, int64_t); MAKE_PTRARGCONV(int32_t, int64_t); +MAKE_PTRARGCONV(char16_t, int64_t); +MAKE_PTRARGCONV(char32_t, int64_t); +MAKE_PTRARGCONV(wchar_t, int64_t); MAKE_PTRARG(int64_t); MAKE_PTRARG(uint64_t); // Float types @@ -236,5 +238,3 @@ GDVIRTUAL_NATIVE_PTR(float); GDVIRTUAL_NATIVE_PTR(double); } // namespace godot - -#endif // GODOT_METHOD_PTRCALL_HPP diff --git a/include/godot_cpp/core/mutex_lock.hpp b/include/godot_cpp/core/mutex_lock.hpp index a92ce922..8c1cb06c 100644 --- a/include/godot_cpp/core/mutex_lock.hpp +++ b/include/godot_cpp/core/mutex_lock.hpp @@ -30,8 +30,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ -#ifndef GODOT_MUTEX_LOCK_HPP -#define GODOT_MUTEX_LOCK_HPP +#pragma once #include @@ -57,5 +56,3 @@ class MutexLock { #define _THREAD_SAFE_UNLOCK_ _thread_safe_.unlock(); } // namespace godot - -#endif // GODOT_MUTEX_LOCK_HPP diff --git a/include/godot_cpp/core/object.hpp b/include/godot_cpp/core/object.hpp index a18600e3..ed0cef5e 100644 --- a/include/godot_cpp/core/object.hpp +++ b/include/godot_cpp/core/object.hpp @@ -30,8 +30,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ -#ifndef GODOT_OBJECT_HPP -#define GODOT_OBJECT_HPP +#pragma once #include @@ -150,5 +149,3 @@ const T *Object::cast_to(const Object *p_object) { } } // namespace godot - -#endif // GODOT_OBJECT_HPP diff --git a/include/godot_cpp/core/object_id.hpp b/include/godot_cpp/core/object_id.hpp index 099845cc..1e7de8f9 100644 --- a/include/godot_cpp/core/object_id.hpp +++ b/include/godot_cpp/core/object_id.hpp @@ -30,8 +30,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ -#ifndef GODOT_OBJECT_ID_HPP -#define GODOT_OBJECT_ID_HPP +#pragma once #include @@ -60,5 +59,3 @@ class ObjectID { }; } // namespace godot - -#endif // GODOT_OBJECT_ID_HPP diff --git a/include/godot_cpp/core/print_string.hpp b/include/godot_cpp/core/print_string.hpp index 9336bf96..a599a409 100644 --- a/include/godot_cpp/core/print_string.hpp +++ b/include/godot_cpp/core/print_string.hpp @@ -30,8 +30,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ -#ifndef GODOT_PRINT_STRING_HPP -#define GODOT_PRINT_STRING_HPP +#pragma once #include @@ -71,5 +70,3 @@ void print_verbose(const Variant &p_variant, Args... p_args) { bool is_print_verbose_enabled(); } // namespace godot - -#endif // GODOT_PRINT_STRING_HPP diff --git a/include/godot_cpp/core/property_info.hpp b/include/godot_cpp/core/property_info.hpp index 3ea64bab..98560257 100644 --- a/include/godot_cpp/core/property_info.hpp +++ b/include/godot_cpp/core/property_info.hpp @@ -30,8 +30,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ -#ifndef GODOT_PROPERTY_INFO_HPP -#define GODOT_PROPERTY_INFO_HPP +#pragma once #include @@ -130,5 +129,3 @@ struct PropertyInfo { }; } // namespace godot - -#endif // GODOT_PROPERTY_INFO_HPP diff --git a/include/godot_cpp/core/type_info.hpp b/include/godot_cpp/core/type_info.hpp index f9f483f2..1d48e166 100644 --- a/include/godot_cpp/core/type_info.hpp +++ b/include/godot_cpp/core/type_info.hpp @@ -30,9 +30,9 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ -#ifndef GODOT_TYPE_INFO_HPP -#define GODOT_TYPE_INFO_HPP +#pragma once +#include #include #include #include @@ -418,5 +418,3 @@ MAKE_TYPED_ARRAY_INFO(IPAddress, Variant::STRING) #define CLASS_INFO(m_type) (GetTypeInfo::get_class_info()) } // namespace godot - -#endif // GODOT_TYPE_INFO_HPP diff --git a/include/godot_cpp/godot.hpp b/include/godot_cpp/godot.hpp index 6b7d2689..cc11747c 100644 --- a/include/godot_cpp/godot.hpp +++ b/include/godot_cpp/godot.hpp @@ -30,8 +30,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ -#ifndef GODOT_GODOT_HPP -#define GODOT_GODOT_HPP +#pragma once #include @@ -200,6 +199,7 @@ extern "C" GDExtensionInterfaceClassdbUnregisterExtensionClass gdextension_inter extern "C" GDExtensionInterfaceGetLibraryPath gdextension_interface_get_library_path; extern "C" GDExtensionInterfaceEditorAddPlugin gdextension_interface_editor_add_plugin; extern "C" GDExtensionInterfaceEditorRemovePlugin gdextension_interface_editor_remove_plugin; +extern "C" GDExtensionInterfaceEditorRegisterGetClassesUsedCallback gdextension_interface_editor_register_get_classes_used_callback; extern "C" GDExtensionsInterfaceEditorHelpLoadXmlFromUtf8Chars gdextension_interface_editor_help_load_xml_from_utf8_chars; extern "C" GDExtensionsInterfaceEditorHelpLoadXmlFromUtf8CharsAndLen gdextension_interface_editor_help_load_xml_from_utf8_chars_and_len; extern "C" GDExtensionInterfaceImagePtrw gdextension_interface_image_ptrw; @@ -267,5 +267,3 @@ class GDExtensionBinding { }; } // namespace godot - -#endif // GODOT_GODOT_HPP diff --git a/include/godot_cpp/templates/cowdata.hpp b/include/godot_cpp/templates/cowdata.hpp index 8b2c477d..f7a48f42 100644 --- a/include/godot_cpp/templates/cowdata.hpp +++ b/include/godot_cpp/templates/cowdata.hpp @@ -30,8 +30,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ -#ifndef GODOT_COWDATA_HPP -#define GODOT_COWDATA_HPP +#pragma once #include #include @@ -40,8 +39,10 @@ #include #include +#include #include #include +#include namespace godot { @@ -169,13 +170,25 @@ class CowData { return *out; } - void _unref(void *p_data); + // Decrements the reference count. Deallocates the backing buffer if needed. + // After this function, _ptr is guaranteed to be NULL. + void _unref(); void _ref(const CowData *p_from); void _ref(const CowData &p_from); USize _copy_on_write(); + Error _realloc(Size p_alloc_size); public: void operator=(const CowData &p_from) { _ref(p_from); } + void operator=(CowData &&p_from) { + if (_ptr == p_from._ptr) { + return; + } + + _unref(); + _ptr = p_from._ptr; + p_from._ptr = nullptr; + } _FORCE_INLINE_ T *ptrw() { _copy_on_write(); @@ -224,19 +237,22 @@ class CowData { T *p = ptrw(); Size len = size(); for (Size i = p_index; i < len - 1; i++) { - p[i] = p[i + 1]; + p[i] = std::move(p[i + 1]); } resize(len - 1); } Error insert(Size p_pos, const T &p_val) { - ERR_FAIL_INDEX_V(p_pos, size() + 1, ERR_INVALID_PARAMETER); - resize(size() + 1); - for (Size i = (size() - 1); i > p_pos; i--) { - set(i, get(i - 1)); + Size new_size = size() + 1; + ERR_FAIL_INDEX_V(p_pos, new_size, ERR_INVALID_PARAMETER); + Error err = resize(new_size); + ERR_FAIL_COND_V(err, err); + T *p = ptrw(); + for (Size i = new_size - 1; i > p_pos; i--) { + p[i] = std::move(p[i - 1]); } - set(p_pos, p_val); + p[p_pos] = p_val; return OK; } @@ -246,35 +262,47 @@ class CowData { Size count(const T &p_val) const; _FORCE_INLINE_ CowData() {} - _FORCE_INLINE_ ~CowData(); - _FORCE_INLINE_ CowData(CowData &p_from) { _ref(p_from); }; + _FORCE_INLINE_ ~CowData() { _unref(); } + _FORCE_INLINE_ CowData(std::initializer_list p_init); + _FORCE_INLINE_ CowData(const CowData &p_from) { _ref(p_from); } + _FORCE_INLINE_ CowData(CowData &&p_from) { + _ptr = p_from._ptr; + p_from._ptr = nullptr; + } }; template -void CowData::_unref(void *p_data) { - if (!p_data) { +void CowData::_unref() { + if (!_ptr) { return; } SafeNumeric *refc = _get_refcount(); - if (refc->decrement() > 0) { - return; // still in use + // Data is still in use elsewhere. + _ptr = nullptr; + return; } - // clean up + // Clean up. + // First, invalidate our own reference. + // NOTE: It is required to do so immediately because it must not be observable outside of this + // function after refcount has already been reduced to 0. + // WARNING: It must be done before calling the destructors, because one of them may otherwise + // observe it through a reference to us. In this case, it may try to access the buffer, + // which is illegal after some of the elements in it have already been destructed, and + // may lead to a segmentation fault. + USize current_size = *_get_size(); + T *prev_ptr = _ptr; + _ptr = nullptr; if constexpr (!std::is_trivially_destructible_v) { - USize *count = _get_size(); - T *data = (T *)(count + 1); - - for (USize i = 0; i < *count; ++i) { - // call destructors - data[i].~T(); + for (USize i = 0; i < current_size; ++i) { + prev_ptr[i].~T(); } } // free mem - Memory::free_static(((uint8_t *)p_data) - DATA_OFFSET, false); + Memory::free_static((uint8_t *)prev_ptr - DATA_OFFSET, false); } template @@ -309,7 +337,7 @@ typename CowData::USize CowData::_copy_on_write() { } } - _unref(_ptr); + _unref(); _ptr = _data_ptr; rc = 1; @@ -329,14 +357,13 @@ Error CowData::resize(Size p_size) { } if (p_size == 0) { - // wants to clean up - _unref(_ptr); - _ptr = nullptr; + // Wants to clean up. + _unref(); // Resets _ptr to nullptr. return OK; } // possibly changing size, copy on write - USize rc = _copy_on_write(); + _copy_on_write(); USize current_alloc_size = _get_alloc_size(current_size); USize alloc_size; @@ -357,16 +384,12 @@ Error CowData::resize(Size p_size) { *(_size_ptr) = 0; //size, currently none _ptr = _data_ptr; - } else { - uint8_t *mem_new = (uint8_t *)Memory::realloc_static(((uint8_t *)_ptr) - DATA_OFFSET, alloc_size + DATA_OFFSET, false); - ERR_FAIL_NULL_V(mem_new, ERR_OUT_OF_MEMORY); - - SafeNumeric *_refc_ptr = _get_refcount_ptr(mem_new); - T *_data_ptr = _get_data_ptr(mem_new); - - new (_refc_ptr) SafeNumeric(rc); //refcount - _ptr = _data_ptr; + } else { + const Error error = _realloc(alloc_size); + if (error) { + return error; + } } } @@ -392,15 +415,10 @@ Error CowData::resize(Size p_size) { } if (alloc_size != current_alloc_size) { - uint8_t *mem_new = (uint8_t *)Memory::realloc_static(((uint8_t *)_ptr) - DATA_OFFSET, alloc_size + DATA_OFFSET, false); - ERR_FAIL_NULL_V(mem_new, ERR_OUT_OF_MEMORY); - - SafeNumeric *_refc_ptr = _get_refcount_ptr(mem_new); - T *_data_ptr = _get_data_ptr(mem_new); - - new (_refc_ptr) SafeNumeric(rc); //refcount - - _ptr = _data_ptr; + const Error error = _realloc(alloc_size); + if (error) { + return error; + } } *_get_size() = p_size; @@ -409,6 +427,21 @@ Error CowData::resize(Size p_size) { return OK; } +template +Error CowData::_realloc(Size p_alloc_size) { + uint8_t *mem_new = (uint8_t *)Memory::realloc_static(((uint8_t *)_ptr) - DATA_OFFSET, p_alloc_size + DATA_OFFSET, false); + ERR_FAIL_NULL_V(mem_new, ERR_OUT_OF_MEMORY); + + SafeNumeric *_refc_ptr = _get_refcount_ptr(mem_new); + T *_data_ptr = _get_data_ptr(mem_new); + + // If we realloc, we're guaranteed to be the only reference. + new (_refc_ptr) SafeNumeric(1); + _ptr = _data_ptr; + + return OK; +} + template typename CowData::Size CowData::find(const T &p_val, Size p_from) const { Size ret = -1; @@ -468,11 +501,10 @@ void CowData::_ref(const CowData &p_from) { return; // self assign, do nothing. } - _unref(_ptr); - _ptr = nullptr; + _unref(); // Resets _ptr to nullptr. if (!p_from._ptr) { - return; // nothing to do + return; //nothing to do } if (p_from._get_refcount()->conditional_increment() > 0) { // could reference @@ -481,8 +513,16 @@ void CowData::_ref(const CowData &p_from) { } template -CowData::~CowData() { - _unref(_ptr); +CowData::CowData(std::initializer_list p_init) { + Error err = resize(p_init.size()); + if (err != OK) { + return; + } + + Size i = 0; + for (const T &element : p_init) { + set(i++, element); + } } #if defined(__GNUC__) && !defined(__clang__) @@ -490,5 +530,3 @@ CowData::~CowData() { #endif } // namespace godot - -#endif // GODOT_COWDATA_HPP diff --git a/include/godot_cpp/templates/hash_map.hpp b/include/godot_cpp/templates/hash_map.hpp index 2596792b..d6df5dcc 100644 --- a/include/godot_cpp/templates/hash_map.hpp +++ b/include/godot_cpp/templates/hash_map.hpp @@ -30,8 +30,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ -#ifndef GODOT_HASH_MAP_HPP -#define GODOT_HASH_MAP_HPP +#pragma once #include #include @@ -64,15 +63,17 @@ struct HashMapElement { data(p_key, p_value) {} }; +bool _hashmap_variant_less_than(const Variant &p_left, const Variant &p_right); + template , typename Allocator = DefaultTypedAllocator>> class HashMap { public: - const uint32_t MIN_CAPACITY_INDEX = 2; // Use a prime. - const float MAX_OCCUPANCY = 0.75; - const uint32_t EMPTY_HASH = 0; + static constexpr uint32_t MIN_CAPACITY_INDEX = 2; // Use a prime. + static constexpr float MAX_OCCUPANCY = 0.75; + static constexpr uint32_t EMPTY_HASH = 0; private: Allocator element_alloc; @@ -94,19 +95,20 @@ class HashMap { return hash; } - _FORCE_INLINE_ uint32_t _get_probe_length(uint32_t p_pos, uint32_t p_hash, uint32_t p_capacity) const { - uint32_t original_pos = p_hash % p_capacity; - return (p_pos - original_pos + p_capacity) % p_capacity; + static _FORCE_INLINE_ uint32_t _get_probe_length(const uint32_t p_pos, const uint32_t p_hash, const uint32_t p_capacity, const uint64_t p_capacity_inv) { + const uint32_t original_pos = fastmod(p_hash, p_capacity_inv, p_capacity); + return fastmod(p_pos - original_pos + p_capacity, p_capacity_inv, p_capacity); } bool _lookup_pos(const TKey &p_key, uint32_t &r_pos) const { - if (elements == nullptr) { + if (elements == nullptr || num_elements == 0) { return false; // Failed lookups, no elements } - uint32_t capacity = hash_table_size_primes[capacity_index]; + const uint32_t capacity = hash_table_size_primes[capacity_index]; + const uint64_t capacity_inv = hash_table_size_primes_inv[capacity_index]; uint32_t hash = _hash(p_key); - uint32_t pos = hash % capacity; + uint32_t pos = fastmod(hash, capacity_inv, capacity); uint32_t distance = 0; while (true) { @@ -114,7 +116,7 @@ class HashMap { return false; } - if (distance > _get_probe_length(pos, hashes[pos], capacity)) { + if (distance > _get_probe_length(pos, hashes[pos], capacity, capacity_inv)) { return false; } @@ -123,17 +125,18 @@ class HashMap { return true; } - pos = (pos + 1) % capacity; + pos = fastmod((pos + 1), capacity_inv, capacity); distance++; } } void _insert_with_hash(uint32_t p_hash, HashMapElement *p_value) { - uint32_t capacity = hash_table_size_primes[capacity_index]; + const uint32_t capacity = hash_table_size_primes[capacity_index]; + const uint64_t capacity_inv = hash_table_size_primes_inv[capacity_index]; uint32_t hash = p_hash; HashMapElement *value = p_value; uint32_t distance = 0; - uint32_t pos = hash % capacity; + uint32_t pos = fastmod(hash, capacity_inv, capacity); while (true) { if (hashes[pos] == EMPTY_HASH) { @@ -146,14 +149,14 @@ class HashMap { } // Not an empty slot, let's check the probing length of the existing one. - uint32_t existing_probe_len = _get_probe_length(pos, hashes[pos], capacity); + uint32_t existing_probe_len = _get_probe_length(pos, hashes[pos], capacity, capacity_inv); if (existing_probe_len < distance) { SWAP(hash, hashes[pos]); SWAP(value, elements[pos]); distance = existing_probe_len; } - pos = (pos + 1) % capacity; + pos = fastmod((pos + 1), capacity_inv, capacity); distance++; } } @@ -253,7 +256,7 @@ class HashMap { } void clear() { - if (elements == nullptr) { + if (elements == nullptr || num_elements == 0) { return; } uint32_t capacity = hash_table_size_primes[capacity_index]; @@ -272,6 +275,47 @@ class HashMap { num_elements = 0; } + void sort() { + if (elements == nullptr || num_elements < 2) { + return; // An empty or single element HashMap is already sorted. + } + // Use insertion sort because we want this operation to be fast for the + // common case where the input is already sorted or nearly sorted. + HashMapElement *inserting = head_element->next; + while (inserting != nullptr) { + HashMapElement *after = nullptr; + for (HashMapElement *current = inserting->prev; current != nullptr; current = current->prev) { + if (_hashmap_variant_less_than(inserting->data.key, current->data.key)) { + after = current; + } else { + break; + } + } + HashMapElement *next = inserting->next; + if (after != nullptr) { + // Modify the elements around `inserting` to remove it from its current position. + inserting->prev->next = next; + if (next == nullptr) { + tail_element = inserting->prev; + } else { + next->prev = inserting->prev; + } + // Modify `before` and `after` to insert `inserting` between them. + HashMapElement *before = after->prev; + if (before == nullptr) { + head_element = inserting; + } else { + before->next = inserting; + } + after->prev = inserting; + // Point `inserting` to its new surroundings. + inserting->prev = before; + inserting->next = after; + } + inserting = next; + } + } + TValue &get(const TKey &p_key) { uint32_t pos = 0; bool exists = _lookup_pos(p_key, pos); @@ -319,13 +363,14 @@ class HashMap { return false; } - uint32_t capacity = hash_table_size_primes[capacity_index]; - uint32_t next_pos = (pos + 1) % capacity; - while (hashes[next_pos] != EMPTY_HASH && _get_probe_length(next_pos, hashes[next_pos], capacity) != 0) { + const uint32_t capacity = hash_table_size_primes[capacity_index]; + const uint64_t capacity_inv = hash_table_size_primes_inv[capacity_index]; + uint32_t next_pos = fastmod((pos + 1), capacity_inv, capacity); + while (hashes[next_pos] != EMPTY_HASH && _get_probe_length(next_pos, hashes[next_pos], capacity, capacity_inv) != 0) { SWAP(hashes[next_pos], hashes[pos]); SWAP(elements[next_pos], elements[pos]); pos = next_pos; - next_pos = (pos + 1) % capacity; + next_pos = fastmod((pos + 1), capacity_inv, capacity); } hashes[pos] = EMPTY_HASH; @@ -353,6 +398,40 @@ class HashMap { return true; } + // Replace the key of an entry in-place, without invalidating iterators or changing the entries position during iteration. + // p_old_key must exist in the map and p_new_key must not, unless it is equal to p_old_key. + bool replace_key(const TKey &p_old_key, const TKey &p_new_key) { + if (p_old_key == p_new_key) { + return true; + } + uint32_t pos = 0; + ERR_FAIL_COND_V(_lookup_pos(p_new_key, pos), false); + ERR_FAIL_COND_V(!_lookup_pos(p_old_key, pos), false); + HashMapElement *element = elements[pos]; + + // Delete the old entries in hashes and elements. + const uint32_t capacity = hash_table_size_primes[capacity_index]; + const uint64_t capacity_inv = hash_table_size_primes_inv[capacity_index]; + uint32_t next_pos = fastmod((pos + 1), capacity_inv, capacity); + while (hashes[next_pos] != EMPTY_HASH && _get_probe_length(next_pos, hashes[next_pos], capacity, capacity_inv) != 0) { + SWAP(hashes[next_pos], hashes[pos]); + SWAP(elements[next_pos], elements[pos]); + pos = next_pos; + next_pos = fastmod((pos + 1), capacity_inv, capacity); + } + hashes[pos] = EMPTY_HASH; + elements[pos] = nullptr; + // _insert_with_hash will increment this again. + num_elements--; + + // Update the HashMapElement with the new key and reinsert it. + const_cast(element->data.key) = p_new_key; + uint32_t hash = _hash(p_new_key); + _insert_with_hash(hash, element); + + return true; + } + // Reserves space for a number of elements, useful to avoid many resizes and rehashes. // If adding a known (possibly large) number of elements at once, must be larger than old capacity. void reserve(uint32_t p_new_capacity) { @@ -563,6 +642,13 @@ class HashMap { capacity_index = MIN_CAPACITY_INDEX; } + HashMap(std::initializer_list> p_init) { + reserve(p_init.size()); + for (const KeyValue &E : p_init) { + insert(E.key, E.value); + } + } + uint32_t debug_get_hash(uint32_t p_index) { if (num_elements == 0) { return 0; @@ -589,5 +675,3 @@ class HashMap { }; } // namespace godot - -#endif // GODOT_HASH_MAP_HPP diff --git a/include/godot_cpp/templates/hash_set.hpp b/include/godot_cpp/templates/hash_set.hpp index cdcc6b6c..61e076bd 100644 --- a/include/godot_cpp/templates/hash_set.hpp +++ b/include/godot_cpp/templates/hash_set.hpp @@ -30,8 +30,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ -#ifndef GODOT_HASH_SET_HPP -#define GODOT_HASH_SET_HPP +#pragma once #include #include @@ -78,19 +77,20 @@ class HashSet { return hash; } - _FORCE_INLINE_ uint32_t _get_probe_length(uint32_t p_pos, uint32_t p_hash, uint32_t p_capacity) const { - uint32_t original_pos = p_hash % p_capacity; - return (p_pos - original_pos + p_capacity) % p_capacity; + static _FORCE_INLINE_ uint32_t _get_probe_length(const uint32_t p_pos, const uint32_t p_hash, const uint32_t p_capacity, const uint64_t p_capacity_inv) { + const uint32_t original_pos = fastmod(p_hash, p_capacity_inv, p_capacity); + return fastmod(p_pos - original_pos + p_capacity, p_capacity_inv, p_capacity); } bool _lookup_pos(const TKey &p_key, uint32_t &r_pos) const { - if (keys == nullptr) { + if (keys == nullptr || num_elements == 0) { return false; // Failed lookups, no elements } - uint32_t capacity = hash_table_size_primes[capacity_index]; + const uint32_t capacity = hash_table_size_primes[capacity_index]; + const uint64_t capacity_inv = hash_table_size_primes_inv[capacity_index]; uint32_t hash = _hash(p_key); - uint32_t pos = hash % capacity; + uint32_t pos = fastmod(hash, capacity_inv, capacity); uint32_t distance = 0; while (true) { @@ -98,7 +98,7 @@ class HashSet { return false; } - if (distance > _get_probe_length(pos, hashes[pos], capacity)) { + if (distance > _get_probe_length(pos, hashes[pos], capacity, capacity_inv)) { return false; } @@ -107,17 +107,18 @@ class HashSet { return true; } - pos = (pos + 1) % capacity; + pos = fastmod(pos + 1, capacity_inv, capacity); distance++; } } uint32_t _insert_with_hash(uint32_t p_hash, uint32_t p_index) { - uint32_t capacity = hash_table_size_primes[capacity_index]; + const uint32_t capacity = hash_table_size_primes[capacity_index]; + const uint64_t capacity_inv = hash_table_size_primes_inv[capacity_index]; uint32_t hash = p_hash; uint32_t index = p_index; uint32_t distance = 0; - uint32_t pos = hash % capacity; + uint32_t pos = fastmod(hash, capacity_inv, capacity); while (true) { if (hashes[pos] == EMPTY_HASH) { @@ -128,7 +129,7 @@ class HashSet { } // Not an empty slot, let's check the probing length of the existing one. - uint32_t existing_probe_len = _get_probe_length(pos, hashes[pos], capacity); + uint32_t existing_probe_len = _get_probe_length(pos, hashes[pos], capacity, capacity_inv); if (existing_probe_len < distance) { key_to_hash[index] = pos; SWAP(hash, hashes[pos]); @@ -136,7 +137,7 @@ class HashSet { distance = existing_probe_len; } - pos = (pos + 1) % capacity; + pos = fastmod(pos + 1, capacity_inv, capacity); distance++; } } @@ -239,7 +240,7 @@ class HashSet { } void clear() { - if (keys == nullptr) { + if (keys == nullptr || num_elements == 0) { return; } uint32_t capacity = hash_table_size_primes[capacity_index]; @@ -267,11 +268,12 @@ class HashSet { } uint32_t key_pos = pos; - pos = key_to_hash[pos]; // make hash pos + pos = key_to_hash[pos]; //make hash pos - uint32_t capacity = hash_table_size_primes[capacity_index]; - uint32_t next_pos = (pos + 1) % capacity; - while (hashes[next_pos] != EMPTY_HASH && _get_probe_length(next_pos, hashes[next_pos], capacity) != 0) { + const uint32_t capacity = hash_table_size_primes[capacity_index]; + const uint64_t capacity_inv = hash_table_size_primes_inv[capacity_index]; + uint32_t next_pos = fastmod(pos + 1, capacity_inv, capacity); + while (hashes[next_pos] != EMPTY_HASH && _get_probe_length(next_pos, hashes[next_pos], capacity, capacity_inv) != 0) { uint32_t kpos = hash_to_key[pos]; uint32_t kpos_next = hash_to_key[next_pos]; SWAP(key_to_hash[kpos], key_to_hash[kpos_next]); @@ -279,7 +281,7 @@ class HashSet { SWAP(hash_to_key[next_pos], hash_to_key[pos]); pos = next_pos; - next_pos = (pos + 1) % capacity; + next_pos = fastmod(pos + 1, capacity_inv, capacity); } hashes[pos] = EMPTY_HASH; @@ -446,6 +448,13 @@ class HashSet { capacity_index = MIN_CAPACITY_INDEX; } + HashSet(std::initializer_list p_init) { + reserve(p_init.size()); + for (const TKey &E : p_init) { + insert(E); + } + } + void reset() { clear(); @@ -475,5 +484,3 @@ class HashSet { }; } // namespace godot - -#endif // GODOT_HASH_SET_HPP diff --git a/include/godot_cpp/templates/hashfuncs.hpp b/include/godot_cpp/templates/hashfuncs.hpp index 2618a51b..108b943f 100644 --- a/include/godot_cpp/templates/hashfuncs.hpp +++ b/include/godot_cpp/templates/hashfuncs.hpp @@ -30,8 +30,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ -#ifndef GODOT_HASHFUNCS_HPP -#define GODOT_HASHFUNCS_HPP +#pragma once // Needed for fastmod. #if defined(_MSC_VER) @@ -69,10 +68,11 @@ namespace godot { static _FORCE_INLINE_ uint32_t hash_djb2(const char *p_cstr) { const unsigned char *chr = (const unsigned char *)p_cstr; uint32_t hash = 5381; - uint32_t c; + uint32_t c = *chr++; - while ((c = *chr++)) { + while (c) { hash = ((hash << 5) + hash) ^ c; /* hash * 33 ^ c */ + c = *chr++; } return hash; @@ -110,6 +110,16 @@ static _FORCE_INLINE_ uint32_t hash_one_uint64(const uint64_t p_int) { return uint32_t(v); } +static _FORCE_INLINE_ uint64_t hash64_murmur3_64(uint64_t key, uint64_t seed) { + key ^= seed; + key ^= key >> 33; + key *= 0xff51afd7ed558ccd; + key ^= key >> 33; + key *= 0xc4ceb9fe1a85ec53; + key ^= key >> 33; + return key; +} + #define HASH_MURMUR3_SEED 0x7F07C65 // Murmurhash3 32-bit version. // All MurmurHash versions are public domain software, and the author disclaims all copyright to their code. @@ -230,7 +240,7 @@ static _FORCE_INLINE_ uint32_t hash_murmur3_buffer(const void *key, int length, k1 = hash_rotl32(k1, 15); k1 *= c2; h1 ^= k1; - } + }; // Finalize with additional bit mixing. h1 ^= length; @@ -313,40 +323,41 @@ struct HashMapHasherDefault { static _FORCE_INLINE_ uint32_t hash(const String &p_string) { return p_string.hash(); } static _FORCE_INLINE_ uint32_t hash(const char *p_cstr) { return hash_djb2(p_cstr); } - static _FORCE_INLINE_ uint32_t hash(const wchar_t p_wchar) { return hash_fmix32(p_wchar); } - static _FORCE_INLINE_ uint32_t hash(const char16_t p_uchar) { return hash_fmix32(p_uchar); } - static _FORCE_INLINE_ uint32_t hash(const char32_t p_uchar) { return hash_fmix32(p_uchar); } + static _FORCE_INLINE_ uint32_t hash(const wchar_t p_wchar) { return hash_fmix32(uint32_t(p_wchar)); } + static _FORCE_INLINE_ uint32_t hash(const char16_t p_uchar) { return hash_fmix32(uint32_t(p_uchar)); } + static _FORCE_INLINE_ uint32_t hash(const char32_t p_uchar) { return hash_fmix32(uint32_t(p_uchar)); } static _FORCE_INLINE_ uint32_t hash(const RID &p_rid) { return hash_one_uint64(p_rid.get_id()); } + static _FORCE_INLINE_ uint32_t hash(const CharString &p_char_string) { return hash_djb2(p_char_string.get_data()); } static _FORCE_INLINE_ uint32_t hash(const StringName &p_string_name) { return p_string_name.hash(); } static _FORCE_INLINE_ uint32_t hash(const NodePath &p_path) { return p_path.hash(); } static _FORCE_INLINE_ uint32_t hash(const ObjectID &p_id) { return hash_one_uint64(p_id); } static _FORCE_INLINE_ uint32_t hash(const uint64_t p_int) { return hash_one_uint64(p_int); } - static _FORCE_INLINE_ uint32_t hash(const int64_t p_int) { return hash_one_uint64(p_int); } + static _FORCE_INLINE_ uint32_t hash(const int64_t p_int) { return hash_one_uint64(uint64_t(p_int)); } static _FORCE_INLINE_ uint32_t hash(const float p_float) { return hash_murmur3_one_float(p_float); } static _FORCE_INLINE_ uint32_t hash(const double p_double) { return hash_murmur3_one_double(p_double); } static _FORCE_INLINE_ uint32_t hash(const uint32_t p_int) { return hash_fmix32(p_int); } - static _FORCE_INLINE_ uint32_t hash(const int32_t p_int) { return hash_fmix32(p_int); } - static _FORCE_INLINE_ uint32_t hash(const uint16_t p_int) { return hash_fmix32(p_int); } - static _FORCE_INLINE_ uint32_t hash(const int16_t p_int) { return hash_fmix32(p_int); } - static _FORCE_INLINE_ uint32_t hash(const uint8_t p_int) { return hash_fmix32(p_int); } - static _FORCE_INLINE_ uint32_t hash(const int8_t p_int) { return hash_fmix32(p_int); } + static _FORCE_INLINE_ uint32_t hash(const int32_t p_int) { return hash_fmix32(uint32_t(p_int)); } + static _FORCE_INLINE_ uint32_t hash(const uint16_t p_int) { return hash_fmix32(uint32_t(p_int)); } + static _FORCE_INLINE_ uint32_t hash(const int16_t p_int) { return hash_fmix32(uint32_t(p_int)); } + static _FORCE_INLINE_ uint32_t hash(const uint8_t p_int) { return hash_fmix32(uint32_t(p_int)); } + static _FORCE_INLINE_ uint32_t hash(const int8_t p_int) { return hash_fmix32(uint32_t(p_int)); } static _FORCE_INLINE_ uint32_t hash(const Vector2i &p_vec) { - uint32_t h = hash_murmur3_one_32(p_vec.x); - h = hash_murmur3_one_32(p_vec.y, h); + uint32_t h = hash_murmur3_one_32(uint32_t(p_vec.x)); + h = hash_murmur3_one_32(uint32_t(p_vec.y), h); return hash_fmix32(h); } static _FORCE_INLINE_ uint32_t hash(const Vector3i &p_vec) { - uint32_t h = hash_murmur3_one_32(p_vec.x); - h = hash_murmur3_one_32(p_vec.y, h); - h = hash_murmur3_one_32(p_vec.z, h); + uint32_t h = hash_murmur3_one_32(uint32_t(p_vec.x)); + h = hash_murmur3_one_32(uint32_t(p_vec.y), h); + h = hash_murmur3_one_32(uint32_t(p_vec.z), h); return hash_fmix32(h); } static _FORCE_INLINE_ uint32_t hash(const Vector4i &p_vec) { - uint32_t h = hash_murmur3_one_32(p_vec.x); - h = hash_murmur3_one_32(p_vec.y, h); - h = hash_murmur3_one_32(p_vec.z, h); - h = hash_murmur3_one_32(p_vec.w, h); + uint32_t h = hash_murmur3_one_32(uint32_t(p_vec.x)); + h = hash_murmur3_one_32(uint32_t(p_vec.y), h); + h = hash_murmur3_one_32(uint32_t(p_vec.z), h); + h = hash_murmur3_one_32(uint32_t(p_vec.w), h); return hash_fmix32(h); } static _FORCE_INLINE_ uint32_t hash(const Vector2 &p_vec) { @@ -368,10 +379,10 @@ struct HashMapHasherDefault { return hash_fmix32(h); } static _FORCE_INLINE_ uint32_t hash(const Rect2i &p_rect) { - uint32_t h = hash_murmur3_one_32(p_rect.position.x); - h = hash_murmur3_one_32(p_rect.position.y, h); - h = hash_murmur3_one_32(p_rect.size.x, h); - h = hash_murmur3_one_32(p_rect.size.y, h); + uint32_t h = hash_murmur3_one_32(uint32_t(p_rect.position.x)); + h = hash_murmur3_one_32(uint32_t(p_rect.position.y), h); + h = hash_murmur3_one_32(uint32_t(p_rect.size.x), h); + h = hash_murmur3_one_32(uint32_t(p_rect.size.y), h); return hash_fmix32(h); } static _FORCE_INLINE_ uint32_t hash(const Rect2 &p_rect) { @@ -392,6 +403,19 @@ struct HashMapHasherDefault { } }; +struct HashHasher { + static _FORCE_INLINE_ uint32_t hash(const int32_t hash) { return hash; } + static _FORCE_INLINE_ uint32_t hash(const uint32_t hash) { return hash; } + static _FORCE_INLINE_ uint64_t hash(const int64_t hash) { return hash; } + static _FORCE_INLINE_ uint64_t hash(const uint64_t hash) { return hash; } +}; + +// TODO: Fold this into HashMapHasherDefault once C++20 concepts are allowed +template +struct HashableHasher { + static _FORCE_INLINE_ uint32_t hash(const T &hashable) { return hashable.hash(); } +}; + template struct HashMapComparatorDefault { static bool compare(const T &p_lhs, const T &p_rhs) { @@ -413,6 +437,13 @@ struct HashMapComparatorDefault { } }; +template <> +struct HashMapComparatorDefault { + static bool compare(const Color &p_lhs, const Color &p_rhs) { + return ((p_lhs.r == p_rhs.r) || (Math::is_nan(p_lhs.r) && Math::is_nan(p_rhs.r))) && ((p_lhs.g == p_rhs.g) || (Math::is_nan(p_lhs.g) && Math::is_nan(p_rhs.g))) && ((p_lhs.b == p_rhs.b) || (Math::is_nan(p_lhs.b) && Math::is_nan(p_rhs.b))) && ((p_lhs.a == p_rhs.a) || (Math::is_nan(p_lhs.a) && Math::is_nan(p_rhs.a))); + } +}; + template <> struct HashMapComparatorDefault { static bool compare(const Vector2 &p_lhs, const Vector2 &p_rhs) { @@ -427,9 +458,90 @@ struct HashMapComparatorDefault { } }; +template <> +struct HashMapComparatorDefault { + static bool compare(const Vector4 &p_lhs, const Vector4 &p_rhs) { + return ((p_lhs.x == p_rhs.x) || (Math::is_nan(p_lhs.x) && Math::is_nan(p_rhs.x))) && ((p_lhs.y == p_rhs.y) || (Math::is_nan(p_lhs.y) && Math::is_nan(p_rhs.y))) && ((p_lhs.z == p_rhs.z) || (Math::is_nan(p_lhs.z) && Math::is_nan(p_rhs.z))) && ((p_lhs.w == p_rhs.w) || (Math::is_nan(p_lhs.w) && Math::is_nan(p_rhs.w))); + } +}; + +template <> +struct HashMapComparatorDefault { + static bool compare(const Rect2 &p_lhs, const Rect2 &p_rhs) { + return HashMapComparatorDefault().compare(p_lhs.position, p_rhs.position) && HashMapComparatorDefault().compare(p_lhs.size, p_rhs.size); + } +}; + +template <> +struct HashMapComparatorDefault { + static bool compare(const AABB &p_lhs, const AABB &p_rhs) { + return HashMapComparatorDefault().compare(p_lhs.position, p_rhs.position) && HashMapComparatorDefault().compare(p_lhs.size, p_rhs.size); + } +}; + +template <> +struct HashMapComparatorDefault { + static bool compare(const Plane &p_lhs, const Plane &p_rhs) { + return HashMapComparatorDefault().compare(p_lhs.normal, p_rhs.normal) && ((p_lhs.d == p_rhs.d) || (Math::is_nan(p_lhs.d) && Math::is_nan(p_rhs.d))); + } +}; + +template <> +struct HashMapComparatorDefault { + static bool compare(const Transform2D &p_lhs, const Transform2D &p_rhs) { + for (int i = 0; i < 3; ++i) { + if (!HashMapComparatorDefault().compare(p_lhs.columns[i], p_rhs.columns[i])) { + return false; + } + } + + return true; + } +}; + +template <> +struct HashMapComparatorDefault { + static bool compare(const Basis &p_lhs, const Basis &p_rhs) { + for (int i = 0; i < 3; ++i) { + if (!HashMapComparatorDefault().compare(p_lhs.rows[i], p_rhs.rows[i])) { + return false; + } + } + + return true; + } +}; + +template <> +struct HashMapComparatorDefault { + static bool compare(const Transform3D &p_lhs, const Transform3D &p_rhs) { + return HashMapComparatorDefault().compare(p_lhs.basis, p_rhs.basis) && HashMapComparatorDefault().compare(p_lhs.origin, p_rhs.origin); + } +}; + +template <> +struct HashMapComparatorDefault { + static bool compare(const Projection &p_lhs, const Projection &p_rhs) { + for (int i = 0; i < 4; ++i) { + if (!HashMapComparatorDefault().compare(p_lhs.columns[i], p_rhs.columns[i])) { + return false; + } + } + + return true; + } +}; + +template <> +struct HashMapComparatorDefault { + static bool compare(const Quaternion &p_lhs, const Quaternion &p_rhs) { + return ((p_lhs.x == p_rhs.x) || (Math::is_nan(p_lhs.x) && Math::is_nan(p_rhs.x))) && ((p_lhs.y == p_rhs.y) || (Math::is_nan(p_lhs.y) && Math::is_nan(p_rhs.y))) && ((p_lhs.z == p_rhs.z) || (Math::is_nan(p_lhs.z) && Math::is_nan(p_rhs.z))) && ((p_lhs.w == p_rhs.w) || (Math::is_nan(p_lhs.w) && Math::is_nan(p_rhs.w))); + } +}; + constexpr uint32_t HASH_TABLE_SIZE_MAX = 29; -const uint32_t hash_table_size_primes[HASH_TABLE_SIZE_MAX] = { +inline constexpr uint32_t hash_table_size_primes[HASH_TABLE_SIZE_MAX] = { 5, 13, 23, @@ -462,7 +574,7 @@ const uint32_t hash_table_size_primes[HASH_TABLE_SIZE_MAX] = { }; // Computed with elem_i = UINT64_C (0 x FFFFFFFF FFFFFFFF ) / d_i + 1, where d_i is the i-th element of the above array. -const uint64_t hash_table_size_primes_inv[HASH_TABLE_SIZE_MAX] = { +inline constexpr uint64_t hash_table_size_primes_inv[HASH_TABLE_SIZE_MAX] = { 3689348814741910324, 1418980313362273202, 802032351030850071, @@ -524,5 +636,3 @@ static _FORCE_INLINE_ uint32_t fastmod(const uint32_t n, const uint64_t c, const } } // namespace godot - -#endif // GODOT_HASHFUNCS_HPP diff --git a/include/godot_cpp/templates/list.hpp b/include/godot_cpp/templates/list.hpp index 7898bf75..af6df741 100644 --- a/include/godot_cpp/templates/list.hpp +++ b/include/godot_cpp/templates/list.hpp @@ -30,13 +30,14 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ -#ifndef GODOT_LIST_HPP -#define GODOT_LIST_HPP +#pragma once #include #include #include +#include + /** * Generic Templatized Linked List Implementation. * The implementation differs from the STL one because @@ -136,6 +137,8 @@ class List { data->erase(this); } + void transfer_to_back(List *p_dst_list); + _FORCE_INLINE_ Element() {} }; @@ -226,7 +229,7 @@ class List { Element *last = nullptr; int size_cache = 0; - bool erase(const Element *p_I) { + bool erase(Element *p_I) { ERR_FAIL_NULL_V(p_I, false); ERR_FAIL_COND_V(p_I->data != this, false); @@ -246,7 +249,7 @@ class List { p_I->next_ptr->prev_ptr = p_I->prev_ptr; } - memdelete_allocator(const_cast(p_I)); + memdelete_allocator(p_I); size_cache--; return true; @@ -432,7 +435,7 @@ class List { /** * erase an element in the list, by iterator pointing to it. Return true if it was found/erased. */ - bool erase(const Element *p_I) { + bool erase(Element *p_I) { if (_data && p_I) { bool ret = _data->erase(p_I); @@ -524,10 +527,14 @@ class List { it = it->next(); } } + void operator=(List &&p_list) { + if (unlikely(this == &p_list)) { + return; + } - // Index operator, kept for compatibility. - _FORCE_INLINE_ T &operator[](int p_index) { - return get(p_index); + clear(); + _data = p_list._data; + p_list._data = nullptr; } // Random access to elements, use with care, @@ -545,11 +552,6 @@ class List { return I->get(); } - // Index operator, kept for compatibility. - _FORCE_INLINE_ const T &operator[](int p_index) const { - return get(p_index); - } - // Random access to elements, use with care, // do not use for iteration. const T &get(int p_index) const { @@ -723,8 +725,8 @@ class List { template void sort_custom() { - // this version uses auxiliary memory for speed. - // if you don't want to use auxiliary memory, use the in_place version + //this version uses auxiliary memory for speed. + //if you don't want to use auxiliary memory, use the in_place version int s = size(); if (s < 2) { @@ -772,9 +774,19 @@ class List { it = it->next(); } } + List(List &&p_list) { + _data = p_list._data; + p_list._data = nullptr; + } List() {} + List(std::initializer_list p_init) { + for (const T &E : p_init) { + push_back(E); + } + } + ~List() { clear(); if (_data) { @@ -784,6 +796,41 @@ class List { } }; -} // namespace godot +template +void List::Element::transfer_to_back(List *p_dst_list) { + // Detach from current. + + if (data->first == this) { + data->first = data->first->next_ptr; + } + if (data->last == this) { + data->last = data->last->prev_ptr; + } + if (prev_ptr) { + prev_ptr->next_ptr = next_ptr; + } + if (next_ptr) { + next_ptr->prev_ptr = prev_ptr; + } + data->size_cache--; -#endif // GODOT_LIST_HPP + // Attach to the back of the new one. + + if (!p_dst_list->_data) { + p_dst_list->_data = memnew_allocator(_Data, A); + p_dst_list->_data->first = this; + p_dst_list->_data->last = nullptr; + p_dst_list->_data->size_cache = 0; + prev_ptr = nullptr; + } else { + p_dst_list->_data->last->next_ptr = this; + prev_ptr = p_dst_list->_data->last; + } + p_dst_list->_data->last = this; + next_ptr = nullptr; + + data = p_dst_list->_data; + p_dst_list->_data->size_cache++; +} + +} // namespace godot diff --git a/include/godot_cpp/templates/local_vector.hpp b/include/godot_cpp/templates/local_vector.hpp index 73a3ba4d..b448117e 100644 --- a/include/godot_cpp/templates/local_vector.hpp +++ b/include/godot_cpp/templates/local_vector.hpp @@ -30,8 +30,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ -#ifndef GODOT_LOCAL_VECTOR_HPP -#define GODOT_LOCAL_VECTOR_HPP +#pragma once #include #include @@ -61,21 +60,18 @@ class LocalVector { return data; } + // Must take a copy instead of a reference (see GH-31736). _FORCE_INLINE_ void push_back(T p_elem) { if (unlikely(count == capacity)) { - if (capacity == 0) { - capacity = 1; - } else { - capacity <<= 1; - } + capacity = tight ? (capacity + 1) : MAX((U)1, capacity << 1); data = (T *)memrealloc(data, capacity * sizeof(T)); CRASH_COND_MSG(!data, "Out of memory"); } - if constexpr (!std::is_trivially_constructible::value && !force_trivial) { + if constexpr (!std::is_trivially_constructible_v && !force_trivial) { memnew_placement(&data[count++], T(p_elem)); } else { - data[count++] = p_elem; + data[count++] = std::move(p_elem); } } @@ -83,31 +79,49 @@ class LocalVector { ERR_FAIL_UNSIGNED_INDEX(p_index, count); count--; for (U i = p_index; i < count; i++) { - data[i] = data[i + 1]; + data[i] = std::move(data[i + 1]); } - if constexpr (!std::is_trivially_destructible::value && !force_trivial) { + if constexpr (!std::is_trivially_destructible_v && !force_trivial) { data[count].~T(); } } /// Removes the item copying the last value into the position of the one to - /// remove. It's generally faster than `remove`. + /// remove. It's generally faster than `remove_at`. void remove_at_unordered(U p_index) { ERR_FAIL_INDEX(p_index, count); count--; if (count > p_index) { - data[p_index] = data[count]; + data[p_index] = std::move(data[count]); } - if constexpr (!std::is_trivially_destructible::value && !force_trivial) { + if constexpr (!std::is_trivially_destructible_v && !force_trivial) { data[count].~T(); } } - void erase(const T &p_val) { + _FORCE_INLINE_ bool erase(const T &p_val) { int64_t idx = find(p_val); if (idx >= 0) { remove_at(idx); + return true; + } + return false; + } + + U erase_multiple_unordered(const T &p_val) { + U from = 0; + U occurrences = 0; + while (true) { + int64_t idx = find(p_val, from); + + if (idx == -1) { + break; + } + remove_at_unordered(idx); + from = idx; + occurrences++; } + return occurrences; } void invert() { @@ -139,7 +153,7 @@ class LocalVector { _FORCE_INLINE_ U size() const { return count; } void resize(U p_size) { if (p_size < count) { - if constexpr (!std::is_trivially_destructible::value && !force_trivial) { + if constexpr (!std::is_trivially_destructible_v && !force_trivial) { for (U i = p_size; i < count; i++) { data[i].~T(); } @@ -147,16 +161,11 @@ class LocalVector { count = p_size; } else if (p_size > count) { if (unlikely(p_size > capacity)) { - if (capacity == 0) { - capacity = 1; - } - while (capacity < p_size) { - capacity <<= 1; - } + capacity = tight ? p_size : nearest_power_of_2_templated(p_size); data = (T *)memrealloc(data, capacity * sizeof(T)); CRASH_COND_MSG(!data, "Out of memory"); } - if constexpr (!std::is_trivially_constructible::value && !force_trivial) { + if constexpr (!std::is_trivially_constructible_v && !force_trivial) { for (U i = count; i < p_size; i++) { memnew_placement(&data[i], T); } @@ -240,13 +249,13 @@ class LocalVector { void insert(U p_pos, T p_val) { ERR_FAIL_UNSIGNED_INDEX(p_pos, count + 1); if (p_pos == count) { - push_back(p_val); + push_back(std::move(p_val)); } else { resize(count + 1); for (U i = count - 1; i > p_pos; i--) { - data[i] = data[i - 1]; + data[i] = std::move(data[i - 1]); } - data[p_pos] = p_val; + data[p_pos] = std::move(p_val); } } @@ -290,9 +299,17 @@ class LocalVector { operator Vector() const { Vector ret; - ret.resize(size()); + ret.resize(count); T *w = ret.ptrw(); - memcpy(w, data, sizeof(T) * count); + if (w) { + if constexpr (std::is_trivially_copyable_v) { + memcpy(w, data, sizeof(T) * count); + } else { + for (U i = 0; i < count; i++) { + w[i] = data[i]; + } + } + } return ret; } @@ -300,7 +317,9 @@ class LocalVector { Vector ret; ret.resize(count * sizeof(T)); uint8_t *w = ret.ptrw(); - memcpy(w, data, sizeof(T) * count); + if (w) { + memcpy(w, data, sizeof(T) * count); + } return ret; } @@ -317,6 +336,16 @@ class LocalVector { data[i] = p_from.data[i]; } } + _FORCE_INLINE_ LocalVector(LocalVector &&p_from) { + data = p_from.data; + count = p_from.count; + capacity = p_from.capacity; + + p_from.data = nullptr; + p_from.count = 0; + p_from.capacity = 0; + } + inline void operator=(const LocalVector &p_from) { resize(p_from.size()); for (U i = 0; i < p_from.count; i++) { @@ -329,6 +358,26 @@ class LocalVector { data[i] = p_from[i]; } } + inline void operator=(LocalVector &&p_from) { + if (unlikely(this == &p_from)) { + return; + } + reset(); + + data = p_from.data; + count = p_from.count; + capacity = p_from.capacity; + + p_from.data = nullptr; + p_from.count = 0; + p_from.capacity = 0; + } + inline void operator=(Vector &&p_from) { + resize(p_from.size()); + for (U i = 0; i < count; i++) { + data[i] = std::move(p_from[i]); + } + } _FORCE_INLINE_ ~LocalVector() { if (data) { @@ -341,5 +390,3 @@ template using TightLocalVector = LocalVector; } // namespace godot - -#endif // GODOT_LOCAL_VECTOR_HPP diff --git a/include/godot_cpp/templates/pair.hpp b/include/godot_cpp/templates/pair.hpp index 63953403..d552d19e 100644 --- a/include/godot_cpp/templates/pair.hpp +++ b/include/godot_cpp/templates/pair.hpp @@ -30,8 +30,9 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ -#ifndef GODOT_PAIR_HPP -#define GODOT_PAIR_HPP +#pragma once + +#include namespace godot { @@ -71,6 +72,15 @@ struct PairSort { } }; +template +struct PairHash { + static uint32_t hash(const Pair &P) { + uint64_t h1 = HashMapHasherDefault::hash(P.first); + uint64_t h2 = HashMapHasherDefault::hash(P.second); + return hash_one_uint64((h1 << 32) | h2); + } +}; + template struct KeyValue { const K key; @@ -105,5 +115,3 @@ struct KeyValueSort { }; } // namespace godot - -#endif // GODOT_PAIR_HPP diff --git a/include/godot_cpp/templates/rb_map.hpp b/include/godot_cpp/templates/rb_map.hpp index 038a7565..5f001c29 100644 --- a/include/godot_cpp/templates/rb_map.hpp +++ b/include/godot_cpp/templates/rb_map.hpp @@ -30,13 +30,14 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ -#ifndef GODOT_RB_MAP_HPP -#define GODOT_RB_MAP_HPP +#pragma once #include #include #include +#include + namespace godot { // based on the very nice implementation of rb-trees by: @@ -100,6 +101,8 @@ class RBMap { typedef KeyValue ValueType; struct Iterator { + friend class RBMap; + _FORCE_INLINE_ KeyValue &operator*() const { return E->key_value(); } @@ -113,11 +116,16 @@ class RBMap { return *this; } - _FORCE_INLINE_ bool operator==(const Iterator &b) const { return E == b.E; } - _FORCE_INLINE_ bool operator!=(const Iterator &b) const { return E != b.E; } + _FORCE_INLINE_ bool operator==(const Iterator &p_it) const { return E == p_it.E; } + _FORCE_INLINE_ bool operator!=(const Iterator &p_it) const { return E != p_it.E; } explicit operator bool() const { return E != nullptr; } + + Iterator &operator=(const Iterator &p_it) { + E = p_it.E; + return *this; + } Iterator(Element *p_E) { E = p_E; } Iterator() {} Iterator(const Iterator &p_it) { E = p_it.E; } @@ -140,11 +148,16 @@ class RBMap { return *this; } - _FORCE_INLINE_ bool operator==(const ConstIterator &b) const { return E == b.E; } - _FORCE_INLINE_ bool operator!=(const ConstIterator &b) const { return E != b.E; } + _FORCE_INLINE_ bool operator==(const ConstIterator &p_it) const { return E == p_it.E; } + _FORCE_INLINE_ bool operator!=(const ConstIterator &p_it) const { return E != p_it.E; } explicit operator bool() const { return E != nullptr; } + + ConstIterator &operator=(const ConstIterator &p_it) { + E = p_it.E; + return *this; + } ConstIterator(const Element *p_E) { E = p_E; } ConstIterator() {} ConstIterator(const ConstIterator &p_it) { E = p_it.E; } @@ -421,7 +434,7 @@ class RBMap { new_node->right = _data._nil; new_node->left = _data._nil; - // new_node->data=_data; + //new_node->data=_data; if (new_parent == _data._root || less(p_key, new_parent->_data.key)) { new_parent->left = new_node; @@ -755,6 +768,12 @@ class RBMap { _copy_from(p_map); } + RBMap(std::initializer_list> p_init) { + for (const KeyValue &E : p_init) { + insert(E.key, E.value); + } + } + _FORCE_INLINE_ RBMap() {} ~RBMap() { @@ -763,5 +782,3 @@ class RBMap { }; } // namespace godot - -#endif // GODOT_RB_MAP_HPP diff --git a/include/godot_cpp/templates/rb_set.hpp b/include/godot_cpp/templates/rb_set.hpp index de5adb53..ff92bdb4 100644 --- a/include/godot_cpp/templates/rb_set.hpp +++ b/include/godot_cpp/templates/rb_set.hpp @@ -30,11 +30,12 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ -#ifndef GODOT_RB_SET_HPP -#define GODOT_RB_SET_HPP +#pragma once #include +#include + // based on the very nice implementation of rb-trees by: // https://web.archive.org/web/20120507164830/https://web.mit.edu/~emin/www/source_code/red_black_tree/index.html @@ -401,7 +402,7 @@ class RBSet { new_node->right = _data._nil; new_node->left = _data._nil; new_node->value = p_value; - // new_node->data=_data; + //new_node->data=_data; if (new_parent == _data._root || less(p_value, new_parent->value)) { new_parent->left = new_node; @@ -704,6 +705,12 @@ class RBSet { _copy_from(p_set); } + RBSet(std::initializer_list p_init) { + for (const T &E : p_init) { + insert(E); + } + } + _FORCE_INLINE_ RBSet() {} ~RBSet() { @@ -712,5 +719,3 @@ class RBSet { }; } // namespace godot - -#endif // GODOT_RB_SET_HPP diff --git a/include/godot_cpp/templates/rid_owner.hpp b/include/godot_cpp/templates/rid_owner.hpp index e7b43fca..984f1af1 100644 --- a/include/godot_cpp/templates/rid_owner.hpp +++ b/include/godot_cpp/templates/rid_owner.hpp @@ -30,8 +30,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ -#ifndef GODOT_RID_OWNER_HPP -#define GODOT_RID_OWNER_HPP +#pragma once #include #include @@ -463,5 +462,3 @@ class RID_Owner { }; } // namespace godot - -#endif // GODOT_RID_OWNER_HPP diff --git a/include/godot_cpp/templates/safe_refcount.hpp b/include/godot_cpp/templates/safe_refcount.hpp index 15f8ccfe..4bb66e1e 100644 --- a/include/godot_cpp/templates/safe_refcount.hpp +++ b/include/godot_cpp/templates/safe_refcount.hpp @@ -30,8 +30,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ -#ifndef GODOT_SAFE_REFCOUNT_HPP -#define GODOT_SAFE_REFCOUNT_HPP +#pragma once #if !defined(NO_THREADS) @@ -54,7 +53,7 @@ namespace godot { #define SAFE_NUMERIC_TYPE_PUN_GUARANTEES(m_type) \ static_assert(sizeof(SafeNumeric) == sizeof(m_type)); \ static_assert(alignof(SafeNumeric) == alignof(m_type)); \ - static_assert(std::is_trivially_destructible>::value); + static_assert(std::is_trivially_destructible_v>); #define SAFE_FLAG_TYPE_PUN_GUARANTEES \ static_assert(sizeof(SafeFlag) == sizeof(bool)); \ static_assert(alignof(SafeFlag) == alignof(bool)); @@ -105,6 +104,17 @@ class SafeNumeric { return value.fetch_sub(p_value, std::memory_order_acq_rel) - p_value; } + _ALWAYS_INLINE_ T bit_or(T p_value) { + return value.fetch_or(p_value, std::memory_order_acq_rel); + } + _ALWAYS_INLINE_ T bit_and(T p_value) { + return value.fetch_and(p_value, std::memory_order_acq_rel); + } + + _ALWAYS_INLINE_ T bit_xor(T p_value) { + return value.fetch_xor(p_value, std::memory_order_acq_rel); + } + // Returns the original value instead of the new one _ALWAYS_INLINE_ T postsub(T p_value) { return value.fetch_sub(p_value, std::memory_order_acq_rel); @@ -116,7 +126,8 @@ class SafeNumeric { if (tmp >= p_value) { return tmp; // already greater, or equal } - if (value.compare_exchange_weak(tmp, p_value, std::memory_order_release)) { + + if (value.compare_exchange_weak(tmp, p_value, std::memory_order_acq_rel)) { return p_value; } } @@ -128,7 +139,7 @@ class SafeNumeric { if (c == 0) { return 0; } - if (value.compare_exchange_weak(c, c + 1, std::memory_order_release)) { + if (value.compare_exchange_weak(c, c + 1, std::memory_order_acq_rel)) { return c + 1; } } @@ -169,6 +180,16 @@ class SafeFlag { class SafeRefCount { SafeNumeric count; +#ifdef DEV_ENABLED + _ALWAYS_INLINE_ void _check_unref_safety() { + // This won't catch every misuse, but it's better than nothing. + CRASH_COND_MSG(count.get() == 0, + "Trying to unreference a SafeRefCount which is already zero is wrong and a symptom of it being misused.\n" + "Upon a SafeRefCount reaching zero any object whose lifetime is tied to it, as well as the ref count itself, must be destroyed.\n" + "Moreover, to guarantee that, no multiple threads should be racing to do the final unreferencing to zero."); + } +#endif + public: _ALWAYS_INLINE_ bool ref() { // true on success return count.conditional_increment() != 0; @@ -179,10 +200,16 @@ class SafeRefCount { } _ALWAYS_INLINE_ bool unref() { // true if must be disposed of +#ifdef DEV_ENABLED + _check_unref_safety(); +#endif return count.decrement() == 0; } _ALWAYS_INLINE_ uint32_t unrefval() { // 0 if must be disposed of +#ifdef DEV_ENABLED + _check_unref_safety(); +#endif return count.decrement(); } @@ -195,143 +222,6 @@ class SafeRefCount { } }; -#else - -template -class SafeNumeric { -protected: - T value; - -public: - _ALWAYS_INLINE_ void set(T p_value) { - value = p_value; - } - - _ALWAYS_INLINE_ T get() const { - return value; - } - - _ALWAYS_INLINE_ T increment() { - return ++value; - } - - _ALWAYS_INLINE_ T postincrement() { - return value++; - } - - _ALWAYS_INLINE_ T decrement() { - return --value; - } - - _ALWAYS_INLINE_ T postdecrement() { - return value--; - } - - _ALWAYS_INLINE_ T add(T p_value) { - return value += p_value; - } - - _ALWAYS_INLINE_ T postadd(T p_value) { - T old = value; - value += p_value; - return old; - } - - _ALWAYS_INLINE_ T sub(T p_value) { - return value -= p_value; - } - - _ALWAYS_INLINE_ T postsub(T p_value) { - T old = value; - value -= p_value; - return old; - } - - _ALWAYS_INLINE_ T exchange_if_greater(T p_value) { - if (value < p_value) { - value = p_value; - } - return value; - } - - _ALWAYS_INLINE_ T conditional_increment() { - if (value == 0) { - return 0; - } else { - return ++value; - } - } - - _ALWAYS_INLINE_ explicit SafeNumeric(T p_value = static_cast(0)) : - value(p_value) { - } -}; - -class SafeFlag { -protected: - bool flag; - -public: - _ALWAYS_INLINE_ bool is_set() const { - return flag; - } - - _ALWAYS_INLINE_ void set() { - flag = true; - } - - _ALWAYS_INLINE_ void clear() { - flag = false; - } - - _ALWAYS_INLINE_ void set_to(bool p_value) { - flag = p_value; - } - - _ALWAYS_INLINE_ explicit SafeFlag(bool p_value = false) : - flag(p_value) {} -}; - -class SafeRefCount { - uint32_t count = 0; - -public: - _ALWAYS_INLINE_ bool ref() { // true on success - if (count != 0) { - ++count; - return true; - } else { - return false; - } - } - - _ALWAYS_INLINE_ uint32_t refval() { // none-zero on success - if (count != 0) { - return ++count; - } else { - return 0; - } - } - - _ALWAYS_INLINE_ bool unref() { // true if must be disposed of - return --count == 0; - } - - _ALWAYS_INLINE_ uint32_t unrefval() { // 0 if must be disposed of - return --count; - } - - _ALWAYS_INLINE_ uint32_t get() const { - return count; - } - - _ALWAYS_INLINE_ void init(uint32_t p_value = 1) { - count = p_value; - } -}; - -#endif - } // namespace godot -#endif // GODOT_SAFE_REFCOUNT_HPP +#endif // !defined(NO_THREADS) diff --git a/include/godot_cpp/templates/search_array.hpp b/include/godot_cpp/templates/search_array.hpp index 1a7f9abe..8b802d6b 100644 --- a/include/godot_cpp/templates/search_array.hpp +++ b/include/godot_cpp/templates/search_array.hpp @@ -30,8 +30,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ -#ifndef GODOT_SEARCH_ARRAY_HPP -#define GODOT_SEARCH_ARRAY_HPP +#pragma once #include @@ -42,12 +41,12 @@ class SearchArray { public: Comparator compare; - inline int bisect(const T *p_array, int p_len, const T &p_value, bool p_before) const { - int lo = 0; - int hi = p_len; + inline int64_t bisect(const T *p_array, int64_t p_len, const T &p_value, bool p_before) const { + int64_t lo = 0; + int64_t hi = p_len; if (p_before) { while (lo < hi) { - const int mid = (lo + hi) / 2; + const int64_t mid = (lo + hi) / 2; if (compare(p_array[mid], p_value)) { lo = mid + 1; } else { @@ -56,7 +55,7 @@ class SearchArray { } } else { while (lo < hi) { - const int mid = (lo + hi) / 2; + const int64_t mid = (lo + hi) / 2; if (compare(p_value, p_array[mid])) { hi = mid; } else { @@ -69,5 +68,3 @@ class SearchArray { }; } // namespace godot - -#endif // GODOT_SEARCH_ARRAY_HPP diff --git a/include/godot_cpp/templates/self_list.hpp b/include/godot_cpp/templates/self_list.hpp index 2b651481..feb73556 100644 --- a/include/godot_cpp/templates/self_list.hpp +++ b/include/godot_cpp/templates/self_list.hpp @@ -30,8 +30,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ -#ifndef GODOT_SELF_LIST_HPP -#define GODOT_SELF_LIST_HPP +#pragma once #include #include @@ -103,11 +102,74 @@ class SelfList { p_elem->_root = nullptr; } + void clear() { + while (_first) { + remove(_first); + } + } + + void sort() { + sort_custom>(); + } + + template + void sort_custom() { + if (_first == _last) { + return; + } + + SelfList *from = _first; + SelfList *current = from; + SelfList *to = from; + + while (current) { + SelfList *next = current->_next; + + if (from != current) { + current->_prev = nullptr; + current->_next = from; + + SelfList *find = from; + C less; + while (find && less(*find->_self, *current->_self)) { + current->_prev = find; + current->_next = find->_next; + find = find->_next; + } + + if (current->_prev) { + current->_prev->_next = current; + } else { + from = current; + } + + if (current->_next) { + current->_next->_prev = current; + } else { + to = current; + } + } else { + current->_prev = nullptr; + current->_next = nullptr; + } + + current = next; + } + _first = from; + _last = to; + } + _FORCE_INLINE_ SelfList *first() { return _first; } _FORCE_INLINE_ const SelfList *first() const { return _first; } + // Forbid copying, which has broken behavior. + void operator=(const List &) = delete; + _FORCE_INLINE_ List() {} - _FORCE_INLINE_ ~List() { ERR_FAIL_COND(_first != nullptr); } + _FORCE_INLINE_ ~List() { + // A self list must be empty on destruction. + DEV_ASSERT(_first == nullptr); + } }; private: @@ -129,6 +191,9 @@ class SelfList { _FORCE_INLINE_ const SelfList *prev() const { return _prev; } _FORCE_INLINE_ T *self() const { return _self; } + // Forbid copying, which has broken behavior. + void operator=(const SelfList &) = delete; + _FORCE_INLINE_ SelfList(T *p_self) { _self = p_self; } @@ -141,5 +206,3 @@ class SelfList { }; } // namespace godot - -#endif // GODOT_SELF_LIST_HPP diff --git a/include/godot_cpp/templates/sort_array.hpp b/include/godot_cpp/templates/sort_array.hpp index 00b743c9..b9b0b1b1 100644 --- a/include/godot_cpp/templates/sort_array.hpp +++ b/include/godot_cpp/templates/sort_array.hpp @@ -30,8 +30,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ -#ifndef GODOT_SORT_ARRAY_HPP -#define GODOT_SORT_ARRAY_HPP +#pragma once #include @@ -81,8 +80,8 @@ class SortArray { } } - inline int bitlog(int n) const { - int k; + inline int64_t bitlog(int64_t n) const { + int64_t k; for (k = 0; n != 1; n >>= 1) { ++k; } @@ -91,8 +90,8 @@ class SortArray { /* Heap / Heapsort functions */ - inline void push_heap(int p_first, int p_hole_idx, int p_top_index, T p_value, T *p_array) const { - int parent = (p_hole_idx - 1) / 2; + inline void push_heap(int64_t p_first, int64_t p_hole_idx, int64_t p_top_index, T p_value, T *p_array) const { + int64_t parent = (p_hole_idx - 1) / 2; while (p_hole_idx > p_top_index && compare(p_array[p_first + parent], p_value)) { p_array[p_first + p_hole_idx] = p_array[p_first + parent]; p_hole_idx = parent; @@ -101,17 +100,17 @@ class SortArray { p_array[p_first + p_hole_idx] = p_value; } - inline void pop_heap(int p_first, int p_last, int p_result, T p_value, T *p_array) const { + inline void pop_heap(int64_t p_first, int64_t p_last, int64_t p_result, T p_value, T *p_array) const { p_array[p_result] = p_array[p_first]; adjust_heap(p_first, 0, p_last - p_first, p_value, p_array); } - inline void pop_heap(int p_first, int p_last, T *p_array) const { + inline void pop_heap(int64_t p_first, int64_t p_last, T *p_array) const { pop_heap(p_first, p_last - 1, p_last - 1, p_array[p_last - 1], p_array); } - inline void adjust_heap(int p_first, int p_hole_idx, int p_len, T p_value, T *p_array) const { - int top_index = p_hole_idx; - int second_child = 2 * p_hole_idx + 2; + inline void adjust_heap(int64_t p_first, int64_t p_hole_idx, int64_t p_len, T p_value, T *p_array) const { + int64_t top_index = p_hole_idx; + int64_t second_child = 2 * p_hole_idx + 2; while (second_child < p_len) { if (compare(p_array[p_first + second_child], p_array[p_first + (second_child - 1)])) { @@ -130,18 +129,18 @@ class SortArray { push_heap(p_first, p_hole_idx, top_index, p_value, p_array); } - inline void sort_heap(int p_first, int p_last, T *p_array) const { + inline void sort_heap(int64_t p_first, int64_t p_last, T *p_array) const { while (p_last - p_first > 1) { pop_heap(p_first, p_last--, p_array); } } - inline void make_heap(int p_first, int p_last, T *p_array) const { + inline void make_heap(int64_t p_first, int64_t p_last, T *p_array) const { if (p_last - p_first < 2) { return; } - int len = p_last - p_first; - int parent = (len - 2) / 2; + int64_t len = p_last - p_first; + int64_t parent = (len - 2) / 2; while (true) { adjust_heap(p_first, parent, len, p_array[p_first + parent], p_array); @@ -152,9 +151,9 @@ class SortArray { } } - inline void partial_sort(int p_first, int p_last, int p_middle, T *p_array) const { + inline void partial_sort(int64_t p_first, int64_t p_last, int64_t p_middle, T *p_array) const { make_heap(p_first, p_middle, p_array); - for (int i = p_middle; i < p_last; i++) { + for (int64_t i = p_middle; i < p_last; i++) { if (compare(p_array[i], p_array[p_first])) { pop_heap(p_first, p_middle, i, p_array[i], p_array); } @@ -162,29 +161,29 @@ class SortArray { sort_heap(p_first, p_middle, p_array); } - inline void partial_select(int p_first, int p_last, int p_middle, T *p_array) const { + inline void partial_select(int64_t p_first, int64_t p_last, int64_t p_middle, T *p_array) const { make_heap(p_first, p_middle, p_array); - for (int i = p_middle; i < p_last; i++) { + for (int64_t i = p_middle; i < p_last; i++) { if (compare(p_array[i], p_array[p_first])) { pop_heap(p_first, p_middle, i, p_array[i], p_array); } } } - inline int partitioner(int p_first, int p_last, T p_pivot, T *p_array) const { - const int unmodified_first = p_first; - const int unmodified_last = p_last; + inline int64_t partitioner(int64_t p_first, int64_t p_last, T p_pivot, T *p_array) const { + const int64_t unmodified_first = p_first; + const int64_t unmodified_last = p_last; while (true) { while (compare(p_array[p_first], p_pivot)) { - if (Validate) { + if constexpr (Validate) { ERR_BAD_COMPARE(p_first == unmodified_last - 1); } p_first++; } p_last--; while (compare(p_pivot, p_array[p_last])) { - if (Validate) { + if constexpr (Validate) { ERR_BAD_COMPARE(p_last == unmodified_first); } p_last--; @@ -199,7 +198,7 @@ class SortArray { } } - inline void introsort(int p_first, int p_last, T *p_array, int p_max_depth) const { + inline void introsort(int64_t p_first, int64_t p_last, T *p_array, int64_t p_max_depth) const { while (p_last - p_first > INTROSORT_THRESHOLD) { if (p_max_depth == 0) { partial_sort(p_first, p_last, p_last, p_array); @@ -208,7 +207,7 @@ class SortArray { p_max_depth--; - int cut = partitioner( + int64_t cut = partitioner( p_first, p_last, median_of_3( @@ -222,7 +221,7 @@ class SortArray { } } - inline void introselect(int p_first, int p_nth, int p_last, T *p_array, int p_max_depth) const { + inline void introselect(int64_t p_first, int64_t p_nth, int64_t p_last, T *p_array, int64_t p_max_depth) const { while (p_last - p_first > 3) { if (p_max_depth == 0) { partial_select(p_first, p_nth + 1, p_last, p_array); @@ -232,7 +231,7 @@ class SortArray { p_max_depth--; - int cut = partitioner( + int64_t cut = partitioner( p_first, p_last, median_of_3( @@ -251,10 +250,10 @@ class SortArray { insertion_sort(p_first, p_last, p_array); } - inline void unguarded_linear_insert(int p_last, T p_value, T *p_array) const { - int next = p_last - 1; + inline void unguarded_linear_insert(int64_t p_last, T p_value, T *p_array) const { + int64_t next = p_last - 1; while (compare(p_value, p_array[next])) { - if (Validate) { + if constexpr (Validate) { ERR_BAD_COMPARE(next == 0); } p_array[p_last] = p_array[next]; @@ -264,10 +263,10 @@ class SortArray { p_array[p_last] = p_value; } - inline void linear_insert(int p_first, int p_last, T *p_array) const { + inline void linear_insert(int64_t p_first, int64_t p_last, T *p_array) const { T val = p_array[p_last]; if (compare(val, p_array[p_first])) { - for (int i = p_last; i > p_first; i--) { + for (int64_t i = p_last; i > p_first; i--) { p_array[i] = p_array[i - 1]; } @@ -277,22 +276,22 @@ class SortArray { } } - inline void insertion_sort(int p_first, int p_last, T *p_array) const { + inline void insertion_sort(int64_t p_first, int64_t p_last, T *p_array) const { if (p_first == p_last) { return; } - for (int i = p_first + 1; i != p_last; i++) { + for (int64_t i = p_first + 1; i != p_last; i++) { linear_insert(p_first, i, p_array); } } - inline void unguarded_insertion_sort(int p_first, int p_last, T *p_array) const { - for (int i = p_first; i != p_last; i++) { + inline void unguarded_insertion_sort(int64_t p_first, int64_t p_last, T *p_array) const { + for (int64_t i = p_first; i != p_last; i++) { unguarded_linear_insert(i, p_array[i], p_array); } } - inline void final_insertion_sort(int p_first, int p_last, T *p_array) const { + inline void final_insertion_sort(int64_t p_first, int64_t p_last, T *p_array) const { if (p_last - p_first > INTROSORT_THRESHOLD) { insertion_sort(p_first, p_first + INTROSORT_THRESHOLD, p_array); unguarded_insertion_sort(p_first + INTROSORT_THRESHOLD, p_last, p_array); @@ -301,18 +300,18 @@ class SortArray { } } - inline void sort_range(int p_first, int p_last, T *p_array) const { + inline void sort_range(int64_t p_first, int64_t p_last, T *p_array) const { if (p_first != p_last) { introsort(p_first, p_last, p_array, bitlog(p_last - p_first) * 2); final_insertion_sort(p_first, p_last, p_array); } } - inline void sort(T *p_array, int p_len) const { + inline void sort(T *p_array, int64_t p_len) const { sort_range(0, p_len, p_array); } - inline void nth_element(int p_first, int p_last, int p_nth, T *p_array) const { + inline void nth_element(int64_t p_first, int64_t p_last, int64_t p_nth, T *p_array) const { if (p_first == p_last || p_nth == p_last) { return; } @@ -321,5 +320,3 @@ class SortArray { }; } // namespace godot - -#endif // GODOT_SORT_ARRAY_HPP diff --git a/include/godot_cpp/templates/spin_lock.hpp b/include/godot_cpp/templates/spin_lock.hpp index 6e761694..68e88320 100644 --- a/include/godot_cpp/templates/spin_lock.hpp +++ b/include/godot_cpp/templates/spin_lock.hpp @@ -30,8 +30,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ -#ifndef GODOT_SPIN_LOCK_HPP -#define GODOT_SPIN_LOCK_HPP +#pragma once #include @@ -52,5 +51,3 @@ class SpinLock { }; } // namespace godot - -#endif // GODOT_SPIN_LOCK_HPP diff --git a/include/godot_cpp/templates/thread_work_pool.hpp b/include/godot_cpp/templates/thread_work_pool.hpp index 6ad79c58..bcf8abe4 100644 --- a/include/godot_cpp/templates/thread_work_pool.hpp +++ b/include/godot_cpp/templates/thread_work_pool.hpp @@ -30,8 +30,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ -#ifndef GODOT_THREAD_WORK_POOL_HPP -#define GODOT_THREAD_WORK_POOL_HPP +#pragma once #include #include @@ -203,5 +202,3 @@ class ThreadWorkPool { }; } // namespace godot - -#endif // GODOT_THREAD_WORK_POOL_HPP diff --git a/include/godot_cpp/templates/vector.hpp b/include/godot_cpp/templates/vector.hpp index 4bd46603..92d4a351 100644 --- a/include/godot_cpp/templates/vector.hpp +++ b/include/godot_cpp/templates/vector.hpp @@ -30,8 +30,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ -#ifndef GODOT_VECTOR_HPP -#define GODOT_VECTOR_HPP +#pragma once /** * @class Vector @@ -71,6 +70,7 @@ class Vector { CowData _cowdata; public: + // Must take a copy instead of a reference (see GH-31736). bool push_back(T p_elem); _FORCE_INLINE_ bool append(const T &p_elem) { return push_back(p_elem); } //alias void fill(T p_elem); @@ -99,11 +99,13 @@ class Vector { Error resize(Size p_size) { return _cowdata.resize(p_size); } Error resize_zeroed(Size p_size) { return _cowdata.template resize(p_size); } _FORCE_INLINE_ const T &operator[](Size p_index) const { return _cowdata.get(p_index); } + // Must take a copy instead of a reference (see GH-31736). Error insert(Size p_pos, T p_val) { return _cowdata.insert(p_pos, p_val); } Size find(const T &p_val, Size p_from = 0) const { return _cowdata.find(p_val, p_from); } Size rfind(const T &p_val, Size p_from = -1) const { return _cowdata.rfind(p_val, p_from); } Size count(const T &p_val) const { return _cowdata.count(p_val); } + // Must take a copy instead of a reference (see GH-31736). void append_array(Vector p_other); _FORCE_INLINE_ bool has(const T &p_val) const { return find(p_val) != -1; } @@ -148,17 +150,19 @@ class Vector { insert(i, p_val); } - inline void operator=(const Vector &p_from) { - _cowdata._ref(p_from._cowdata); - } + void operator=(const Vector &p_from) { _cowdata._ref(p_from._cowdata); } + void operator=(Vector &&p_from) { _cowdata = std::move(p_from._cowdata); } Vector to_byte_array() const { Vector ret; if (is_empty()) { return ret; } - ret.resize(size() * sizeof(T)); - memcpy(ret.ptrw(), ptr(), sizeof(T) * size()); + size_t alloc_size = size() * sizeof(T); + ret.resize(alloc_size); + if (alloc_size) { + memcpy(ret.ptrw(), ptr(), alloc_size); + } return ret; } @@ -281,16 +285,11 @@ class Vector { } _FORCE_INLINE_ Vector() {} - _FORCE_INLINE_ Vector(std::initializer_list p_init) { - Error err = _cowdata.resize(p_init.size()); - ERR_FAIL_COND(err); - - Size i = 0; - for (const T &element : p_init) { - _cowdata.set(i++, element); - } - } + _FORCE_INLINE_ Vector(std::initializer_list p_init) : + _cowdata(p_init) {} _FORCE_INLINE_ Vector(const Vector &p_from) { _cowdata._ref(p_from._cowdata); } + _FORCE_INLINE_ Vector(Vector &&p_from) : + _cowdata(std::move(p_from._cowdata)) {} _FORCE_INLINE_ ~Vector() {} }; @@ -334,5 +333,3 @@ void Vector::fill(T p_elem) { } } // namespace godot - -#endif // GODOT_VECTOR_HPP diff --git a/include/godot_cpp/templates/vmap.hpp b/include/godot_cpp/templates/vmap.hpp index 60fa99d6..dd0ff279 100644 --- a/include/godot_cpp/templates/vmap.hpp +++ b/include/godot_cpp/templates/vmap.hpp @@ -30,8 +30,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ -#ifndef GODOT_VMAP_HPP -#define GODOT_VMAP_HPP +#pragma once #include @@ -75,16 +74,16 @@ class VMap { middle = (low + high) / 2; if (p_val < a[middle].key) { - high = middle - 1; // search low end of array + high = middle - 1; //search low end of array } else if (a[middle].key < p_val) { - low = middle + 1; // search high end of array + low = middle + 1; //search high end of array } else { r_exact = true; return middle; } } - // return the position where this would be inserted + //return the position where this would be inserted if (a[middle].key < p_val) { middle++; } @@ -105,9 +104,9 @@ class VMap { middle = (low + high) / 2; if (p_val < a[middle].key) { - high = middle - 1; // search low end of array + high = middle - 1; //search low end of array } else if (a[middle].key < p_val) { - low = middle + 1; // search high end of array + low = middle + 1; //search high end of array } else { return middle; } @@ -145,6 +144,9 @@ class VMap { } int find_nearest(const T &p_val) const { + if (_cowdata.is_empty()) { + return -1; + } bool exact; return _find(p_val, exact); } @@ -194,6 +196,8 @@ class VMap { } _FORCE_INLINE_ VMap() {} + _FORCE_INLINE_ VMap(std::initializer_list p_init) : + _cowdata(p_init) {} _FORCE_INLINE_ VMap(const VMap &p_from) { _cowdata._ref(p_from._cowdata); } inline void operator=(const VMap &p_from) { @@ -202,5 +206,3 @@ class VMap { }; } // namespace godot - -#endif // GODOT_VMAP_HPP diff --git a/include/godot_cpp/templates/vset.hpp b/include/godot_cpp/templates/vset.hpp index 7b46d8d2..e89a5f10 100644 --- a/include/godot_cpp/templates/vset.hpp +++ b/include/godot_cpp/templates/vset.hpp @@ -30,8 +30,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ -#ifndef GODOT_VSET_HPP -#define GODOT_VSET_HPP +#pragma once #include @@ -62,16 +61,16 @@ class VSet { middle = (low + high) / 2; if (p_val < a[middle]) { - high = middle - 1; // search low end of array + high = middle - 1; //search low end of array } else if (a[middle] < p_val) { - low = middle + 1; // search high end of array + low = middle + 1; //search high end of array } else { r_exact = true; return middle; } } - // return the position where this would be inserted + //return the position where this would be inserted if (a[middle] < p_val) { middle++; } @@ -92,9 +91,9 @@ class VSet { middle = (low + high) / 2; if (p_val < a[middle]) { - high = middle - 1; // search low end of array + high = middle - 1; //search low end of array } else if (a[middle] < p_val) { - low = middle + 1; // search high end of array + low = middle + 1; //search high end of array } else { return middle; } @@ -140,8 +139,10 @@ class VSet { inline const T &operator[](int p_index) const { return _data[p_index]; } + + _FORCE_INLINE_ VSet() {} + _FORCE_INLINE_ VSet(std::initializer_list p_init) : + _data(p_init) {} }; } // namespace godot - -#endif // GODOT_VSET_HPP diff --git a/include/godot_cpp/variant/aabb.hpp b/include/godot_cpp/variant/aabb.hpp index f9a73593..26876028 100644 --- a/include/godot_cpp/variant/aabb.hpp +++ b/include/godot_cpp/variant/aabb.hpp @@ -30,8 +30,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ -#ifndef GODOT_AABB_HPP -#define GODOT_AABB_HPP +#pragma once #include #include @@ -75,16 +74,21 @@ struct [[nodiscard]] AABB { AABB merge(const AABB &p_with) const; void merge_with(const AABB &p_aabb); ///merge with another AABB AABB intersection(const AABB &p_aabb) const; ///get box where two intersect, empty if no intersection occurs - bool intersects_segment(const Vector3 &p_from, const Vector3 &p_to, Vector3 *r_clip = nullptr, Vector3 *r_normal = nullptr) const; - bool intersects_ray(const Vector3 &p_from, const Vector3 &p_dir, Vector3 *r_clip = nullptr, Vector3 *r_normal = nullptr) const; - _FORCE_INLINE_ bool smits_intersect_ray(const Vector3 &p_from, const Vector3 &p_dir, real_t t0, real_t t1) const; + _FORCE_INLINE_ bool smits_intersect_ray(const Vector3 &p_from, const Vector3 &p_dir, real_t p_t0, real_t p_t1) const; + + bool intersects_segment(const Vector3 &p_from, const Vector3 &p_to, Vector3 *r_intersection_point = nullptr, Vector3 *r_normal = nullptr) const; + bool intersects_ray(const Vector3 &p_from, const Vector3 &p_dir) const { + bool inside; + return find_intersects_ray(p_from, p_dir, inside); + } + bool find_intersects_ray(const Vector3 &p_from, const Vector3 &p_dir, bool &r_inside, Vector3 *r_intersection_point = nullptr, Vector3 *r_normal = nullptr) const; _FORCE_INLINE_ bool intersects_convex_shape(const Plane *p_planes, int p_plane_count, const Vector3 *p_points, int p_point_count) const; _FORCE_INLINE_ bool inside_convex_shape(const Plane *p_planes, int p_plane_count) const; bool intersects_plane(const Plane &p_plane) const; _FORCE_INLINE_ bool has_point(const Vector3 &p_point) const; - _FORCE_INLINE_ Vector3 get_support(const Vector3 &p_normal) const; + _FORCE_INLINE_ Vector3 get_support(const Vector3 &p_direction) const; Vector3 get_longest_axis() const; int get_longest_axis_index() const; @@ -211,15 +215,18 @@ inline bool AABB::encloses(const AABB &p_aabb) const { (src_max.z >= dst_max.z)); } -Vector3 AABB::get_support(const Vector3 &p_normal) const { - Vector3 half_extents = size * 0.5f; - Vector3 ofs = position + half_extents; - - return Vector3( - (p_normal.x > 0) ? half_extents.x : -half_extents.x, - (p_normal.y > 0) ? half_extents.y : -half_extents.y, - (p_normal.z > 0) ? half_extents.z : -half_extents.z) + - ofs; +Vector3 AABB::get_support(const Vector3 &p_direction) const { + Vector3 support = position; + if (p_direction.x > 0.0f) { + support.x += size.x; + } + if (p_direction.y > 0.0f) { + support.y += size.y; + } + if (p_direction.z > 0.0f) { + support.z += size.z; + } + return support; } Vector3 AABB::get_endpoint(int p_point) const { @@ -405,7 +412,7 @@ inline real_t AABB::get_shortest_axis_size() const { return max_size; } -bool AABB::smits_intersect_ray(const Vector3 &p_from, const Vector3 &p_dir, real_t t0, real_t t1) const { +bool AABB::smits_intersect_ray(const Vector3 &p_from, const Vector3 &p_dir, real_t p_t0, real_t p_t1) const { #ifdef MATH_CHECKS if (unlikely(size.x < 0 || size.y < 0 || size.z < 0)) { ERR_PRINT("AABB size is negative, this is not supported. Use AABB.abs() to get an AABB with a positive size."); @@ -456,7 +463,7 @@ bool AABB::smits_intersect_ray(const Vector3 &p_from, const Vector3 &p_dir, real if (tzmax < tmax) { tmax = tzmax; } - return ((tmin < t1) && (tmax > t0)); + return ((tmin < p_t1) && (tmax > p_t0)); } void AABB::grow_by(real_t p_amount) { @@ -493,5 +500,3 @@ AABB AABB::quantized(real_t p_unit) const { } } // namespace godot - -#endif // GODOT_AABB_HPP diff --git a/include/godot_cpp/variant/array_helpers.hpp b/include/godot_cpp/variant/array_helpers.hpp index 8d8455d8..d2b471e8 100644 --- a/include/godot_cpp/variant/array_helpers.hpp +++ b/include/godot_cpp/variant/array_helpers.hpp @@ -30,8 +30,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ -#ifndef GODOT_ARRAY_HELPERS_HPP -#define GODOT_ARRAY_HELPERS_HPP +#pragma once namespace godot { namespace helpers { @@ -53,5 +52,3 @@ T append_all(T appendable) { } } // namespace helpers } // namespace godot - -#endif // GODOT_ARRAY_HELPERS_HPP diff --git a/include/godot_cpp/variant/basis.hpp b/include/godot_cpp/variant/basis.hpp index 32c94956..f982b9f0 100644 --- a/include/godot_cpp/variant/basis.hpp +++ b/include/godot_cpp/variant/basis.hpp @@ -30,8 +30,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ -#ifndef GODOT_BASIS_HPP -#define GODOT_BASIS_HPP +#pragma once #include #include @@ -46,11 +45,11 @@ struct [[nodiscard]] Basis { Vector3(0, 0, 1) }; - _FORCE_INLINE_ const Vector3 &operator[](int axis) const { - return rows[axis]; + _FORCE_INLINE_ const Vector3 &operator[](int p_row) const { + return rows[p_row]; } - _FORCE_INLINE_ Vector3 &operator[](int axis) { - return rows[axis]; + _FORCE_INLINE_ Vector3 &operator[](int p_row) { + return rows[p_row]; } void invert(); @@ -61,21 +60,19 @@ struct [[nodiscard]] Basis { _FORCE_INLINE_ real_t determinant() const; - void from_z(const Vector3 &p_z); - void rotate(const Vector3 &p_axis, real_t p_angle); Basis rotated(const Vector3 &p_axis, real_t p_angle) const; void rotate_local(const Vector3 &p_axis, real_t p_angle); Basis rotated_local(const Vector3 &p_axis, real_t p_angle) const; - void rotate(const Vector3 &p_euler, EulerOrder p_order = EULER_ORDER_YXZ); - Basis rotated(const Vector3 &p_euler, EulerOrder p_order = EULER_ORDER_YXZ) const; + void rotate(const Vector3 &p_euler, EulerOrder p_order = EulerOrder::EULER_ORDER_YXZ); + Basis rotated(const Vector3 &p_euler, EulerOrder p_order = EulerOrder::EULER_ORDER_YXZ) const; void rotate(const Quaternion &p_quaternion); Basis rotated(const Quaternion &p_quaternion) const; - Vector3 get_euler_normalized(EulerOrder p_order = EULER_ORDER_YXZ) const; + Vector3 get_euler_normalized(EulerOrder p_order = EulerOrder::EULER_ORDER_YXZ) const; void get_rotation_axis_angle(Vector3 &p_axis, real_t &p_angle) const; void get_rotation_axis_angle_local(Vector3 &p_axis, real_t &p_angle) const; Quaternion get_rotation_quaternion() const; @@ -84,9 +81,9 @@ struct [[nodiscard]] Basis { Vector3 rotref_posscale_decomposition(Basis &rotref) const; - Vector3 get_euler(EulerOrder p_order = EULER_ORDER_YXZ) const; - void set_euler(const Vector3 &p_euler, EulerOrder p_order = EULER_ORDER_YXZ); - static Basis from_euler(const Vector3 &p_euler, EulerOrder p_order = EULER_ORDER_YXZ) { + Vector3 get_euler(EulerOrder p_order = EulerOrder::EULER_ORDER_YXZ) const; + void set_euler(const Vector3 &p_euler, EulerOrder p_order = EulerOrder::EULER_ORDER_YXZ); + static Basis from_euler(const Vector3 &p_euler, EulerOrder p_order = EulerOrder::EULER_ORDER_YXZ) { Basis b; b.set_euler(p_euler, p_order); return b; @@ -106,27 +103,25 @@ struct [[nodiscard]] Basis { void scale_orthogonal(const Vector3 &p_scale); Basis scaled_orthogonal(const Vector3 &p_scale) const; - - void make_scale_uniform(); - float get_uniform_scale() const; + real_t get_uniform_scale() const; Vector3 get_scale() const; Vector3 get_scale_abs() const; - Vector3 get_scale_local() const; + Vector3 get_scale_global() const; void set_axis_angle_scale(const Vector3 &p_axis, real_t p_angle, const Vector3 &p_scale); - void set_euler_scale(const Vector3 &p_euler, const Vector3 &p_scale, EulerOrder p_order = EULER_ORDER_YXZ); + void set_euler_scale(const Vector3 &p_euler, const Vector3 &p_scale, EulerOrder p_order = EulerOrder::EULER_ORDER_YXZ); void set_quaternion_scale(const Quaternion &p_quaternion, const Vector3 &p_scale); // transposed dot products - _FORCE_INLINE_ real_t tdotx(const Vector3 &v) const { - return rows[0][0] * v[0] + rows[1][0] * v[1] + rows[2][0] * v[2]; + _FORCE_INLINE_ real_t tdotx(const Vector3 &p_v) const { + return rows[0][0] * p_v[0] + rows[1][0] * p_v[1] + rows[2][0] * p_v[2]; } - _FORCE_INLINE_ real_t tdoty(const Vector3 &v) const { - return rows[0][1] * v[0] + rows[1][1] * v[1] + rows[2][1] * v[2]; + _FORCE_INLINE_ real_t tdoty(const Vector3 &p_v) const { + return rows[0][1] * p_v[0] + rows[1][1] * p_v[1] + rows[2][1] * p_v[2]; } - _FORCE_INLINE_ real_t tdotz(const Vector3 &v) const { - return rows[0][2] * v[0] + rows[1][2] * v[1] + rows[2][2] * v[2]; + _FORCE_INLINE_ real_t tdotz(const Vector3 &p_v) const { + return rows[0][2] * p_v[0] + rows[1][2] * p_v[1] + rows[2][2] * p_v[2]; } bool is_equal_approx(const Basis &p_basis) const; @@ -143,31 +138,35 @@ struct [[nodiscard]] Basis { _FORCE_INLINE_ Basis operator+(const Basis &p_matrix) const; _FORCE_INLINE_ void operator-=(const Basis &p_matrix); _FORCE_INLINE_ Basis operator-(const Basis &p_matrix) const; - _FORCE_INLINE_ void operator*=(const real_t p_val); - _FORCE_INLINE_ Basis operator*(const real_t p_val) const; + _FORCE_INLINE_ void operator*=(real_t p_val); + _FORCE_INLINE_ Basis operator*(real_t p_val) const; + _FORCE_INLINE_ void operator/=(real_t p_val); + _FORCE_INLINE_ Basis operator/(real_t p_val) const; bool is_orthogonal() const; + bool is_orthonormal() const; + bool is_conformal() const; bool is_diagonal() const; bool is_rotation() const; - Basis lerp(const Basis &p_to, const real_t &p_weight) const; - Basis slerp(const Basis &p_to, const real_t &p_weight) const; + Basis lerp(const Basis &p_to, real_t p_weight) const; + Basis slerp(const Basis &p_to, real_t p_weight) const; void rotate_sh(real_t *p_values); operator String() const; /* create / set */ - _FORCE_INLINE_ void set(real_t xx, real_t xy, real_t xz, real_t yx, real_t yy, real_t yz, real_t zx, real_t zy, real_t zz) { - rows[0][0] = xx; - rows[0][1] = xy; - rows[0][2] = xz; - rows[1][0] = yx; - rows[1][1] = yy; - rows[1][2] = yz; - rows[2][0] = zx; - rows[2][1] = zy; - rows[2][2] = zz; + _FORCE_INLINE_ void set(real_t p_xx, real_t p_xy, real_t p_xz, real_t p_yx, real_t p_yy, real_t p_yz, real_t p_zx, real_t p_zy, real_t p_zz) { + rows[0][0] = p_xx; + rows[0][1] = p_xy; + rows[0][2] = p_xz; + rows[1][0] = p_yx; + rows[1][1] = p_yy; + rows[1][2] = p_yz; + rows[2][0] = p_zx; + rows[2][1] = p_zy; + rows[2][2] = p_zz; } _FORCE_INLINE_ void set_columns(const Vector3 &p_x, const Vector3 &p_y, const Vector3 &p_z) { set_column(0, p_x); @@ -197,20 +196,20 @@ struct [[nodiscard]] Basis { rows[2].zero(); } - _FORCE_INLINE_ Basis transpose_xform(const Basis &m) const { + _FORCE_INLINE_ Basis transpose_xform(const Basis &p_m) const { return Basis( - rows[0].x * m[0].x + rows[1].x * m[1].x + rows[2].x * m[2].x, - rows[0].x * m[0].y + rows[1].x * m[1].y + rows[2].x * m[2].y, - rows[0].x * m[0].z + rows[1].x * m[1].z + rows[2].x * m[2].z, - rows[0].y * m[0].x + rows[1].y * m[1].x + rows[2].y * m[2].x, - rows[0].y * m[0].y + rows[1].y * m[1].y + rows[2].y * m[2].y, - rows[0].y * m[0].z + rows[1].y * m[1].z + rows[2].y * m[2].z, - rows[0].z * m[0].x + rows[1].z * m[1].x + rows[2].z * m[2].x, - rows[0].z * m[0].y + rows[1].z * m[1].y + rows[2].z * m[2].y, - rows[0].z * m[0].z + rows[1].z * m[1].z + rows[2].z * m[2].z); + rows[0].x * p_m[0].x + rows[1].x * p_m[1].x + rows[2].x * p_m[2].x, + rows[0].x * p_m[0].y + rows[1].x * p_m[1].y + rows[2].x * p_m[2].y, + rows[0].x * p_m[0].z + rows[1].x * p_m[1].z + rows[2].x * p_m[2].z, + rows[0].y * p_m[0].x + rows[1].y * p_m[1].x + rows[2].y * p_m[2].x, + rows[0].y * p_m[0].y + rows[1].y * p_m[1].y + rows[2].y * p_m[2].y, + rows[0].y * p_m[0].z + rows[1].y * p_m[1].z + rows[2].y * p_m[2].z, + rows[0].z * p_m[0].x + rows[1].z * p_m[1].x + rows[2].z * p_m[2].x, + rows[0].z * p_m[0].y + rows[1].z * p_m[1].y + rows[2].z * p_m[2].y, + rows[0].z * p_m[0].z + rows[1].z * p_m[1].z + rows[2].z * p_m[2].z); } - Basis(real_t xx, real_t xy, real_t xz, real_t yx, real_t yy, real_t yz, real_t zx, real_t zy, real_t zz) { - set(xx, xy, xz, yx, yy, yz, zx, zy, zz); + Basis(real_t p_xx, real_t p_xy, real_t p_xz, real_t p_yx, real_t p_yy, real_t p_yz, real_t p_zx, real_t p_zy, real_t p_zz) { + set(p_xx, p_xy, p_xz, p_yx, p_yy, p_yz, p_zx, p_zy, p_zz); } void orthonormalize(); @@ -284,18 +283,30 @@ _FORCE_INLINE_ Basis Basis::operator-(const Basis &p_matrix) const { return ret; } -_FORCE_INLINE_ void Basis::operator*=(const real_t p_val) { +_FORCE_INLINE_ void Basis::operator*=(real_t p_val) { rows[0] *= p_val; rows[1] *= p_val; rows[2] *= p_val; } -_FORCE_INLINE_ Basis Basis::operator*(const real_t p_val) const { +_FORCE_INLINE_ Basis Basis::operator*(real_t p_val) const { Basis ret(*this); ret *= p_val; return ret; } +_FORCE_INLINE_ void Basis::operator/=(real_t p_val) { + rows[0] /= p_val; + rows[1] /= p_val; + rows[2] /= p_val; +} + +_FORCE_INLINE_ Basis Basis::operator/(real_t p_val) const { + Basis ret(*this); + ret /= p_val; + return ret; +} + Vector3 Basis::xform(const Vector3 &p_vector) const { return Vector3( rows[0].dot(p_vector), @@ -317,5 +328,3 @@ real_t Basis::determinant() const { } } // namespace godot - -#endif // GODOT_BASIS_HPP diff --git a/include/godot_cpp/variant/callable_custom.hpp b/include/godot_cpp/variant/callable_custom.hpp index dfbfcc2c..e9dbe338 100644 --- a/include/godot_cpp/variant/callable_custom.hpp +++ b/include/godot_cpp/variant/callable_custom.hpp @@ -30,8 +30,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ -#ifndef GODOT_CALLABLE_CUSTOM_HPP -#define GODOT_CALLABLE_CUSTOM_HPP +#pragma once #include #include @@ -63,5 +62,3 @@ class CallableCustom : public CallableCustomBase { }; } // namespace godot - -#endif // GODOT_CALLABLE_CUSTOM_HPP diff --git a/include/godot_cpp/variant/callable_method_pointer.hpp b/include/godot_cpp/variant/callable_method_pointer.hpp index c34fbc1f..4cf75ee9 100644 --- a/include/godot_cpp/variant/callable_method_pointer.hpp +++ b/include/godot_cpp/variant/callable_method_pointer.hpp @@ -30,8 +30,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ -#ifndef GODOT_CALLABLE_METHOD_POINTER_HPP -#define GODOT_CALLABLE_METHOD_POINTER_HPP +#pragma once #include #include @@ -271,5 +270,3 @@ Callable create_custom_callable_static_function_pointer(R (*p_method)(P...)) { #define callable_mp_static(M) ::godot::create_custom_callable_static_function_pointer(M) } // namespace godot - -#endif // GODOT_CALLABLE_METHOD_POINTER_HPP diff --git a/include/godot_cpp/variant/char_range.inc.hpp b/include/godot_cpp/variant/char_range.inc.hpp new file mode 100644 index 00000000..c012156d --- /dev/null +++ b/include/godot_cpp/variant/char_range.inc.hpp @@ -0,0 +1,3633 @@ +/**************************************************************************/ +/* char_range.inc.hpp */ +/**************************************************************************/ +/* This file is part of: */ +/* REDOT ENGINE */ +/* https://redotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2024-present Redot Engine contributors */ +/* (see REDOT_AUTHORS.md) */ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/**************************************************************************/ + +#pragma once + +// Unicode Derived Core Properties +// Source: https://www.unicode.org/Public/16.0.0/ucd/DerivedCoreProperties.txt + +namespace godot { + +struct CharRange { + char32_t start; + char32_t end; +}; + +constexpr inline CharRange xid_start[] = { + { 0x41, 0x5a }, + { 0x5f, 0x5f }, // Underscore technically isn't in XID_Start, but for our purposes it's included. + { 0x61, 0x7a }, + { 0xaa, 0xaa }, + { 0xb5, 0xb5 }, + { 0xba, 0xba }, + { 0xc0, 0xd6 }, + { 0xd8, 0xf6 }, + { 0xf8, 0x2c1 }, + { 0x2c6, 0x2d1 }, + { 0x2e0, 0x2e4 }, + { 0x2ec, 0x2ec }, + { 0x2ee, 0x2ee }, + { 0x370, 0x374 }, + { 0x376, 0x377 }, + { 0x37b, 0x37d }, + { 0x37f, 0x37f }, + { 0x386, 0x386 }, + { 0x388, 0x38a }, + { 0x38c, 0x38c }, + { 0x38e, 0x3a1 }, + { 0x3a3, 0x3f5 }, + { 0x3f7, 0x481 }, + { 0x48a, 0x52f }, + { 0x531, 0x556 }, + { 0x559, 0x559 }, + { 0x560, 0x588 }, + { 0x5d0, 0x5ea }, + { 0x5ef, 0x5f2 }, + { 0x620, 0x64a }, + { 0x66e, 0x66f }, + { 0x671, 0x6d3 }, + { 0x6d5, 0x6d5 }, + { 0x6e5, 0x6e6 }, + { 0x6ee, 0x6ef }, + { 0x6fa, 0x6fc }, + { 0x6ff, 0x6ff }, + { 0x710, 0x710 }, + { 0x712, 0x72f }, + { 0x74d, 0x7a5 }, + { 0x7b1, 0x7b1 }, + { 0x7ca, 0x7ea }, + { 0x7f4, 0x7f5 }, + { 0x7fa, 0x7fa }, + { 0x800, 0x815 }, + { 0x81a, 0x81a }, + { 0x824, 0x824 }, + { 0x828, 0x828 }, + { 0x840, 0x858 }, + { 0x860, 0x86a }, + { 0x870, 0x887 }, + { 0x889, 0x88e }, + { 0x8a0, 0x8c9 }, + { 0x904, 0x939 }, + { 0x93d, 0x93d }, + { 0x950, 0x950 }, + { 0x958, 0x961 }, + { 0x971, 0x980 }, + { 0x985, 0x98c }, + { 0x98f, 0x990 }, + { 0x993, 0x9a8 }, + { 0x9aa, 0x9b0 }, + { 0x9b2, 0x9b2 }, + { 0x9b6, 0x9b9 }, + { 0x9bd, 0x9bd }, + { 0x9ce, 0x9ce }, + { 0x9dc, 0x9dd }, + { 0x9df, 0x9e1 }, + { 0x9f0, 0x9f1 }, + { 0x9fc, 0x9fc }, + { 0xa05, 0xa0a }, + { 0xa0f, 0xa10 }, + { 0xa13, 0xa28 }, + { 0xa2a, 0xa30 }, + { 0xa32, 0xa33 }, + { 0xa35, 0xa36 }, + { 0xa38, 0xa39 }, + { 0xa59, 0xa5c }, + { 0xa5e, 0xa5e }, + { 0xa72, 0xa74 }, + { 0xa85, 0xa8d }, + { 0xa8f, 0xa91 }, + { 0xa93, 0xaa8 }, + { 0xaaa, 0xab0 }, + { 0xab2, 0xab3 }, + { 0xab5, 0xab9 }, + { 0xabd, 0xabd }, + { 0xad0, 0xad0 }, + { 0xae0, 0xae1 }, + { 0xaf9, 0xaf9 }, + { 0xb05, 0xb0c }, + { 0xb0f, 0xb10 }, + { 0xb13, 0xb28 }, + { 0xb2a, 0xb30 }, + { 0xb32, 0xb33 }, + { 0xb35, 0xb39 }, + { 0xb3d, 0xb3d }, + { 0xb5c, 0xb5d }, + { 0xb5f, 0xb61 }, + { 0xb71, 0xb71 }, + { 0xb83, 0xb83 }, + { 0xb85, 0xb8a }, + { 0xb8e, 0xb90 }, + { 0xb92, 0xb95 }, + { 0xb99, 0xb9a }, + { 0xb9c, 0xb9c }, + { 0xb9e, 0xb9f }, + { 0xba3, 0xba4 }, + { 0xba8, 0xbaa }, + { 0xbae, 0xbb9 }, + { 0xbd0, 0xbd0 }, + { 0xc05, 0xc0c }, + { 0xc0e, 0xc10 }, + { 0xc12, 0xc28 }, + { 0xc2a, 0xc39 }, + { 0xc3d, 0xc3d }, + { 0xc58, 0xc5a }, + { 0xc5d, 0xc5d }, + { 0xc60, 0xc61 }, + { 0xc80, 0xc80 }, + { 0xc85, 0xc8c }, + { 0xc8e, 0xc90 }, + { 0xc92, 0xca8 }, + { 0xcaa, 0xcb3 }, + { 0xcb5, 0xcb9 }, + { 0xcbd, 0xcbd }, + { 0xcdd, 0xcde }, + { 0xce0, 0xce1 }, + { 0xcf1, 0xcf2 }, + { 0xd04, 0xd0c }, + { 0xd0e, 0xd10 }, + { 0xd12, 0xd3a }, + { 0xd3d, 0xd3d }, + { 0xd4e, 0xd4e }, + { 0xd54, 0xd56 }, + { 0xd5f, 0xd61 }, + { 0xd7a, 0xd7f }, + { 0xd85, 0xd96 }, + { 0xd9a, 0xdb1 }, + { 0xdb3, 0xdbb }, + { 0xdbd, 0xdbd }, + { 0xdc0, 0xdc6 }, + { 0xe01, 0xe30 }, + { 0xe32, 0xe32 }, + { 0xe40, 0xe46 }, + { 0xe81, 0xe82 }, + { 0xe84, 0xe84 }, + { 0xe86, 0xe8a }, + { 0xe8c, 0xea3 }, + { 0xea5, 0xea5 }, + { 0xea7, 0xeb0 }, + { 0xeb2, 0xeb2 }, + { 0xebd, 0xebd }, + { 0xec0, 0xec4 }, + { 0xec6, 0xec6 }, + { 0xedc, 0xedf }, + { 0xf00, 0xf00 }, + { 0xf40, 0xf47 }, + { 0xf49, 0xf6c }, + { 0xf88, 0xf8c }, + { 0x1000, 0x102a }, + { 0x103f, 0x103f }, + { 0x1050, 0x1055 }, + { 0x105a, 0x105d }, + { 0x1061, 0x1061 }, + { 0x1065, 0x1066 }, + { 0x106e, 0x1070 }, + { 0x1075, 0x1081 }, + { 0x108e, 0x108e }, + { 0x10a0, 0x10c5 }, + { 0x10c7, 0x10c7 }, + { 0x10cd, 0x10cd }, + { 0x10d0, 0x10fa }, + { 0x10fc, 0x1248 }, + { 0x124a, 0x124d }, + { 0x1250, 0x1256 }, + { 0x1258, 0x1258 }, + { 0x125a, 0x125d }, + { 0x1260, 0x1288 }, + { 0x128a, 0x128d }, + { 0x1290, 0x12b0 }, + { 0x12b2, 0x12b5 }, + { 0x12b8, 0x12be }, + { 0x12c0, 0x12c0 }, + { 0x12c2, 0x12c5 }, + { 0x12c8, 0x12d6 }, + { 0x12d8, 0x1310 }, + { 0x1312, 0x1315 }, + { 0x1318, 0x135a }, + { 0x1380, 0x138f }, + { 0x13a0, 0x13f5 }, + { 0x13f8, 0x13fd }, + { 0x1401, 0x166c }, + { 0x166f, 0x167f }, + { 0x1681, 0x169a }, + { 0x16a0, 0x16ea }, + { 0x16ee, 0x16f8 }, + { 0x1700, 0x1711 }, + { 0x171f, 0x1731 }, + { 0x1740, 0x1751 }, + { 0x1760, 0x176c }, + { 0x176e, 0x1770 }, + { 0x1780, 0x17b3 }, + { 0x17d7, 0x17d7 }, + { 0x17dc, 0x17dc }, + { 0x1820, 0x1878 }, + { 0x1880, 0x18a8 }, + { 0x18aa, 0x18aa }, + { 0x18b0, 0x18f5 }, + { 0x1900, 0x191e }, + { 0x1950, 0x196d }, + { 0x1970, 0x1974 }, + { 0x1980, 0x19ab }, + { 0x19b0, 0x19c9 }, + { 0x1a00, 0x1a16 }, + { 0x1a20, 0x1a54 }, + { 0x1aa7, 0x1aa7 }, + { 0x1b05, 0x1b33 }, + { 0x1b45, 0x1b4c }, + { 0x1b83, 0x1ba0 }, + { 0x1bae, 0x1baf }, + { 0x1bba, 0x1be5 }, + { 0x1c00, 0x1c23 }, + { 0x1c4d, 0x1c4f }, + { 0x1c5a, 0x1c7d }, + { 0x1c80, 0x1c8a }, + { 0x1c90, 0x1cba }, + { 0x1cbd, 0x1cbf }, + { 0x1ce9, 0x1cec }, + { 0x1cee, 0x1cf3 }, + { 0x1cf5, 0x1cf6 }, + { 0x1cfa, 0x1cfa }, + { 0x1d00, 0x1dbf }, + { 0x1e00, 0x1f15 }, + { 0x1f18, 0x1f1d }, + { 0x1f20, 0x1f45 }, + { 0x1f48, 0x1f4d }, + { 0x1f50, 0x1f57 }, + { 0x1f59, 0x1f59 }, + { 0x1f5b, 0x1f5b }, + { 0x1f5d, 0x1f5d }, + { 0x1f5f, 0x1f7d }, + { 0x1f80, 0x1fb4 }, + { 0x1fb6, 0x1fbc }, + { 0x1fbe, 0x1fbe }, + { 0x1fc2, 0x1fc4 }, + { 0x1fc6, 0x1fcc }, + { 0x1fd0, 0x1fd3 }, + { 0x1fd6, 0x1fdb }, + { 0x1fe0, 0x1fec }, + { 0x1ff2, 0x1ff4 }, + { 0x1ff6, 0x1ffc }, + { 0x2071, 0x2071 }, + { 0x207f, 0x207f }, + { 0x2090, 0x209c }, + { 0x2102, 0x2102 }, + { 0x2107, 0x2107 }, + { 0x210a, 0x2113 }, + { 0x2115, 0x2115 }, + { 0x2118, 0x211d }, + { 0x2124, 0x2124 }, + { 0x2126, 0x2126 }, + { 0x2128, 0x2128 }, + { 0x212a, 0x2139 }, + { 0x213c, 0x213f }, + { 0x2145, 0x2149 }, + { 0x214e, 0x214e }, + { 0x2160, 0x2188 }, + { 0x2c00, 0x2ce4 }, + { 0x2ceb, 0x2cee }, + { 0x2cf2, 0x2cf3 }, + { 0x2d00, 0x2d25 }, + { 0x2d27, 0x2d27 }, + { 0x2d2d, 0x2d2d }, + { 0x2d30, 0x2d67 }, + { 0x2d6f, 0x2d6f }, + { 0x2d80, 0x2d96 }, + { 0x2da0, 0x2da6 }, + { 0x2da8, 0x2dae }, + { 0x2db0, 0x2db6 }, + { 0x2db8, 0x2dbe }, + { 0x2dc0, 0x2dc6 }, + { 0x2dc8, 0x2dce }, + { 0x2dd0, 0x2dd6 }, + { 0x2dd8, 0x2dde }, + { 0x3005, 0x3007 }, + { 0x3021, 0x3029 }, + { 0x3031, 0x3035 }, + { 0x3038, 0x303c }, + { 0x3041, 0x3096 }, + { 0x309d, 0x309f }, + { 0x30a1, 0x30fa }, + { 0x30fc, 0x30ff }, + { 0x3105, 0x312f }, + { 0x3131, 0x318e }, + { 0x31a0, 0x31bf }, + { 0x31f0, 0x31ff }, + { 0x3400, 0x4dbf }, + { 0x4e00, 0xa48c }, + { 0xa4d0, 0xa4fd }, + { 0xa500, 0xa60c }, + { 0xa610, 0xa61f }, + { 0xa62a, 0xa62b }, + { 0xa640, 0xa66e }, + { 0xa67f, 0xa69d }, + { 0xa6a0, 0xa6ef }, + { 0xa717, 0xa71f }, + { 0xa722, 0xa788 }, + { 0xa78b, 0xa7cd }, + { 0xa7d0, 0xa7d1 }, + { 0xa7d3, 0xa7d3 }, + { 0xa7d5, 0xa7dc }, + { 0xa7f2, 0xa801 }, + { 0xa803, 0xa805 }, + { 0xa807, 0xa80a }, + { 0xa80c, 0xa822 }, + { 0xa840, 0xa873 }, + { 0xa882, 0xa8b3 }, + { 0xa8f2, 0xa8f7 }, + { 0xa8fb, 0xa8fb }, + { 0xa8fd, 0xa8fe }, + { 0xa90a, 0xa925 }, + { 0xa930, 0xa946 }, + { 0xa960, 0xa97c }, + { 0xa984, 0xa9b2 }, + { 0xa9cf, 0xa9cf }, + { 0xa9e0, 0xa9e4 }, + { 0xa9e6, 0xa9ef }, + { 0xa9fa, 0xa9fe }, + { 0xaa00, 0xaa28 }, + { 0xaa40, 0xaa42 }, + { 0xaa44, 0xaa4b }, + { 0xaa60, 0xaa76 }, + { 0xaa7a, 0xaa7a }, + { 0xaa7e, 0xaaaf }, + { 0xaab1, 0xaab1 }, + { 0xaab5, 0xaab6 }, + { 0xaab9, 0xaabd }, + { 0xaac0, 0xaac0 }, + { 0xaac2, 0xaac2 }, + { 0xaadb, 0xaadd }, + { 0xaae0, 0xaaea }, + { 0xaaf2, 0xaaf4 }, + { 0xab01, 0xab06 }, + { 0xab09, 0xab0e }, + { 0xab11, 0xab16 }, + { 0xab20, 0xab26 }, + { 0xab28, 0xab2e }, + { 0xab30, 0xab5a }, + { 0xab5c, 0xab69 }, + { 0xab70, 0xabe2 }, + { 0xac00, 0xd7a3 }, + { 0xd7b0, 0xd7c6 }, + { 0xd7cb, 0xd7fb }, + { 0xf900, 0xfa6d }, + { 0xfa70, 0xfad9 }, + { 0xfb00, 0xfb06 }, + { 0xfb13, 0xfb17 }, + { 0xfb1d, 0xfb1d }, + { 0xfb1f, 0xfb28 }, + { 0xfb2a, 0xfb36 }, + { 0xfb38, 0xfb3c }, + { 0xfb3e, 0xfb3e }, + { 0xfb40, 0xfb41 }, + { 0xfb43, 0xfb44 }, + { 0xfb46, 0xfbb1 }, + { 0xfbd3, 0xfc5d }, + { 0xfc64, 0xfd3d }, + { 0xfd50, 0xfd8f }, + { 0xfd92, 0xfdc7 }, + { 0xfdf0, 0xfdf9 }, + { 0xfe71, 0xfe71 }, + { 0xfe73, 0xfe73 }, + { 0xfe77, 0xfe77 }, + { 0xfe79, 0xfe79 }, + { 0xfe7b, 0xfe7b }, + { 0xfe7d, 0xfe7d }, + { 0xfe7f, 0xfefc }, + { 0xff21, 0xff3a }, + { 0xff41, 0xff5a }, + { 0xff66, 0xff9d }, + { 0xffa0, 0xffbe }, + { 0xffc2, 0xffc7 }, + { 0xffca, 0xffcf }, + { 0xffd2, 0xffd7 }, + { 0xffda, 0xffdc }, + { 0x10000, 0x1000b }, + { 0x1000d, 0x10026 }, + { 0x10028, 0x1003a }, + { 0x1003c, 0x1003d }, + { 0x1003f, 0x1004d }, + { 0x10050, 0x1005d }, + { 0x10080, 0x100fa }, + { 0x10140, 0x10174 }, + { 0x10280, 0x1029c }, + { 0x102a0, 0x102d0 }, + { 0x10300, 0x1031f }, + { 0x1032d, 0x1034a }, + { 0x10350, 0x10375 }, + { 0x10380, 0x1039d }, + { 0x103a0, 0x103c3 }, + { 0x103c8, 0x103cf }, + { 0x103d1, 0x103d5 }, + { 0x10400, 0x1049d }, + { 0x104b0, 0x104d3 }, + { 0x104d8, 0x104fb }, + { 0x10500, 0x10527 }, + { 0x10530, 0x10563 }, + { 0x10570, 0x1057a }, + { 0x1057c, 0x1058a }, + { 0x1058c, 0x10592 }, + { 0x10594, 0x10595 }, + { 0x10597, 0x105a1 }, + { 0x105a3, 0x105b1 }, + { 0x105b3, 0x105b9 }, + { 0x105bb, 0x105bc }, + { 0x105c0, 0x105f3 }, + { 0x10600, 0x10736 }, + { 0x10740, 0x10755 }, + { 0x10760, 0x10767 }, + { 0x10780, 0x10785 }, + { 0x10787, 0x107b0 }, + { 0x107b2, 0x107ba }, + { 0x10800, 0x10805 }, + { 0x10808, 0x10808 }, + { 0x1080a, 0x10835 }, + { 0x10837, 0x10838 }, + { 0x1083c, 0x1083c }, + { 0x1083f, 0x10855 }, + { 0x10860, 0x10876 }, + { 0x10880, 0x1089e }, + { 0x108e0, 0x108f2 }, + { 0x108f4, 0x108f5 }, + { 0x10900, 0x10915 }, + { 0x10920, 0x10939 }, + { 0x10980, 0x109b7 }, + { 0x109be, 0x109bf }, + { 0x10a00, 0x10a00 }, + { 0x10a10, 0x10a13 }, + { 0x10a15, 0x10a17 }, + { 0x10a19, 0x10a35 }, + { 0x10a60, 0x10a7c }, + { 0x10a80, 0x10a9c }, + { 0x10ac0, 0x10ac7 }, + { 0x10ac9, 0x10ae4 }, + { 0x10b00, 0x10b35 }, + { 0x10b40, 0x10b55 }, + { 0x10b60, 0x10b72 }, + { 0x10b80, 0x10b91 }, + { 0x10c00, 0x10c48 }, + { 0x10c80, 0x10cb2 }, + { 0x10cc0, 0x10cf2 }, + { 0x10d00, 0x10d23 }, + { 0x10d4a, 0x10d65 }, + { 0x10d6f, 0x10d85 }, + { 0x10e80, 0x10ea9 }, + { 0x10eb0, 0x10eb1 }, + { 0x10ec2, 0x10ec4 }, + { 0x10f00, 0x10f1c }, + { 0x10f27, 0x10f27 }, + { 0x10f30, 0x10f45 }, + { 0x10f70, 0x10f81 }, + { 0x10fb0, 0x10fc4 }, + { 0x10fe0, 0x10ff6 }, + { 0x11003, 0x11037 }, + { 0x11071, 0x11072 }, + { 0x11075, 0x11075 }, + { 0x11083, 0x110af }, + { 0x110d0, 0x110e8 }, + { 0x11103, 0x11126 }, + { 0x11144, 0x11144 }, + { 0x11147, 0x11147 }, + { 0x11150, 0x11172 }, + { 0x11176, 0x11176 }, + { 0x11183, 0x111b2 }, + { 0x111c1, 0x111c4 }, + { 0x111da, 0x111da }, + { 0x111dc, 0x111dc }, + { 0x11200, 0x11211 }, + { 0x11213, 0x1122b }, + { 0x1123f, 0x11240 }, + { 0x11280, 0x11286 }, + { 0x11288, 0x11288 }, + { 0x1128a, 0x1128d }, + { 0x1128f, 0x1129d }, + { 0x1129f, 0x112a8 }, + { 0x112b0, 0x112de }, + { 0x11305, 0x1130c }, + { 0x1130f, 0x11310 }, + { 0x11313, 0x11328 }, + { 0x1132a, 0x11330 }, + { 0x11332, 0x11333 }, + { 0x11335, 0x11339 }, + { 0x1133d, 0x1133d }, + { 0x11350, 0x11350 }, + { 0x1135d, 0x11361 }, + { 0x11380, 0x11389 }, + { 0x1138b, 0x1138b }, + { 0x1138e, 0x1138e }, + { 0x11390, 0x113b5 }, + { 0x113b7, 0x113b7 }, + { 0x113d1, 0x113d1 }, + { 0x113d3, 0x113d3 }, + { 0x11400, 0x11434 }, + { 0x11447, 0x1144a }, + { 0x1145f, 0x11461 }, + { 0x11480, 0x114af }, + { 0x114c4, 0x114c5 }, + { 0x114c7, 0x114c7 }, + { 0x11580, 0x115ae }, + { 0x115d8, 0x115db }, + { 0x11600, 0x1162f }, + { 0x11644, 0x11644 }, + { 0x11680, 0x116aa }, + { 0x116b8, 0x116b8 }, + { 0x11700, 0x1171a }, + { 0x11740, 0x11746 }, + { 0x11800, 0x1182b }, + { 0x118a0, 0x118df }, + { 0x118ff, 0x11906 }, + { 0x11909, 0x11909 }, + { 0x1190c, 0x11913 }, + { 0x11915, 0x11916 }, + { 0x11918, 0x1192f }, + { 0x1193f, 0x1193f }, + { 0x11941, 0x11941 }, + { 0x119a0, 0x119a7 }, + { 0x119aa, 0x119d0 }, + { 0x119e1, 0x119e1 }, + { 0x119e3, 0x119e3 }, + { 0x11a00, 0x11a00 }, + { 0x11a0b, 0x11a32 }, + { 0x11a3a, 0x11a3a }, + { 0x11a50, 0x11a50 }, + { 0x11a5c, 0x11a89 }, + { 0x11a9d, 0x11a9d }, + { 0x11ab0, 0x11af8 }, + { 0x11bc0, 0x11be0 }, + { 0x11c00, 0x11c08 }, + { 0x11c0a, 0x11c2e }, + { 0x11c40, 0x11c40 }, + { 0x11c72, 0x11c8f }, + { 0x11d00, 0x11d06 }, + { 0x11d08, 0x11d09 }, + { 0x11d0b, 0x11d30 }, + { 0x11d46, 0x11d46 }, + { 0x11d60, 0x11d65 }, + { 0x11d67, 0x11d68 }, + { 0x11d6a, 0x11d89 }, + { 0x11d98, 0x11d98 }, + { 0x11ee0, 0x11ef2 }, + { 0x11f02, 0x11f02 }, + { 0x11f04, 0x11f10 }, + { 0x11f12, 0x11f33 }, + { 0x11fb0, 0x11fb0 }, + { 0x12000, 0x12399 }, + { 0x12400, 0x1246e }, + { 0x12480, 0x12543 }, + { 0x12f90, 0x12ff0 }, + { 0x13000, 0x1342f }, + { 0x13441, 0x13446 }, + { 0x13460, 0x143fa }, + { 0x14400, 0x14646 }, + { 0x16100, 0x1611d }, + { 0x16800, 0x16a38 }, + { 0x16a40, 0x16a5e }, + { 0x16a70, 0x16abe }, + { 0x16ad0, 0x16aed }, + { 0x16b00, 0x16b2f }, + { 0x16b40, 0x16b43 }, + { 0x16b63, 0x16b77 }, + { 0x16b7d, 0x16b8f }, + { 0x16d40, 0x16d6c }, + { 0x16e40, 0x16e7f }, + { 0x16f00, 0x16f4a }, + { 0x16f50, 0x16f50 }, + { 0x16f93, 0x16f9f }, + { 0x16fe0, 0x16fe1 }, + { 0x16fe3, 0x16fe3 }, + { 0x17000, 0x187f7 }, + { 0x18800, 0x18cd5 }, + { 0x18cff, 0x18d08 }, + { 0x1aff0, 0x1aff3 }, + { 0x1aff5, 0x1affb }, + { 0x1affd, 0x1affe }, + { 0x1b000, 0x1b122 }, + { 0x1b132, 0x1b132 }, + { 0x1b150, 0x1b152 }, + { 0x1b155, 0x1b155 }, + { 0x1b164, 0x1b167 }, + { 0x1b170, 0x1b2fb }, + { 0x1bc00, 0x1bc6a }, + { 0x1bc70, 0x1bc7c }, + { 0x1bc80, 0x1bc88 }, + { 0x1bc90, 0x1bc99 }, + { 0x1d400, 0x1d454 }, + { 0x1d456, 0x1d49c }, + { 0x1d49e, 0x1d49f }, + { 0x1d4a2, 0x1d4a2 }, + { 0x1d4a5, 0x1d4a6 }, + { 0x1d4a9, 0x1d4ac }, + { 0x1d4ae, 0x1d4b9 }, + { 0x1d4bb, 0x1d4bb }, + { 0x1d4bd, 0x1d4c3 }, + { 0x1d4c5, 0x1d505 }, + { 0x1d507, 0x1d50a }, + { 0x1d50d, 0x1d514 }, + { 0x1d516, 0x1d51c }, + { 0x1d51e, 0x1d539 }, + { 0x1d53b, 0x1d53e }, + { 0x1d540, 0x1d544 }, + { 0x1d546, 0x1d546 }, + { 0x1d54a, 0x1d550 }, + { 0x1d552, 0x1d6a5 }, + { 0x1d6a8, 0x1d6c0 }, + { 0x1d6c2, 0x1d6da }, + { 0x1d6dc, 0x1d6fa }, + { 0x1d6fc, 0x1d714 }, + { 0x1d716, 0x1d734 }, + { 0x1d736, 0x1d74e }, + { 0x1d750, 0x1d76e }, + { 0x1d770, 0x1d788 }, + { 0x1d78a, 0x1d7a8 }, + { 0x1d7aa, 0x1d7c2 }, + { 0x1d7c4, 0x1d7cb }, + { 0x1df00, 0x1df1e }, + { 0x1df25, 0x1df2a }, + { 0x1e030, 0x1e06d }, + { 0x1e100, 0x1e12c }, + { 0x1e137, 0x1e13d }, + { 0x1e14e, 0x1e14e }, + { 0x1e290, 0x1e2ad }, + { 0x1e2c0, 0x1e2eb }, + { 0x1e4d0, 0x1e4eb }, + { 0x1e5d0, 0x1e5ed }, + { 0x1e5f0, 0x1e5f0 }, + { 0x1e7e0, 0x1e7e6 }, + { 0x1e7e8, 0x1e7eb }, + { 0x1e7ed, 0x1e7ee }, + { 0x1e7f0, 0x1e7fe }, + { 0x1e800, 0x1e8c4 }, + { 0x1e900, 0x1e943 }, + { 0x1e94b, 0x1e94b }, + { 0x1ee00, 0x1ee03 }, + { 0x1ee05, 0x1ee1f }, + { 0x1ee21, 0x1ee22 }, + { 0x1ee24, 0x1ee24 }, + { 0x1ee27, 0x1ee27 }, + { 0x1ee29, 0x1ee32 }, + { 0x1ee34, 0x1ee37 }, + { 0x1ee39, 0x1ee39 }, + { 0x1ee3b, 0x1ee3b }, + { 0x1ee42, 0x1ee42 }, + { 0x1ee47, 0x1ee47 }, + { 0x1ee49, 0x1ee49 }, + { 0x1ee4b, 0x1ee4b }, + { 0x1ee4d, 0x1ee4f }, + { 0x1ee51, 0x1ee52 }, + { 0x1ee54, 0x1ee54 }, + { 0x1ee57, 0x1ee57 }, + { 0x1ee59, 0x1ee59 }, + { 0x1ee5b, 0x1ee5b }, + { 0x1ee5d, 0x1ee5d }, + { 0x1ee5f, 0x1ee5f }, + { 0x1ee61, 0x1ee62 }, + { 0x1ee64, 0x1ee64 }, + { 0x1ee67, 0x1ee6a }, + { 0x1ee6c, 0x1ee72 }, + { 0x1ee74, 0x1ee77 }, + { 0x1ee79, 0x1ee7c }, + { 0x1ee7e, 0x1ee7e }, + { 0x1ee80, 0x1ee89 }, + { 0x1ee8b, 0x1ee9b }, + { 0x1eea1, 0x1eea3 }, + { 0x1eea5, 0x1eea9 }, + { 0x1eeab, 0x1eebb }, + { 0x20000, 0x2a6df }, + { 0x2a700, 0x2b739 }, + { 0x2b740, 0x2b81d }, + { 0x2b820, 0x2cea1 }, + { 0x2ceb0, 0x2ebe0 }, + { 0x2ebf0, 0x2ee5d }, + { 0x2f800, 0x2fa1d }, + { 0x30000, 0x3134a }, + { 0x31350, 0x323af }, +}; + +constexpr inline CharRange xid_continue[] = { + { 0x30, 0x39 }, + { 0x41, 0x5a }, + { 0x5f, 0x5f }, + { 0x61, 0x7a }, + { 0xaa, 0xaa }, + { 0xb5, 0xb5 }, + { 0xb7, 0xb7 }, + { 0xba, 0xba }, + { 0xc0, 0xd6 }, + { 0xd8, 0xf6 }, + { 0xf8, 0x2c1 }, + { 0x2c6, 0x2d1 }, + { 0x2e0, 0x2e4 }, + { 0x2ec, 0x2ec }, + { 0x2ee, 0x2ee }, + { 0x300, 0x374 }, + { 0x376, 0x377 }, + { 0x37b, 0x37d }, + { 0x37f, 0x37f }, + { 0x386, 0x38a }, + { 0x38c, 0x38c }, + { 0x38e, 0x3a1 }, + { 0x3a3, 0x3f5 }, + { 0x3f7, 0x481 }, + { 0x483, 0x487 }, + { 0x48a, 0x52f }, + { 0x531, 0x556 }, + { 0x559, 0x559 }, + { 0x560, 0x588 }, + { 0x591, 0x5bd }, + { 0x5bf, 0x5bf }, + { 0x5c1, 0x5c2 }, + { 0x5c4, 0x5c5 }, + { 0x5c7, 0x5c7 }, + { 0x5d0, 0x5ea }, + { 0x5ef, 0x5f2 }, + { 0x610, 0x61a }, + { 0x620, 0x669 }, + { 0x66e, 0x6d3 }, + { 0x6d5, 0x6dc }, + { 0x6df, 0x6e8 }, + { 0x6ea, 0x6fc }, + { 0x6ff, 0x6ff }, + { 0x710, 0x74a }, + { 0x74d, 0x7b1 }, + { 0x7c0, 0x7f5 }, + { 0x7fa, 0x7fa }, + { 0x7fd, 0x7fd }, + { 0x800, 0x82d }, + { 0x840, 0x85b }, + { 0x860, 0x86a }, + { 0x870, 0x887 }, + { 0x889, 0x88e }, + { 0x897, 0x8e1 }, + { 0x8e3, 0x963 }, + { 0x966, 0x96f }, + { 0x971, 0x983 }, + { 0x985, 0x98c }, + { 0x98f, 0x990 }, + { 0x993, 0x9a8 }, + { 0x9aa, 0x9b0 }, + { 0x9b2, 0x9b2 }, + { 0x9b6, 0x9b9 }, + { 0x9bc, 0x9c4 }, + { 0x9c7, 0x9c8 }, + { 0x9cb, 0x9ce }, + { 0x9d7, 0x9d7 }, + { 0x9dc, 0x9dd }, + { 0x9df, 0x9e3 }, + { 0x9e6, 0x9f1 }, + { 0x9fc, 0x9fc }, + { 0x9fe, 0x9fe }, + { 0xa01, 0xa03 }, + { 0xa05, 0xa0a }, + { 0xa0f, 0xa10 }, + { 0xa13, 0xa28 }, + { 0xa2a, 0xa30 }, + { 0xa32, 0xa33 }, + { 0xa35, 0xa36 }, + { 0xa38, 0xa39 }, + { 0xa3c, 0xa3c }, + { 0xa3e, 0xa42 }, + { 0xa47, 0xa48 }, + { 0xa4b, 0xa4d }, + { 0xa51, 0xa51 }, + { 0xa59, 0xa5c }, + { 0xa5e, 0xa5e }, + { 0xa66, 0xa75 }, + { 0xa81, 0xa83 }, + { 0xa85, 0xa8d }, + { 0xa8f, 0xa91 }, + { 0xa93, 0xaa8 }, + { 0xaaa, 0xab0 }, + { 0xab2, 0xab3 }, + { 0xab5, 0xab9 }, + { 0xabc, 0xac5 }, + { 0xac7, 0xac9 }, + { 0xacb, 0xacd }, + { 0xad0, 0xad0 }, + { 0xae0, 0xae3 }, + { 0xae6, 0xaef }, + { 0xaf9, 0xaff }, + { 0xb01, 0xb03 }, + { 0xb05, 0xb0c }, + { 0xb0f, 0xb10 }, + { 0xb13, 0xb28 }, + { 0xb2a, 0xb30 }, + { 0xb32, 0xb33 }, + { 0xb35, 0xb39 }, + { 0xb3c, 0xb44 }, + { 0xb47, 0xb48 }, + { 0xb4b, 0xb4d }, + { 0xb55, 0xb57 }, + { 0xb5c, 0xb5d }, + { 0xb5f, 0xb63 }, + { 0xb66, 0xb6f }, + { 0xb71, 0xb71 }, + { 0xb82, 0xb83 }, + { 0xb85, 0xb8a }, + { 0xb8e, 0xb90 }, + { 0xb92, 0xb95 }, + { 0xb99, 0xb9a }, + { 0xb9c, 0xb9c }, + { 0xb9e, 0xb9f }, + { 0xba3, 0xba4 }, + { 0xba8, 0xbaa }, + { 0xbae, 0xbb9 }, + { 0xbbe, 0xbc2 }, + { 0xbc6, 0xbc8 }, + { 0xbca, 0xbcd }, + { 0xbd0, 0xbd0 }, + { 0xbd7, 0xbd7 }, + { 0xbe6, 0xbef }, + { 0xc00, 0xc0c }, + { 0xc0e, 0xc10 }, + { 0xc12, 0xc28 }, + { 0xc2a, 0xc39 }, + { 0xc3c, 0xc44 }, + { 0xc46, 0xc48 }, + { 0xc4a, 0xc4d }, + { 0xc55, 0xc56 }, + { 0xc58, 0xc5a }, + { 0xc5d, 0xc5d }, + { 0xc60, 0xc63 }, + { 0xc66, 0xc6f }, + { 0xc80, 0xc83 }, + { 0xc85, 0xc8c }, + { 0xc8e, 0xc90 }, + { 0xc92, 0xca8 }, + { 0xcaa, 0xcb3 }, + { 0xcb5, 0xcb9 }, + { 0xcbc, 0xcc4 }, + { 0xcc6, 0xcc8 }, + { 0xcca, 0xccd }, + { 0xcd5, 0xcd6 }, + { 0xcdd, 0xcde }, + { 0xce0, 0xce3 }, + { 0xce6, 0xcef }, + { 0xcf1, 0xcf3 }, + { 0xd00, 0xd0c }, + { 0xd0e, 0xd10 }, + { 0xd12, 0xd44 }, + { 0xd46, 0xd48 }, + { 0xd4a, 0xd4e }, + { 0xd54, 0xd57 }, + { 0xd5f, 0xd63 }, + { 0xd66, 0xd6f }, + { 0xd7a, 0xd7f }, + { 0xd81, 0xd83 }, + { 0xd85, 0xd96 }, + { 0xd9a, 0xdb1 }, + { 0xdb3, 0xdbb }, + { 0xdbd, 0xdbd }, + { 0xdc0, 0xdc6 }, + { 0xdca, 0xdca }, + { 0xdcf, 0xdd4 }, + { 0xdd6, 0xdd6 }, + { 0xdd8, 0xddf }, + { 0xde6, 0xdef }, + { 0xdf2, 0xdf3 }, + { 0xe01, 0xe3a }, + { 0xe40, 0xe4e }, + { 0xe50, 0xe59 }, + { 0xe81, 0xe82 }, + { 0xe84, 0xe84 }, + { 0xe86, 0xe8a }, + { 0xe8c, 0xea3 }, + { 0xea5, 0xea5 }, + { 0xea7, 0xebd }, + { 0xec0, 0xec4 }, + { 0xec6, 0xec6 }, + { 0xec8, 0xece }, + { 0xed0, 0xed9 }, + { 0xedc, 0xedf }, + { 0xf00, 0xf00 }, + { 0xf18, 0xf19 }, + { 0xf20, 0xf29 }, + { 0xf35, 0xf35 }, + { 0xf37, 0xf37 }, + { 0xf39, 0xf39 }, + { 0xf3e, 0xf47 }, + { 0xf49, 0xf6c }, + { 0xf71, 0xf84 }, + { 0xf86, 0xf97 }, + { 0xf99, 0xfbc }, + { 0xfc6, 0xfc6 }, + { 0x1000, 0x1049 }, + { 0x1050, 0x109d }, + { 0x10a0, 0x10c5 }, + { 0x10c7, 0x10c7 }, + { 0x10cd, 0x10cd }, + { 0x10d0, 0x10fa }, + { 0x10fc, 0x1248 }, + { 0x124a, 0x124d }, + { 0x1250, 0x1256 }, + { 0x1258, 0x1258 }, + { 0x125a, 0x125d }, + { 0x1260, 0x1288 }, + { 0x128a, 0x128d }, + { 0x1290, 0x12b0 }, + { 0x12b2, 0x12b5 }, + { 0x12b8, 0x12be }, + { 0x12c0, 0x12c0 }, + { 0x12c2, 0x12c5 }, + { 0x12c8, 0x12d6 }, + { 0x12d8, 0x1310 }, + { 0x1312, 0x1315 }, + { 0x1318, 0x135a }, + { 0x135d, 0x135f }, + { 0x1369, 0x1371 }, + { 0x1380, 0x138f }, + { 0x13a0, 0x13f5 }, + { 0x13f8, 0x13fd }, + { 0x1401, 0x166c }, + { 0x166f, 0x167f }, + { 0x1681, 0x169a }, + { 0x16a0, 0x16ea }, + { 0x16ee, 0x16f8 }, + { 0x1700, 0x1715 }, + { 0x171f, 0x1734 }, + { 0x1740, 0x1753 }, + { 0x1760, 0x176c }, + { 0x176e, 0x1770 }, + { 0x1772, 0x1773 }, + { 0x1780, 0x17d3 }, + { 0x17d7, 0x17d7 }, + { 0x17dc, 0x17dd }, + { 0x17e0, 0x17e9 }, + { 0x180b, 0x180d }, + { 0x180f, 0x1819 }, + { 0x1820, 0x1878 }, + { 0x1880, 0x18aa }, + { 0x18b0, 0x18f5 }, + { 0x1900, 0x191e }, + { 0x1920, 0x192b }, + { 0x1930, 0x193b }, + { 0x1946, 0x196d }, + { 0x1970, 0x1974 }, + { 0x1980, 0x19ab }, + { 0x19b0, 0x19c9 }, + { 0x19d0, 0x19da }, + { 0x1a00, 0x1a1b }, + { 0x1a20, 0x1a5e }, + { 0x1a60, 0x1a7c }, + { 0x1a7f, 0x1a89 }, + { 0x1a90, 0x1a99 }, + { 0x1aa7, 0x1aa7 }, + { 0x1ab0, 0x1abd }, + { 0x1abf, 0x1ace }, + { 0x1b00, 0x1b4c }, + { 0x1b50, 0x1b59 }, + { 0x1b6b, 0x1b73 }, + { 0x1b80, 0x1bf3 }, + { 0x1c00, 0x1c37 }, + { 0x1c40, 0x1c49 }, + { 0x1c4d, 0x1c7d }, + { 0x1c80, 0x1c8a }, + { 0x1c90, 0x1cba }, + { 0x1cbd, 0x1cbf }, + { 0x1cd0, 0x1cd2 }, + { 0x1cd4, 0x1cfa }, + { 0x1d00, 0x1f15 }, + { 0x1f18, 0x1f1d }, + { 0x1f20, 0x1f45 }, + { 0x1f48, 0x1f4d }, + { 0x1f50, 0x1f57 }, + { 0x1f59, 0x1f59 }, + { 0x1f5b, 0x1f5b }, + { 0x1f5d, 0x1f5d }, + { 0x1f5f, 0x1f7d }, + { 0x1f80, 0x1fb4 }, + { 0x1fb6, 0x1fbc }, + { 0x1fbe, 0x1fbe }, + { 0x1fc2, 0x1fc4 }, + { 0x1fc6, 0x1fcc }, + { 0x1fd0, 0x1fd3 }, + { 0x1fd6, 0x1fdb }, + { 0x1fe0, 0x1fec }, + { 0x1ff2, 0x1ff4 }, + { 0x1ff6, 0x1ffc }, + { 0x200c, 0x200d }, + { 0x203f, 0x2040 }, + { 0x2054, 0x2054 }, + { 0x2071, 0x2071 }, + { 0x207f, 0x207f }, + { 0x2090, 0x209c }, + { 0x20d0, 0x20dc }, + { 0x20e1, 0x20e1 }, + { 0x20e5, 0x20f0 }, + { 0x2102, 0x2102 }, + { 0x2107, 0x2107 }, + { 0x210a, 0x2113 }, + { 0x2115, 0x2115 }, + { 0x2118, 0x211d }, + { 0x2124, 0x2124 }, + { 0x2126, 0x2126 }, + { 0x2128, 0x2128 }, + { 0x212a, 0x2139 }, + { 0x213c, 0x213f }, + { 0x2145, 0x2149 }, + { 0x214e, 0x214e }, + { 0x2160, 0x2188 }, + { 0x2c00, 0x2ce4 }, + { 0x2ceb, 0x2cf3 }, + { 0x2d00, 0x2d25 }, + { 0x2d27, 0x2d27 }, + { 0x2d2d, 0x2d2d }, + { 0x2d30, 0x2d67 }, + { 0x2d6f, 0x2d6f }, + { 0x2d7f, 0x2d96 }, + { 0x2da0, 0x2da6 }, + { 0x2da8, 0x2dae }, + { 0x2db0, 0x2db6 }, + { 0x2db8, 0x2dbe }, + { 0x2dc0, 0x2dc6 }, + { 0x2dc8, 0x2dce }, + { 0x2dd0, 0x2dd6 }, + { 0x2dd8, 0x2dde }, + { 0x2de0, 0x2dff }, + { 0x3005, 0x3007 }, + { 0x3021, 0x302f }, + { 0x3031, 0x3035 }, + { 0x3038, 0x303c }, + { 0x3041, 0x3096 }, + { 0x3099, 0x309a }, + { 0x309d, 0x309f }, + { 0x30a1, 0x30ff }, + { 0x3105, 0x312f }, + { 0x3131, 0x318e }, + { 0x31a0, 0x31bf }, + { 0x31f0, 0x31ff }, + { 0x3400, 0x4dbf }, + { 0x4e00, 0xa48c }, + { 0xa4d0, 0xa4fd }, + { 0xa500, 0xa60c }, + { 0xa610, 0xa62b }, + { 0xa640, 0xa66f }, + { 0xa674, 0xa67d }, + { 0xa67f, 0xa6f1 }, + { 0xa717, 0xa71f }, + { 0xa722, 0xa788 }, + { 0xa78b, 0xa7cd }, + { 0xa7d0, 0xa7d1 }, + { 0xa7d3, 0xa7d3 }, + { 0xa7d5, 0xa7dc }, + { 0xa7f2, 0xa827 }, + { 0xa82c, 0xa82c }, + { 0xa840, 0xa873 }, + { 0xa880, 0xa8c5 }, + { 0xa8d0, 0xa8d9 }, + { 0xa8e0, 0xa8f7 }, + { 0xa8fb, 0xa8fb }, + { 0xa8fd, 0xa92d }, + { 0xa930, 0xa953 }, + { 0xa960, 0xa97c }, + { 0xa980, 0xa9c0 }, + { 0xa9cf, 0xa9d9 }, + { 0xa9e0, 0xa9fe }, + { 0xaa00, 0xaa36 }, + { 0xaa40, 0xaa4d }, + { 0xaa50, 0xaa59 }, + { 0xaa60, 0xaa76 }, + { 0xaa7a, 0xaac2 }, + { 0xaadb, 0xaadd }, + { 0xaae0, 0xaaef }, + { 0xaaf2, 0xaaf6 }, + { 0xab01, 0xab06 }, + { 0xab09, 0xab0e }, + { 0xab11, 0xab16 }, + { 0xab20, 0xab26 }, + { 0xab28, 0xab2e }, + { 0xab30, 0xab5a }, + { 0xab5c, 0xab69 }, + { 0xab70, 0xabea }, + { 0xabec, 0xabed }, + { 0xabf0, 0xabf9 }, + { 0xac00, 0xd7a3 }, + { 0xd7b0, 0xd7c6 }, + { 0xd7cb, 0xd7fb }, + { 0xf900, 0xfa6d }, + { 0xfa70, 0xfad9 }, + { 0xfb00, 0xfb06 }, + { 0xfb13, 0xfb17 }, + { 0xfb1d, 0xfb28 }, + { 0xfb2a, 0xfb36 }, + { 0xfb38, 0xfb3c }, + { 0xfb3e, 0xfb3e }, + { 0xfb40, 0xfb41 }, + { 0xfb43, 0xfb44 }, + { 0xfb46, 0xfbb1 }, + { 0xfbd3, 0xfc5d }, + { 0xfc64, 0xfd3d }, + { 0xfd50, 0xfd8f }, + { 0xfd92, 0xfdc7 }, + { 0xfdf0, 0xfdf9 }, + { 0xfe00, 0xfe0f }, + { 0xfe20, 0xfe2f }, + { 0xfe33, 0xfe34 }, + { 0xfe4d, 0xfe4f }, + { 0xfe71, 0xfe71 }, + { 0xfe73, 0xfe73 }, + { 0xfe77, 0xfe77 }, + { 0xfe79, 0xfe79 }, + { 0xfe7b, 0xfe7b }, + { 0xfe7d, 0xfe7d }, + { 0xfe7f, 0xfefc }, + { 0xff10, 0xff19 }, + { 0xff21, 0xff3a }, + { 0xff3f, 0xff3f }, + { 0xff41, 0xff5a }, + { 0xff65, 0xffbe }, + { 0xffc2, 0xffc7 }, + { 0xffca, 0xffcf }, + { 0xffd2, 0xffd7 }, + { 0xffda, 0xffdc }, + { 0x10000, 0x1000b }, + { 0x1000d, 0x10026 }, + { 0x10028, 0x1003a }, + { 0x1003c, 0x1003d }, + { 0x1003f, 0x1004d }, + { 0x10050, 0x1005d }, + { 0x10080, 0x100fa }, + { 0x10140, 0x10174 }, + { 0x101fd, 0x101fd }, + { 0x10280, 0x1029c }, + { 0x102a0, 0x102d0 }, + { 0x102e0, 0x102e0 }, + { 0x10300, 0x1031f }, + { 0x1032d, 0x1034a }, + { 0x10350, 0x1037a }, + { 0x10380, 0x1039d }, + { 0x103a0, 0x103c3 }, + { 0x103c8, 0x103cf }, + { 0x103d1, 0x103d5 }, + { 0x10400, 0x1049d }, + { 0x104a0, 0x104a9 }, + { 0x104b0, 0x104d3 }, + { 0x104d8, 0x104fb }, + { 0x10500, 0x10527 }, + { 0x10530, 0x10563 }, + { 0x10570, 0x1057a }, + { 0x1057c, 0x1058a }, + { 0x1058c, 0x10592 }, + { 0x10594, 0x10595 }, + { 0x10597, 0x105a1 }, + { 0x105a3, 0x105b1 }, + { 0x105b3, 0x105b9 }, + { 0x105bb, 0x105bc }, + { 0x105c0, 0x105f3 }, + { 0x10600, 0x10736 }, + { 0x10740, 0x10755 }, + { 0x10760, 0x10767 }, + { 0x10780, 0x10785 }, + { 0x10787, 0x107b0 }, + { 0x107b2, 0x107ba }, + { 0x10800, 0x10805 }, + { 0x10808, 0x10808 }, + { 0x1080a, 0x10835 }, + { 0x10837, 0x10838 }, + { 0x1083c, 0x1083c }, + { 0x1083f, 0x10855 }, + { 0x10860, 0x10876 }, + { 0x10880, 0x1089e }, + { 0x108e0, 0x108f2 }, + { 0x108f4, 0x108f5 }, + { 0x10900, 0x10915 }, + { 0x10920, 0x10939 }, + { 0x10980, 0x109b7 }, + { 0x109be, 0x109bf }, + { 0x10a00, 0x10a03 }, + { 0x10a05, 0x10a06 }, + { 0x10a0c, 0x10a13 }, + { 0x10a15, 0x10a17 }, + { 0x10a19, 0x10a35 }, + { 0x10a38, 0x10a3a }, + { 0x10a3f, 0x10a3f }, + { 0x10a60, 0x10a7c }, + { 0x10a80, 0x10a9c }, + { 0x10ac0, 0x10ac7 }, + { 0x10ac9, 0x10ae6 }, + { 0x10b00, 0x10b35 }, + { 0x10b40, 0x10b55 }, + { 0x10b60, 0x10b72 }, + { 0x10b80, 0x10b91 }, + { 0x10c00, 0x10c48 }, + { 0x10c80, 0x10cb2 }, + { 0x10cc0, 0x10cf2 }, + { 0x10d00, 0x10d27 }, + { 0x10d30, 0x10d39 }, + { 0x10d40, 0x10d65 }, + { 0x10d69, 0x10d6d }, + { 0x10d6f, 0x10d85 }, + { 0x10e80, 0x10ea9 }, + { 0x10eab, 0x10eac }, + { 0x10eb0, 0x10eb1 }, + { 0x10ec2, 0x10ec4 }, + { 0x10efc, 0x10f1c }, + { 0x10f27, 0x10f27 }, + { 0x10f30, 0x10f50 }, + { 0x10f70, 0x10f85 }, + { 0x10fb0, 0x10fc4 }, + { 0x10fe0, 0x10ff6 }, + { 0x11000, 0x11046 }, + { 0x11066, 0x11075 }, + { 0x1107f, 0x110ba }, + { 0x110c2, 0x110c2 }, + { 0x110d0, 0x110e8 }, + { 0x110f0, 0x110f9 }, + { 0x11100, 0x11134 }, + { 0x11136, 0x1113f }, + { 0x11144, 0x11147 }, + { 0x11150, 0x11173 }, + { 0x11176, 0x11176 }, + { 0x11180, 0x111c4 }, + { 0x111c9, 0x111cc }, + { 0x111ce, 0x111da }, + { 0x111dc, 0x111dc }, + { 0x11200, 0x11211 }, + { 0x11213, 0x11237 }, + { 0x1123e, 0x11241 }, + { 0x11280, 0x11286 }, + { 0x11288, 0x11288 }, + { 0x1128a, 0x1128d }, + { 0x1128f, 0x1129d }, + { 0x1129f, 0x112a8 }, + { 0x112b0, 0x112ea }, + { 0x112f0, 0x112f9 }, + { 0x11300, 0x11303 }, + { 0x11305, 0x1130c }, + { 0x1130f, 0x11310 }, + { 0x11313, 0x11328 }, + { 0x1132a, 0x11330 }, + { 0x11332, 0x11333 }, + { 0x11335, 0x11339 }, + { 0x1133b, 0x11344 }, + { 0x11347, 0x11348 }, + { 0x1134b, 0x1134d }, + { 0x11350, 0x11350 }, + { 0x11357, 0x11357 }, + { 0x1135d, 0x11363 }, + { 0x11366, 0x1136c }, + { 0x11370, 0x11374 }, + { 0x11380, 0x11389 }, + { 0x1138b, 0x1138b }, + { 0x1138e, 0x1138e }, + { 0x11390, 0x113b5 }, + { 0x113b7, 0x113c0 }, + { 0x113c2, 0x113c2 }, + { 0x113c5, 0x113c5 }, + { 0x113c7, 0x113ca }, + { 0x113cc, 0x113d3 }, + { 0x113e1, 0x113e2 }, + { 0x11400, 0x1144a }, + { 0x11450, 0x11459 }, + { 0x1145e, 0x11461 }, + { 0x11480, 0x114c5 }, + { 0x114c7, 0x114c7 }, + { 0x114d0, 0x114d9 }, + { 0x11580, 0x115b5 }, + { 0x115b8, 0x115c0 }, + { 0x115d8, 0x115dd }, + { 0x11600, 0x11640 }, + { 0x11644, 0x11644 }, + { 0x11650, 0x11659 }, + { 0x11680, 0x116b8 }, + { 0x116c0, 0x116c9 }, + { 0x116d0, 0x116e3 }, + { 0x11700, 0x1171a }, + { 0x1171d, 0x1172b }, + { 0x11730, 0x11739 }, + { 0x11740, 0x11746 }, + { 0x11800, 0x1183a }, + { 0x118a0, 0x118e9 }, + { 0x118ff, 0x11906 }, + { 0x11909, 0x11909 }, + { 0x1190c, 0x11913 }, + { 0x11915, 0x11916 }, + { 0x11918, 0x11935 }, + { 0x11937, 0x11938 }, + { 0x1193b, 0x11943 }, + { 0x11950, 0x11959 }, + { 0x119a0, 0x119a7 }, + { 0x119aa, 0x119d7 }, + { 0x119da, 0x119e1 }, + { 0x119e3, 0x119e4 }, + { 0x11a00, 0x11a3e }, + { 0x11a47, 0x11a47 }, + { 0x11a50, 0x11a99 }, + { 0x11a9d, 0x11a9d }, + { 0x11ab0, 0x11af8 }, + { 0x11bc0, 0x11be0 }, + { 0x11bf0, 0x11bf9 }, + { 0x11c00, 0x11c08 }, + { 0x11c0a, 0x11c36 }, + { 0x11c38, 0x11c40 }, + { 0x11c50, 0x11c59 }, + { 0x11c72, 0x11c8f }, + { 0x11c92, 0x11ca7 }, + { 0x11ca9, 0x11cb6 }, + { 0x11d00, 0x11d06 }, + { 0x11d08, 0x11d09 }, + { 0x11d0b, 0x11d36 }, + { 0x11d3a, 0x11d3a }, + { 0x11d3c, 0x11d3d }, + { 0x11d3f, 0x11d47 }, + { 0x11d50, 0x11d59 }, + { 0x11d60, 0x11d65 }, + { 0x11d67, 0x11d68 }, + { 0x11d6a, 0x11d8e }, + { 0x11d90, 0x11d91 }, + { 0x11d93, 0x11d98 }, + { 0x11da0, 0x11da9 }, + { 0x11ee0, 0x11ef6 }, + { 0x11f00, 0x11f10 }, + { 0x11f12, 0x11f3a }, + { 0x11f3e, 0x11f42 }, + { 0x11f50, 0x11f5a }, + { 0x11fb0, 0x11fb0 }, + { 0x12000, 0x12399 }, + { 0x12400, 0x1246e }, + { 0x12480, 0x12543 }, + { 0x12f90, 0x12ff0 }, + { 0x13000, 0x1342f }, + { 0x13440, 0x13455 }, + { 0x13460, 0x143fa }, + { 0x14400, 0x14646 }, + { 0x16100, 0x16139 }, + { 0x16800, 0x16a38 }, + { 0x16a40, 0x16a5e }, + { 0x16a60, 0x16a69 }, + { 0x16a70, 0x16abe }, + { 0x16ac0, 0x16ac9 }, + { 0x16ad0, 0x16aed }, + { 0x16af0, 0x16af4 }, + { 0x16b00, 0x16b36 }, + { 0x16b40, 0x16b43 }, + { 0x16b50, 0x16b59 }, + { 0x16b63, 0x16b77 }, + { 0x16b7d, 0x16b8f }, + { 0x16d40, 0x16d6c }, + { 0x16d70, 0x16d79 }, + { 0x16e40, 0x16e7f }, + { 0x16f00, 0x16f4a }, + { 0x16f4f, 0x16f87 }, + { 0x16f8f, 0x16f9f }, + { 0x16fe0, 0x16fe1 }, + { 0x16fe3, 0x16fe4 }, + { 0x16ff0, 0x16ff1 }, + { 0x17000, 0x187f7 }, + { 0x18800, 0x18cd5 }, + { 0x18cff, 0x18d08 }, + { 0x1aff0, 0x1aff3 }, + { 0x1aff5, 0x1affb }, + { 0x1affd, 0x1affe }, + { 0x1b000, 0x1b122 }, + { 0x1b132, 0x1b132 }, + { 0x1b150, 0x1b152 }, + { 0x1b155, 0x1b155 }, + { 0x1b164, 0x1b167 }, + { 0x1b170, 0x1b2fb }, + { 0x1bc00, 0x1bc6a }, + { 0x1bc70, 0x1bc7c }, + { 0x1bc80, 0x1bc88 }, + { 0x1bc90, 0x1bc99 }, + { 0x1bc9d, 0x1bc9e }, + { 0x1ccf0, 0x1ccf9 }, + { 0x1cf00, 0x1cf2d }, + { 0x1cf30, 0x1cf46 }, + { 0x1d165, 0x1d169 }, + { 0x1d16d, 0x1d172 }, + { 0x1d17b, 0x1d182 }, + { 0x1d185, 0x1d18b }, + { 0x1d1aa, 0x1d1ad }, + { 0x1d242, 0x1d244 }, + { 0x1d400, 0x1d454 }, + { 0x1d456, 0x1d49c }, + { 0x1d49e, 0x1d49f }, + { 0x1d4a2, 0x1d4a2 }, + { 0x1d4a5, 0x1d4a6 }, + { 0x1d4a9, 0x1d4ac }, + { 0x1d4ae, 0x1d4b9 }, + { 0x1d4bb, 0x1d4bb }, + { 0x1d4bd, 0x1d4c3 }, + { 0x1d4c5, 0x1d505 }, + { 0x1d507, 0x1d50a }, + { 0x1d50d, 0x1d514 }, + { 0x1d516, 0x1d51c }, + { 0x1d51e, 0x1d539 }, + { 0x1d53b, 0x1d53e }, + { 0x1d540, 0x1d544 }, + { 0x1d546, 0x1d546 }, + { 0x1d54a, 0x1d550 }, + { 0x1d552, 0x1d6a5 }, + { 0x1d6a8, 0x1d6c0 }, + { 0x1d6c2, 0x1d6da }, + { 0x1d6dc, 0x1d6fa }, + { 0x1d6fc, 0x1d714 }, + { 0x1d716, 0x1d734 }, + { 0x1d736, 0x1d74e }, + { 0x1d750, 0x1d76e }, + { 0x1d770, 0x1d788 }, + { 0x1d78a, 0x1d7a8 }, + { 0x1d7aa, 0x1d7c2 }, + { 0x1d7c4, 0x1d7cb }, + { 0x1d7ce, 0x1d7ff }, + { 0x1da00, 0x1da36 }, + { 0x1da3b, 0x1da6c }, + { 0x1da75, 0x1da75 }, + { 0x1da84, 0x1da84 }, + { 0x1da9b, 0x1da9f }, + { 0x1daa1, 0x1daaf }, + { 0x1df00, 0x1df1e }, + { 0x1df25, 0x1df2a }, + { 0x1e000, 0x1e006 }, + { 0x1e008, 0x1e018 }, + { 0x1e01b, 0x1e021 }, + { 0x1e023, 0x1e024 }, + { 0x1e026, 0x1e02a }, + { 0x1e030, 0x1e06d }, + { 0x1e08f, 0x1e08f }, + { 0x1e100, 0x1e12c }, + { 0x1e130, 0x1e13d }, + { 0x1e140, 0x1e149 }, + { 0x1e14e, 0x1e14e }, + { 0x1e290, 0x1e2ae }, + { 0x1e2c0, 0x1e2f9 }, + { 0x1e4d0, 0x1e4f9 }, + { 0x1e5d0, 0x1e5fa }, + { 0x1e7e0, 0x1e7e6 }, + { 0x1e7e8, 0x1e7eb }, + { 0x1e7ed, 0x1e7ee }, + { 0x1e7f0, 0x1e7fe }, + { 0x1e800, 0x1e8c4 }, + { 0x1e8d0, 0x1e8d6 }, + { 0x1e900, 0x1e94b }, + { 0x1e950, 0x1e959 }, + { 0x1ee00, 0x1ee03 }, + { 0x1ee05, 0x1ee1f }, + { 0x1ee21, 0x1ee22 }, + { 0x1ee24, 0x1ee24 }, + { 0x1ee27, 0x1ee27 }, + { 0x1ee29, 0x1ee32 }, + { 0x1ee34, 0x1ee37 }, + { 0x1ee39, 0x1ee39 }, + { 0x1ee3b, 0x1ee3b }, + { 0x1ee42, 0x1ee42 }, + { 0x1ee47, 0x1ee47 }, + { 0x1ee49, 0x1ee49 }, + { 0x1ee4b, 0x1ee4b }, + { 0x1ee4d, 0x1ee4f }, + { 0x1ee51, 0x1ee52 }, + { 0x1ee54, 0x1ee54 }, + { 0x1ee57, 0x1ee57 }, + { 0x1ee59, 0x1ee59 }, + { 0x1ee5b, 0x1ee5b }, + { 0x1ee5d, 0x1ee5d }, + { 0x1ee5f, 0x1ee5f }, + { 0x1ee61, 0x1ee62 }, + { 0x1ee64, 0x1ee64 }, + { 0x1ee67, 0x1ee6a }, + { 0x1ee6c, 0x1ee72 }, + { 0x1ee74, 0x1ee77 }, + { 0x1ee79, 0x1ee7c }, + { 0x1ee7e, 0x1ee7e }, + { 0x1ee80, 0x1ee89 }, + { 0x1ee8b, 0x1ee9b }, + { 0x1eea1, 0x1eea3 }, + { 0x1eea5, 0x1eea9 }, + { 0x1eeab, 0x1eebb }, + { 0x1fbf0, 0x1fbf9 }, + { 0x20000, 0x2a6df }, + { 0x2a700, 0x2b739 }, + { 0x2b740, 0x2b81d }, + { 0x2b820, 0x2cea1 }, + { 0x2ceb0, 0x2ebe0 }, + { 0x2ebf0, 0x2ee5d }, + { 0x2f800, 0x2fa1d }, + { 0x30000, 0x3134a }, + { 0x31350, 0x323af }, + { 0xe0100, 0xe01ef }, +}; + +constexpr inline CharRange uppercase_letter[] = { + { 0x41, 0x5a }, + { 0xc0, 0xd6 }, + { 0xd8, 0xde }, + { 0x100, 0x100 }, + { 0x102, 0x102 }, + { 0x104, 0x104 }, + { 0x106, 0x106 }, + { 0x108, 0x108 }, + { 0x10a, 0x10a }, + { 0x10c, 0x10c }, + { 0x10e, 0x10e }, + { 0x110, 0x110 }, + { 0x112, 0x112 }, + { 0x114, 0x114 }, + { 0x116, 0x116 }, + { 0x118, 0x118 }, + { 0x11a, 0x11a }, + { 0x11c, 0x11c }, + { 0x11e, 0x11e }, + { 0x120, 0x120 }, + { 0x122, 0x122 }, + { 0x124, 0x124 }, + { 0x126, 0x126 }, + { 0x128, 0x128 }, + { 0x12a, 0x12a }, + { 0x12c, 0x12c }, + { 0x12e, 0x12e }, + { 0x130, 0x130 }, + { 0x132, 0x132 }, + { 0x134, 0x134 }, + { 0x136, 0x136 }, + { 0x139, 0x139 }, + { 0x13b, 0x13b }, + { 0x13d, 0x13d }, + { 0x13f, 0x13f }, + { 0x141, 0x141 }, + { 0x143, 0x143 }, + { 0x145, 0x145 }, + { 0x147, 0x147 }, + { 0x14a, 0x14a }, + { 0x14c, 0x14c }, + { 0x14e, 0x14e }, + { 0x150, 0x150 }, + { 0x152, 0x152 }, + { 0x154, 0x154 }, + { 0x156, 0x156 }, + { 0x158, 0x158 }, + { 0x15a, 0x15a }, + { 0x15c, 0x15c }, + { 0x15e, 0x15e }, + { 0x160, 0x160 }, + { 0x162, 0x162 }, + { 0x164, 0x164 }, + { 0x166, 0x166 }, + { 0x168, 0x168 }, + { 0x16a, 0x16a }, + { 0x16c, 0x16c }, + { 0x16e, 0x16e }, + { 0x170, 0x170 }, + { 0x172, 0x172 }, + { 0x174, 0x174 }, + { 0x176, 0x176 }, + { 0x178, 0x179 }, + { 0x17b, 0x17b }, + { 0x17d, 0x17d }, + { 0x181, 0x182 }, + { 0x184, 0x184 }, + { 0x186, 0x187 }, + { 0x189, 0x18b }, + { 0x18e, 0x191 }, + { 0x193, 0x194 }, + { 0x196, 0x198 }, + { 0x19c, 0x19d }, + { 0x19f, 0x1a0 }, + { 0x1a2, 0x1a2 }, + { 0x1a4, 0x1a4 }, + { 0x1a6, 0x1a7 }, + { 0x1a9, 0x1a9 }, + { 0x1ac, 0x1ac }, + { 0x1ae, 0x1af }, + { 0x1b1, 0x1b3 }, + { 0x1b5, 0x1b5 }, + { 0x1b7, 0x1b8 }, + { 0x1bc, 0x1bc }, + { 0x1c4, 0x1c4 }, + { 0x1c7, 0x1c7 }, + { 0x1ca, 0x1ca }, + { 0x1cd, 0x1cd }, + { 0x1cf, 0x1cf }, + { 0x1d1, 0x1d1 }, + { 0x1d3, 0x1d3 }, + { 0x1d5, 0x1d5 }, + { 0x1d7, 0x1d7 }, + { 0x1d9, 0x1d9 }, + { 0x1db, 0x1db }, + { 0x1de, 0x1de }, + { 0x1e0, 0x1e0 }, + { 0x1e2, 0x1e2 }, + { 0x1e4, 0x1e4 }, + { 0x1e6, 0x1e6 }, + { 0x1e8, 0x1e8 }, + { 0x1ea, 0x1ea }, + { 0x1ec, 0x1ec }, + { 0x1ee, 0x1ee }, + { 0x1f1, 0x1f1 }, + { 0x1f4, 0x1f4 }, + { 0x1f6, 0x1f8 }, + { 0x1fa, 0x1fa }, + { 0x1fc, 0x1fc }, + { 0x1fe, 0x1fe }, + { 0x200, 0x200 }, + { 0x202, 0x202 }, + { 0x204, 0x204 }, + { 0x206, 0x206 }, + { 0x208, 0x208 }, + { 0x20a, 0x20a }, + { 0x20c, 0x20c }, + { 0x20e, 0x20e }, + { 0x210, 0x210 }, + { 0x212, 0x212 }, + { 0x214, 0x214 }, + { 0x216, 0x216 }, + { 0x218, 0x218 }, + { 0x21a, 0x21a }, + { 0x21c, 0x21c }, + { 0x21e, 0x21e }, + { 0x220, 0x220 }, + { 0x222, 0x222 }, + { 0x224, 0x224 }, + { 0x226, 0x226 }, + { 0x228, 0x228 }, + { 0x22a, 0x22a }, + { 0x22c, 0x22c }, + { 0x22e, 0x22e }, + { 0x230, 0x230 }, + { 0x232, 0x232 }, + { 0x23a, 0x23b }, + { 0x23d, 0x23e }, + { 0x241, 0x241 }, + { 0x243, 0x246 }, + { 0x248, 0x248 }, + { 0x24a, 0x24a }, + { 0x24c, 0x24c }, + { 0x24e, 0x24e }, + { 0x370, 0x370 }, + { 0x372, 0x372 }, + { 0x376, 0x376 }, + { 0x37f, 0x37f }, + { 0x386, 0x386 }, + { 0x388, 0x38a }, + { 0x38c, 0x38c }, + { 0x38e, 0x38f }, + { 0x391, 0x3a1 }, + { 0x3a3, 0x3ab }, + { 0x3cf, 0x3cf }, + { 0x3d2, 0x3d4 }, + { 0x3d8, 0x3d8 }, + { 0x3da, 0x3da }, + { 0x3dc, 0x3dc }, + { 0x3de, 0x3de }, + { 0x3e0, 0x3e0 }, + { 0x3e2, 0x3e2 }, + { 0x3e4, 0x3e4 }, + { 0x3e6, 0x3e6 }, + { 0x3e8, 0x3e8 }, + { 0x3ea, 0x3ea }, + { 0x3ec, 0x3ec }, + { 0x3ee, 0x3ee }, + { 0x3f4, 0x3f4 }, + { 0x3f7, 0x3f7 }, + { 0x3f9, 0x3fa }, + { 0x3fd, 0x42f }, + { 0x460, 0x460 }, + { 0x462, 0x462 }, + { 0x464, 0x464 }, + { 0x466, 0x466 }, + { 0x468, 0x468 }, + { 0x46a, 0x46a }, + { 0x46c, 0x46c }, + { 0x46e, 0x46e }, + { 0x470, 0x470 }, + { 0x472, 0x472 }, + { 0x474, 0x474 }, + { 0x476, 0x476 }, + { 0x478, 0x478 }, + { 0x47a, 0x47a }, + { 0x47c, 0x47c }, + { 0x47e, 0x47e }, + { 0x480, 0x480 }, + { 0x48a, 0x48a }, + { 0x48c, 0x48c }, + { 0x48e, 0x48e }, + { 0x490, 0x490 }, + { 0x492, 0x492 }, + { 0x494, 0x494 }, + { 0x496, 0x496 }, + { 0x498, 0x498 }, + { 0x49a, 0x49a }, + { 0x49c, 0x49c }, + { 0x49e, 0x49e }, + { 0x4a0, 0x4a0 }, + { 0x4a2, 0x4a2 }, + { 0x4a4, 0x4a4 }, + { 0x4a6, 0x4a6 }, + { 0x4a8, 0x4a8 }, + { 0x4aa, 0x4aa }, + { 0x4ac, 0x4ac }, + { 0x4ae, 0x4ae }, + { 0x4b0, 0x4b0 }, + { 0x4b2, 0x4b2 }, + { 0x4b4, 0x4b4 }, + { 0x4b6, 0x4b6 }, + { 0x4b8, 0x4b8 }, + { 0x4ba, 0x4ba }, + { 0x4bc, 0x4bc }, + { 0x4be, 0x4be }, + { 0x4c0, 0x4c1 }, + { 0x4c3, 0x4c3 }, + { 0x4c5, 0x4c5 }, + { 0x4c7, 0x4c7 }, + { 0x4c9, 0x4c9 }, + { 0x4cb, 0x4cb }, + { 0x4cd, 0x4cd }, + { 0x4d0, 0x4d0 }, + { 0x4d2, 0x4d2 }, + { 0x4d4, 0x4d4 }, + { 0x4d6, 0x4d6 }, + { 0x4d8, 0x4d8 }, + { 0x4da, 0x4da }, + { 0x4dc, 0x4dc }, + { 0x4de, 0x4de }, + { 0x4e0, 0x4e0 }, + { 0x4e2, 0x4e2 }, + { 0x4e4, 0x4e4 }, + { 0x4e6, 0x4e6 }, + { 0x4e8, 0x4e8 }, + { 0x4ea, 0x4ea }, + { 0x4ec, 0x4ec }, + { 0x4ee, 0x4ee }, + { 0x4f0, 0x4f0 }, + { 0x4f2, 0x4f2 }, + { 0x4f4, 0x4f4 }, + { 0x4f6, 0x4f6 }, + { 0x4f8, 0x4f8 }, + { 0x4fa, 0x4fa }, + { 0x4fc, 0x4fc }, + { 0x4fe, 0x4fe }, + { 0x500, 0x500 }, + { 0x502, 0x502 }, + { 0x504, 0x504 }, + { 0x506, 0x506 }, + { 0x508, 0x508 }, + { 0x50a, 0x50a }, + { 0x50c, 0x50c }, + { 0x50e, 0x50e }, + { 0x510, 0x510 }, + { 0x512, 0x512 }, + { 0x514, 0x514 }, + { 0x516, 0x516 }, + { 0x518, 0x518 }, + { 0x51a, 0x51a }, + { 0x51c, 0x51c }, + { 0x51e, 0x51e }, + { 0x520, 0x520 }, + { 0x522, 0x522 }, + { 0x524, 0x524 }, + { 0x526, 0x526 }, + { 0x528, 0x528 }, + { 0x52a, 0x52a }, + { 0x52c, 0x52c }, + { 0x52e, 0x52e }, + { 0x531, 0x556 }, + { 0x10a0, 0x10c5 }, + { 0x10c7, 0x10c7 }, + { 0x10cd, 0x10cd }, + { 0x13a0, 0x13f5 }, + { 0x1c89, 0x1c89 }, + { 0x1c90, 0x1cba }, + { 0x1cbd, 0x1cbf }, + { 0x1e00, 0x1e00 }, + { 0x1e02, 0x1e02 }, + { 0x1e04, 0x1e04 }, + { 0x1e06, 0x1e06 }, + { 0x1e08, 0x1e08 }, + { 0x1e0a, 0x1e0a }, + { 0x1e0c, 0x1e0c }, + { 0x1e0e, 0x1e0e }, + { 0x1e10, 0x1e10 }, + { 0x1e12, 0x1e12 }, + { 0x1e14, 0x1e14 }, + { 0x1e16, 0x1e16 }, + { 0x1e18, 0x1e18 }, + { 0x1e1a, 0x1e1a }, + { 0x1e1c, 0x1e1c }, + { 0x1e1e, 0x1e1e }, + { 0x1e20, 0x1e20 }, + { 0x1e22, 0x1e22 }, + { 0x1e24, 0x1e24 }, + { 0x1e26, 0x1e26 }, + { 0x1e28, 0x1e28 }, + { 0x1e2a, 0x1e2a }, + { 0x1e2c, 0x1e2c }, + { 0x1e2e, 0x1e2e }, + { 0x1e30, 0x1e30 }, + { 0x1e32, 0x1e32 }, + { 0x1e34, 0x1e34 }, + { 0x1e36, 0x1e36 }, + { 0x1e38, 0x1e38 }, + { 0x1e3a, 0x1e3a }, + { 0x1e3c, 0x1e3c }, + { 0x1e3e, 0x1e3e }, + { 0x1e40, 0x1e40 }, + { 0x1e42, 0x1e42 }, + { 0x1e44, 0x1e44 }, + { 0x1e46, 0x1e46 }, + { 0x1e48, 0x1e48 }, + { 0x1e4a, 0x1e4a }, + { 0x1e4c, 0x1e4c }, + { 0x1e4e, 0x1e4e }, + { 0x1e50, 0x1e50 }, + { 0x1e52, 0x1e52 }, + { 0x1e54, 0x1e54 }, + { 0x1e56, 0x1e56 }, + { 0x1e58, 0x1e58 }, + { 0x1e5a, 0x1e5a }, + { 0x1e5c, 0x1e5c }, + { 0x1e5e, 0x1e5e }, + { 0x1e60, 0x1e60 }, + { 0x1e62, 0x1e62 }, + { 0x1e64, 0x1e64 }, + { 0x1e66, 0x1e66 }, + { 0x1e68, 0x1e68 }, + { 0x1e6a, 0x1e6a }, + { 0x1e6c, 0x1e6c }, + { 0x1e6e, 0x1e6e }, + { 0x1e70, 0x1e70 }, + { 0x1e72, 0x1e72 }, + { 0x1e74, 0x1e74 }, + { 0x1e76, 0x1e76 }, + { 0x1e78, 0x1e78 }, + { 0x1e7a, 0x1e7a }, + { 0x1e7c, 0x1e7c }, + { 0x1e7e, 0x1e7e }, + { 0x1e80, 0x1e80 }, + { 0x1e82, 0x1e82 }, + { 0x1e84, 0x1e84 }, + { 0x1e86, 0x1e86 }, + { 0x1e88, 0x1e88 }, + { 0x1e8a, 0x1e8a }, + { 0x1e8c, 0x1e8c }, + { 0x1e8e, 0x1e8e }, + { 0x1e90, 0x1e90 }, + { 0x1e92, 0x1e92 }, + { 0x1e94, 0x1e94 }, + { 0x1e9e, 0x1e9e }, + { 0x1ea0, 0x1ea0 }, + { 0x1ea2, 0x1ea2 }, + { 0x1ea4, 0x1ea4 }, + { 0x1ea6, 0x1ea6 }, + { 0x1ea8, 0x1ea8 }, + { 0x1eaa, 0x1eaa }, + { 0x1eac, 0x1eac }, + { 0x1eae, 0x1eae }, + { 0x1eb0, 0x1eb0 }, + { 0x1eb2, 0x1eb2 }, + { 0x1eb4, 0x1eb4 }, + { 0x1eb6, 0x1eb6 }, + { 0x1eb8, 0x1eb8 }, + { 0x1eba, 0x1eba }, + { 0x1ebc, 0x1ebc }, + { 0x1ebe, 0x1ebe }, + { 0x1ec0, 0x1ec0 }, + { 0x1ec2, 0x1ec2 }, + { 0x1ec4, 0x1ec4 }, + { 0x1ec6, 0x1ec6 }, + { 0x1ec8, 0x1ec8 }, + { 0x1eca, 0x1eca }, + { 0x1ecc, 0x1ecc }, + { 0x1ece, 0x1ece }, + { 0x1ed0, 0x1ed0 }, + { 0x1ed2, 0x1ed2 }, + { 0x1ed4, 0x1ed4 }, + { 0x1ed6, 0x1ed6 }, + { 0x1ed8, 0x1ed8 }, + { 0x1eda, 0x1eda }, + { 0x1edc, 0x1edc }, + { 0x1ede, 0x1ede }, + { 0x1ee0, 0x1ee0 }, + { 0x1ee2, 0x1ee2 }, + { 0x1ee4, 0x1ee4 }, + { 0x1ee6, 0x1ee6 }, + { 0x1ee8, 0x1ee8 }, + { 0x1eea, 0x1eea }, + { 0x1eec, 0x1eec }, + { 0x1eee, 0x1eee }, + { 0x1ef0, 0x1ef0 }, + { 0x1ef2, 0x1ef2 }, + { 0x1ef4, 0x1ef4 }, + { 0x1ef6, 0x1ef6 }, + { 0x1ef8, 0x1ef8 }, + { 0x1efa, 0x1efa }, + { 0x1efc, 0x1efc }, + { 0x1efe, 0x1efe }, + { 0x1f08, 0x1f0f }, + { 0x1f18, 0x1f1d }, + { 0x1f28, 0x1f2f }, + { 0x1f38, 0x1f3f }, + { 0x1f48, 0x1f4d }, + { 0x1f59, 0x1f59 }, + { 0x1f5b, 0x1f5b }, + { 0x1f5d, 0x1f5d }, + { 0x1f5f, 0x1f5f }, + { 0x1f68, 0x1f6f }, + { 0x1fb8, 0x1fbb }, + { 0x1fc8, 0x1fcb }, + { 0x1fd8, 0x1fdb }, + { 0x1fe8, 0x1fec }, + { 0x1ff8, 0x1ffb }, + { 0x2102, 0x2102 }, + { 0x2107, 0x2107 }, + { 0x210b, 0x210d }, + { 0x2110, 0x2112 }, + { 0x2115, 0x2115 }, + { 0x2119, 0x211d }, + { 0x2124, 0x2124 }, + { 0x2126, 0x2126 }, + { 0x2128, 0x2128 }, + { 0x212a, 0x212d }, + { 0x2130, 0x2133 }, + { 0x213e, 0x213f }, + { 0x2145, 0x2145 }, + { 0x2160, 0x216f }, + { 0x2183, 0x2183 }, + { 0x24b6, 0x24cf }, + { 0x2c00, 0x2c2f }, + { 0x2c60, 0x2c60 }, + { 0x2c62, 0x2c64 }, + { 0x2c67, 0x2c67 }, + { 0x2c69, 0x2c69 }, + { 0x2c6b, 0x2c6b }, + { 0x2c6d, 0x2c70 }, + { 0x2c72, 0x2c72 }, + { 0x2c75, 0x2c75 }, + { 0x2c7e, 0x2c80 }, + { 0x2c82, 0x2c82 }, + { 0x2c84, 0x2c84 }, + { 0x2c86, 0x2c86 }, + { 0x2c88, 0x2c88 }, + { 0x2c8a, 0x2c8a }, + { 0x2c8c, 0x2c8c }, + { 0x2c8e, 0x2c8e }, + { 0x2c90, 0x2c90 }, + { 0x2c92, 0x2c92 }, + { 0x2c94, 0x2c94 }, + { 0x2c96, 0x2c96 }, + { 0x2c98, 0x2c98 }, + { 0x2c9a, 0x2c9a }, + { 0x2c9c, 0x2c9c }, + { 0x2c9e, 0x2c9e }, + { 0x2ca0, 0x2ca0 }, + { 0x2ca2, 0x2ca2 }, + { 0x2ca4, 0x2ca4 }, + { 0x2ca6, 0x2ca6 }, + { 0x2ca8, 0x2ca8 }, + { 0x2caa, 0x2caa }, + { 0x2cac, 0x2cac }, + { 0x2cae, 0x2cae }, + { 0x2cb0, 0x2cb0 }, + { 0x2cb2, 0x2cb2 }, + { 0x2cb4, 0x2cb4 }, + { 0x2cb6, 0x2cb6 }, + { 0x2cb8, 0x2cb8 }, + { 0x2cba, 0x2cba }, + { 0x2cbc, 0x2cbc }, + { 0x2cbe, 0x2cbe }, + { 0x2cc0, 0x2cc0 }, + { 0x2cc2, 0x2cc2 }, + { 0x2cc4, 0x2cc4 }, + { 0x2cc6, 0x2cc6 }, + { 0x2cc8, 0x2cc8 }, + { 0x2cca, 0x2cca }, + { 0x2ccc, 0x2ccc }, + { 0x2cce, 0x2cce }, + { 0x2cd0, 0x2cd0 }, + { 0x2cd2, 0x2cd2 }, + { 0x2cd4, 0x2cd4 }, + { 0x2cd6, 0x2cd6 }, + { 0x2cd8, 0x2cd8 }, + { 0x2cda, 0x2cda }, + { 0x2cdc, 0x2cdc }, + { 0x2cde, 0x2cde }, + { 0x2ce0, 0x2ce0 }, + { 0x2ce2, 0x2ce2 }, + { 0x2ceb, 0x2ceb }, + { 0x2ced, 0x2ced }, + { 0x2cf2, 0x2cf2 }, + { 0xa640, 0xa640 }, + { 0xa642, 0xa642 }, + { 0xa644, 0xa644 }, + { 0xa646, 0xa646 }, + { 0xa648, 0xa648 }, + { 0xa64a, 0xa64a }, + { 0xa64c, 0xa64c }, + { 0xa64e, 0xa64e }, + { 0xa650, 0xa650 }, + { 0xa652, 0xa652 }, + { 0xa654, 0xa654 }, + { 0xa656, 0xa656 }, + { 0xa658, 0xa658 }, + { 0xa65a, 0xa65a }, + { 0xa65c, 0xa65c }, + { 0xa65e, 0xa65e }, + { 0xa660, 0xa660 }, + { 0xa662, 0xa662 }, + { 0xa664, 0xa664 }, + { 0xa666, 0xa666 }, + { 0xa668, 0xa668 }, + { 0xa66a, 0xa66a }, + { 0xa66c, 0xa66c }, + { 0xa680, 0xa680 }, + { 0xa682, 0xa682 }, + { 0xa684, 0xa684 }, + { 0xa686, 0xa686 }, + { 0xa688, 0xa688 }, + { 0xa68a, 0xa68a }, + { 0xa68c, 0xa68c }, + { 0xa68e, 0xa68e }, + { 0xa690, 0xa690 }, + { 0xa692, 0xa692 }, + { 0xa694, 0xa694 }, + { 0xa696, 0xa696 }, + { 0xa698, 0xa698 }, + { 0xa69a, 0xa69a }, + { 0xa722, 0xa722 }, + { 0xa724, 0xa724 }, + { 0xa726, 0xa726 }, + { 0xa728, 0xa728 }, + { 0xa72a, 0xa72a }, + { 0xa72c, 0xa72c }, + { 0xa72e, 0xa72e }, + { 0xa732, 0xa732 }, + { 0xa734, 0xa734 }, + { 0xa736, 0xa736 }, + { 0xa738, 0xa738 }, + { 0xa73a, 0xa73a }, + { 0xa73c, 0xa73c }, + { 0xa73e, 0xa73e }, + { 0xa740, 0xa740 }, + { 0xa742, 0xa742 }, + { 0xa744, 0xa744 }, + { 0xa746, 0xa746 }, + { 0xa748, 0xa748 }, + { 0xa74a, 0xa74a }, + { 0xa74c, 0xa74c }, + { 0xa74e, 0xa74e }, + { 0xa750, 0xa750 }, + { 0xa752, 0xa752 }, + { 0xa754, 0xa754 }, + { 0xa756, 0xa756 }, + { 0xa758, 0xa758 }, + { 0xa75a, 0xa75a }, + { 0xa75c, 0xa75c }, + { 0xa75e, 0xa75e }, + { 0xa760, 0xa760 }, + { 0xa762, 0xa762 }, + { 0xa764, 0xa764 }, + { 0xa766, 0xa766 }, + { 0xa768, 0xa768 }, + { 0xa76a, 0xa76a }, + { 0xa76c, 0xa76c }, + { 0xa76e, 0xa76e }, + { 0xa779, 0xa779 }, + { 0xa77b, 0xa77b }, + { 0xa77d, 0xa77e }, + { 0xa780, 0xa780 }, + { 0xa782, 0xa782 }, + { 0xa784, 0xa784 }, + { 0xa786, 0xa786 }, + { 0xa78b, 0xa78b }, + { 0xa78d, 0xa78d }, + { 0xa790, 0xa790 }, + { 0xa792, 0xa792 }, + { 0xa796, 0xa796 }, + { 0xa798, 0xa798 }, + { 0xa79a, 0xa79a }, + { 0xa79c, 0xa79c }, + { 0xa79e, 0xa79e }, + { 0xa7a0, 0xa7a0 }, + { 0xa7a2, 0xa7a2 }, + { 0xa7a4, 0xa7a4 }, + { 0xa7a6, 0xa7a6 }, + { 0xa7a8, 0xa7a8 }, + { 0xa7aa, 0xa7ae }, + { 0xa7b0, 0xa7b4 }, + { 0xa7b6, 0xa7b6 }, + { 0xa7b8, 0xa7b8 }, + { 0xa7ba, 0xa7ba }, + { 0xa7bc, 0xa7bc }, + { 0xa7be, 0xa7be }, + { 0xa7c0, 0xa7c0 }, + { 0xa7c2, 0xa7c2 }, + { 0xa7c4, 0xa7c7 }, + { 0xa7c9, 0xa7c9 }, + { 0xa7cb, 0xa7cc }, + { 0xa7d0, 0xa7d0 }, + { 0xa7d6, 0xa7d6 }, + { 0xa7d8, 0xa7d8 }, + { 0xa7da, 0xa7da }, + { 0xa7dc, 0xa7dc }, + { 0xa7f5, 0xa7f5 }, + { 0xff21, 0xff3a }, + { 0x10400, 0x10427 }, + { 0x104b0, 0x104d3 }, + { 0x10570, 0x1057a }, + { 0x1057c, 0x1058a }, + { 0x1058c, 0x10592 }, + { 0x10594, 0x10595 }, + { 0x10c80, 0x10cb2 }, + { 0x10d50, 0x10d65 }, + { 0x118a0, 0x118bf }, + { 0x16e40, 0x16e5f }, + { 0x1d400, 0x1d419 }, + { 0x1d434, 0x1d44d }, + { 0x1d468, 0x1d481 }, + { 0x1d49c, 0x1d49c }, + { 0x1d49e, 0x1d49f }, + { 0x1d4a2, 0x1d4a2 }, + { 0x1d4a5, 0x1d4a6 }, + { 0x1d4a9, 0x1d4ac }, + { 0x1d4ae, 0x1d4b5 }, + { 0x1d4d0, 0x1d4e9 }, + { 0x1d504, 0x1d505 }, + { 0x1d507, 0x1d50a }, + { 0x1d50d, 0x1d514 }, + { 0x1d516, 0x1d51c }, + { 0x1d538, 0x1d539 }, + { 0x1d53b, 0x1d53e }, + { 0x1d540, 0x1d544 }, + { 0x1d546, 0x1d546 }, + { 0x1d54a, 0x1d550 }, + { 0x1d56c, 0x1d585 }, + { 0x1d5a0, 0x1d5b9 }, + { 0x1d5d4, 0x1d5ed }, + { 0x1d608, 0x1d621 }, + { 0x1d63c, 0x1d655 }, + { 0x1d670, 0x1d689 }, + { 0x1d6a8, 0x1d6c0 }, + { 0x1d6e2, 0x1d6fa }, + { 0x1d71c, 0x1d734 }, + { 0x1d756, 0x1d76e }, + { 0x1d790, 0x1d7a8 }, + { 0x1d7ca, 0x1d7ca }, + { 0x1e900, 0x1e921 }, + { 0x1f130, 0x1f149 }, + { 0x1f150, 0x1f169 }, + { 0x1f170, 0x1f189 }, +}; + +constexpr inline CharRange lowercase_letter[] = { + { 0x61, 0x7a }, + { 0xaa, 0xaa }, + { 0xb5, 0xb5 }, + { 0xba, 0xba }, + { 0xdf, 0xf6 }, + { 0xf8, 0xff }, + { 0x101, 0x101 }, + { 0x103, 0x103 }, + { 0x105, 0x105 }, + { 0x107, 0x107 }, + { 0x109, 0x109 }, + { 0x10b, 0x10b }, + { 0x10d, 0x10d }, + { 0x10f, 0x10f }, + { 0x111, 0x111 }, + { 0x113, 0x113 }, + { 0x115, 0x115 }, + { 0x117, 0x117 }, + { 0x119, 0x119 }, + { 0x11b, 0x11b }, + { 0x11d, 0x11d }, + { 0x11f, 0x11f }, + { 0x121, 0x121 }, + { 0x123, 0x123 }, + { 0x125, 0x125 }, + { 0x127, 0x127 }, + { 0x129, 0x129 }, + { 0x12b, 0x12b }, + { 0x12d, 0x12d }, + { 0x12f, 0x12f }, + { 0x131, 0x131 }, + { 0x133, 0x133 }, + { 0x135, 0x135 }, + { 0x137, 0x138 }, + { 0x13a, 0x13a }, + { 0x13c, 0x13c }, + { 0x13e, 0x13e }, + { 0x140, 0x140 }, + { 0x142, 0x142 }, + { 0x144, 0x144 }, + { 0x146, 0x146 }, + { 0x148, 0x149 }, + { 0x14b, 0x14b }, + { 0x14d, 0x14d }, + { 0x14f, 0x14f }, + { 0x151, 0x151 }, + { 0x153, 0x153 }, + { 0x155, 0x155 }, + { 0x157, 0x157 }, + { 0x159, 0x159 }, + { 0x15b, 0x15b }, + { 0x15d, 0x15d }, + { 0x15f, 0x15f }, + { 0x161, 0x161 }, + { 0x163, 0x163 }, + { 0x165, 0x165 }, + { 0x167, 0x167 }, + { 0x169, 0x169 }, + { 0x16b, 0x16b }, + { 0x16d, 0x16d }, + { 0x16f, 0x16f }, + { 0x171, 0x171 }, + { 0x173, 0x173 }, + { 0x175, 0x175 }, + { 0x177, 0x177 }, + { 0x17a, 0x17a }, + { 0x17c, 0x17c }, + { 0x17e, 0x180 }, + { 0x183, 0x183 }, + { 0x185, 0x185 }, + { 0x188, 0x188 }, + { 0x18c, 0x18d }, + { 0x192, 0x192 }, + { 0x195, 0x195 }, + { 0x199, 0x19b }, + { 0x19e, 0x19e }, + { 0x1a1, 0x1a1 }, + { 0x1a3, 0x1a3 }, + { 0x1a5, 0x1a5 }, + { 0x1a8, 0x1a8 }, + { 0x1aa, 0x1ab }, + { 0x1ad, 0x1ad }, + { 0x1b0, 0x1b0 }, + { 0x1b4, 0x1b4 }, + { 0x1b6, 0x1b6 }, + { 0x1b9, 0x1ba }, + { 0x1bd, 0x1bf }, + { 0x1c6, 0x1c6 }, + { 0x1c9, 0x1c9 }, + { 0x1cc, 0x1cc }, + { 0x1ce, 0x1ce }, + { 0x1d0, 0x1d0 }, + { 0x1d2, 0x1d2 }, + { 0x1d4, 0x1d4 }, + { 0x1d6, 0x1d6 }, + { 0x1d8, 0x1d8 }, + { 0x1da, 0x1da }, + { 0x1dc, 0x1dd }, + { 0x1df, 0x1df }, + { 0x1e1, 0x1e1 }, + { 0x1e3, 0x1e3 }, + { 0x1e5, 0x1e5 }, + { 0x1e7, 0x1e7 }, + { 0x1e9, 0x1e9 }, + { 0x1eb, 0x1eb }, + { 0x1ed, 0x1ed }, + { 0x1ef, 0x1f0 }, + { 0x1f3, 0x1f3 }, + { 0x1f5, 0x1f5 }, + { 0x1f9, 0x1f9 }, + { 0x1fb, 0x1fb }, + { 0x1fd, 0x1fd }, + { 0x1ff, 0x1ff }, + { 0x201, 0x201 }, + { 0x203, 0x203 }, + { 0x205, 0x205 }, + { 0x207, 0x207 }, + { 0x209, 0x209 }, + { 0x20b, 0x20b }, + { 0x20d, 0x20d }, + { 0x20f, 0x20f }, + { 0x211, 0x211 }, + { 0x213, 0x213 }, + { 0x215, 0x215 }, + { 0x217, 0x217 }, + { 0x219, 0x219 }, + { 0x21b, 0x21b }, + { 0x21d, 0x21d }, + { 0x21f, 0x21f }, + { 0x221, 0x221 }, + { 0x223, 0x223 }, + { 0x225, 0x225 }, + { 0x227, 0x227 }, + { 0x229, 0x229 }, + { 0x22b, 0x22b }, + { 0x22d, 0x22d }, + { 0x22f, 0x22f }, + { 0x231, 0x231 }, + { 0x233, 0x239 }, + { 0x23c, 0x23c }, + { 0x23f, 0x240 }, + { 0x242, 0x242 }, + { 0x247, 0x247 }, + { 0x249, 0x249 }, + { 0x24b, 0x24b }, + { 0x24d, 0x24d }, + { 0x24f, 0x293 }, + { 0x295, 0x2b8 }, + { 0x2c0, 0x2c1 }, + { 0x2e0, 0x2e4 }, + { 0x345, 0x345 }, + { 0x371, 0x371 }, + { 0x373, 0x373 }, + { 0x377, 0x377 }, + { 0x37a, 0x37d }, + { 0x390, 0x390 }, + { 0x3ac, 0x3ce }, + { 0x3d0, 0x3d1 }, + { 0x3d5, 0x3d7 }, + { 0x3d9, 0x3d9 }, + { 0x3db, 0x3db }, + { 0x3dd, 0x3dd }, + { 0x3df, 0x3df }, + { 0x3e1, 0x3e1 }, + { 0x3e3, 0x3e3 }, + { 0x3e5, 0x3e5 }, + { 0x3e7, 0x3e7 }, + { 0x3e9, 0x3e9 }, + { 0x3eb, 0x3eb }, + { 0x3ed, 0x3ed }, + { 0x3ef, 0x3f3 }, + { 0x3f5, 0x3f5 }, + { 0x3f8, 0x3f8 }, + { 0x3fb, 0x3fc }, + { 0x430, 0x45f }, + { 0x461, 0x461 }, + { 0x463, 0x463 }, + { 0x465, 0x465 }, + { 0x467, 0x467 }, + { 0x469, 0x469 }, + { 0x46b, 0x46b }, + { 0x46d, 0x46d }, + { 0x46f, 0x46f }, + { 0x471, 0x471 }, + { 0x473, 0x473 }, + { 0x475, 0x475 }, + { 0x477, 0x477 }, + { 0x479, 0x479 }, + { 0x47b, 0x47b }, + { 0x47d, 0x47d }, + { 0x47f, 0x47f }, + { 0x481, 0x481 }, + { 0x48b, 0x48b }, + { 0x48d, 0x48d }, + { 0x48f, 0x48f }, + { 0x491, 0x491 }, + { 0x493, 0x493 }, + { 0x495, 0x495 }, + { 0x497, 0x497 }, + { 0x499, 0x499 }, + { 0x49b, 0x49b }, + { 0x49d, 0x49d }, + { 0x49f, 0x49f }, + { 0x4a1, 0x4a1 }, + { 0x4a3, 0x4a3 }, + { 0x4a5, 0x4a5 }, + { 0x4a7, 0x4a7 }, + { 0x4a9, 0x4a9 }, + { 0x4ab, 0x4ab }, + { 0x4ad, 0x4ad }, + { 0x4af, 0x4af }, + { 0x4b1, 0x4b1 }, + { 0x4b3, 0x4b3 }, + { 0x4b5, 0x4b5 }, + { 0x4b7, 0x4b7 }, + { 0x4b9, 0x4b9 }, + { 0x4bb, 0x4bb }, + { 0x4bd, 0x4bd }, + { 0x4bf, 0x4bf }, + { 0x4c2, 0x4c2 }, + { 0x4c4, 0x4c4 }, + { 0x4c6, 0x4c6 }, + { 0x4c8, 0x4c8 }, + { 0x4ca, 0x4ca }, + { 0x4cc, 0x4cc }, + { 0x4ce, 0x4cf }, + { 0x4d1, 0x4d1 }, + { 0x4d3, 0x4d3 }, + { 0x4d5, 0x4d5 }, + { 0x4d7, 0x4d7 }, + { 0x4d9, 0x4d9 }, + { 0x4db, 0x4db }, + { 0x4dd, 0x4dd }, + { 0x4df, 0x4df }, + { 0x4e1, 0x4e1 }, + { 0x4e3, 0x4e3 }, + { 0x4e5, 0x4e5 }, + { 0x4e7, 0x4e7 }, + { 0x4e9, 0x4e9 }, + { 0x4eb, 0x4eb }, + { 0x4ed, 0x4ed }, + { 0x4ef, 0x4ef }, + { 0x4f1, 0x4f1 }, + { 0x4f3, 0x4f3 }, + { 0x4f5, 0x4f5 }, + { 0x4f7, 0x4f7 }, + { 0x4f9, 0x4f9 }, + { 0x4fb, 0x4fb }, + { 0x4fd, 0x4fd }, + { 0x4ff, 0x4ff }, + { 0x501, 0x501 }, + { 0x503, 0x503 }, + { 0x505, 0x505 }, + { 0x507, 0x507 }, + { 0x509, 0x509 }, + { 0x50b, 0x50b }, + { 0x50d, 0x50d }, + { 0x50f, 0x50f }, + { 0x511, 0x511 }, + { 0x513, 0x513 }, + { 0x515, 0x515 }, + { 0x517, 0x517 }, + { 0x519, 0x519 }, + { 0x51b, 0x51b }, + { 0x51d, 0x51d }, + { 0x51f, 0x51f }, + { 0x521, 0x521 }, + { 0x523, 0x523 }, + { 0x525, 0x525 }, + { 0x527, 0x527 }, + { 0x529, 0x529 }, + { 0x52b, 0x52b }, + { 0x52d, 0x52d }, + { 0x52f, 0x52f }, + { 0x560, 0x588 }, + { 0x10d0, 0x10fa }, + { 0x10fc, 0x10ff }, + { 0x13f8, 0x13fd }, + { 0x1c80, 0x1c88 }, + { 0x1c8a, 0x1c8a }, + { 0x1d00, 0x1dbf }, + { 0x1e01, 0x1e01 }, + { 0x1e03, 0x1e03 }, + { 0x1e05, 0x1e05 }, + { 0x1e07, 0x1e07 }, + { 0x1e09, 0x1e09 }, + { 0x1e0b, 0x1e0b }, + { 0x1e0d, 0x1e0d }, + { 0x1e0f, 0x1e0f }, + { 0x1e11, 0x1e11 }, + { 0x1e13, 0x1e13 }, + { 0x1e15, 0x1e15 }, + { 0x1e17, 0x1e17 }, + { 0x1e19, 0x1e19 }, + { 0x1e1b, 0x1e1b }, + { 0x1e1d, 0x1e1d }, + { 0x1e1f, 0x1e1f }, + { 0x1e21, 0x1e21 }, + { 0x1e23, 0x1e23 }, + { 0x1e25, 0x1e25 }, + { 0x1e27, 0x1e27 }, + { 0x1e29, 0x1e29 }, + { 0x1e2b, 0x1e2b }, + { 0x1e2d, 0x1e2d }, + { 0x1e2f, 0x1e2f }, + { 0x1e31, 0x1e31 }, + { 0x1e33, 0x1e33 }, + { 0x1e35, 0x1e35 }, + { 0x1e37, 0x1e37 }, + { 0x1e39, 0x1e39 }, + { 0x1e3b, 0x1e3b }, + { 0x1e3d, 0x1e3d }, + { 0x1e3f, 0x1e3f }, + { 0x1e41, 0x1e41 }, + { 0x1e43, 0x1e43 }, + { 0x1e45, 0x1e45 }, + { 0x1e47, 0x1e47 }, + { 0x1e49, 0x1e49 }, + { 0x1e4b, 0x1e4b }, + { 0x1e4d, 0x1e4d }, + { 0x1e4f, 0x1e4f }, + { 0x1e51, 0x1e51 }, + { 0x1e53, 0x1e53 }, + { 0x1e55, 0x1e55 }, + { 0x1e57, 0x1e57 }, + { 0x1e59, 0x1e59 }, + { 0x1e5b, 0x1e5b }, + { 0x1e5d, 0x1e5d }, + { 0x1e5f, 0x1e5f }, + { 0x1e61, 0x1e61 }, + { 0x1e63, 0x1e63 }, + { 0x1e65, 0x1e65 }, + { 0x1e67, 0x1e67 }, + { 0x1e69, 0x1e69 }, + { 0x1e6b, 0x1e6b }, + { 0x1e6d, 0x1e6d }, + { 0x1e6f, 0x1e6f }, + { 0x1e71, 0x1e71 }, + { 0x1e73, 0x1e73 }, + { 0x1e75, 0x1e75 }, + { 0x1e77, 0x1e77 }, + { 0x1e79, 0x1e79 }, + { 0x1e7b, 0x1e7b }, + { 0x1e7d, 0x1e7d }, + { 0x1e7f, 0x1e7f }, + { 0x1e81, 0x1e81 }, + { 0x1e83, 0x1e83 }, + { 0x1e85, 0x1e85 }, + { 0x1e87, 0x1e87 }, + { 0x1e89, 0x1e89 }, + { 0x1e8b, 0x1e8b }, + { 0x1e8d, 0x1e8d }, + { 0x1e8f, 0x1e8f }, + { 0x1e91, 0x1e91 }, + { 0x1e93, 0x1e93 }, + { 0x1e95, 0x1e9d }, + { 0x1e9f, 0x1e9f }, + { 0x1ea1, 0x1ea1 }, + { 0x1ea3, 0x1ea3 }, + { 0x1ea5, 0x1ea5 }, + { 0x1ea7, 0x1ea7 }, + { 0x1ea9, 0x1ea9 }, + { 0x1eab, 0x1eab }, + { 0x1ead, 0x1ead }, + { 0x1eaf, 0x1eaf }, + { 0x1eb1, 0x1eb1 }, + { 0x1eb3, 0x1eb3 }, + { 0x1eb5, 0x1eb5 }, + { 0x1eb7, 0x1eb7 }, + { 0x1eb9, 0x1eb9 }, + { 0x1ebb, 0x1ebb }, + { 0x1ebd, 0x1ebd }, + { 0x1ebf, 0x1ebf }, + { 0x1ec1, 0x1ec1 }, + { 0x1ec3, 0x1ec3 }, + { 0x1ec5, 0x1ec5 }, + { 0x1ec7, 0x1ec7 }, + { 0x1ec9, 0x1ec9 }, + { 0x1ecb, 0x1ecb }, + { 0x1ecd, 0x1ecd }, + { 0x1ecf, 0x1ecf }, + { 0x1ed1, 0x1ed1 }, + { 0x1ed3, 0x1ed3 }, + { 0x1ed5, 0x1ed5 }, + { 0x1ed7, 0x1ed7 }, + { 0x1ed9, 0x1ed9 }, + { 0x1edb, 0x1edb }, + { 0x1edd, 0x1edd }, + { 0x1edf, 0x1edf }, + { 0x1ee1, 0x1ee1 }, + { 0x1ee3, 0x1ee3 }, + { 0x1ee5, 0x1ee5 }, + { 0x1ee7, 0x1ee7 }, + { 0x1ee9, 0x1ee9 }, + { 0x1eeb, 0x1eeb }, + { 0x1eed, 0x1eed }, + { 0x1eef, 0x1eef }, + { 0x1ef1, 0x1ef1 }, + { 0x1ef3, 0x1ef3 }, + { 0x1ef5, 0x1ef5 }, + { 0x1ef7, 0x1ef7 }, + { 0x1ef9, 0x1ef9 }, + { 0x1efb, 0x1efb }, + { 0x1efd, 0x1efd }, + { 0x1eff, 0x1f07 }, + { 0x1f10, 0x1f15 }, + { 0x1f20, 0x1f27 }, + { 0x1f30, 0x1f37 }, + { 0x1f40, 0x1f45 }, + { 0x1f50, 0x1f57 }, + { 0x1f60, 0x1f67 }, + { 0x1f70, 0x1f7d }, + { 0x1f80, 0x1f87 }, + { 0x1f90, 0x1f97 }, + { 0x1fa0, 0x1fa7 }, + { 0x1fb0, 0x1fb4 }, + { 0x1fb6, 0x1fb7 }, + { 0x1fbe, 0x1fbe }, + { 0x1fc2, 0x1fc4 }, + { 0x1fc6, 0x1fc7 }, + { 0x1fd0, 0x1fd3 }, + { 0x1fd6, 0x1fd7 }, + { 0x1fe0, 0x1fe7 }, + { 0x1ff2, 0x1ff4 }, + { 0x1ff6, 0x1ff7 }, + { 0x2071, 0x2071 }, + { 0x207f, 0x207f }, + { 0x2090, 0x209c }, + { 0x210a, 0x210a }, + { 0x210e, 0x210f }, + { 0x2113, 0x2113 }, + { 0x212f, 0x212f }, + { 0x2134, 0x2134 }, + { 0x2139, 0x2139 }, + { 0x213c, 0x213d }, + { 0x2146, 0x2149 }, + { 0x214e, 0x214e }, + { 0x2170, 0x217f }, + { 0x2184, 0x2184 }, + { 0x24d0, 0x24e9 }, + { 0x2c30, 0x2c5f }, + { 0x2c61, 0x2c61 }, + { 0x2c65, 0x2c66 }, + { 0x2c68, 0x2c68 }, + { 0x2c6a, 0x2c6a }, + { 0x2c6c, 0x2c6c }, + { 0x2c71, 0x2c71 }, + { 0x2c73, 0x2c74 }, + { 0x2c76, 0x2c7d }, + { 0x2c81, 0x2c81 }, + { 0x2c83, 0x2c83 }, + { 0x2c85, 0x2c85 }, + { 0x2c87, 0x2c87 }, + { 0x2c89, 0x2c89 }, + { 0x2c8b, 0x2c8b }, + { 0x2c8d, 0x2c8d }, + { 0x2c8f, 0x2c8f }, + { 0x2c91, 0x2c91 }, + { 0x2c93, 0x2c93 }, + { 0x2c95, 0x2c95 }, + { 0x2c97, 0x2c97 }, + { 0x2c99, 0x2c99 }, + { 0x2c9b, 0x2c9b }, + { 0x2c9d, 0x2c9d }, + { 0x2c9f, 0x2c9f }, + { 0x2ca1, 0x2ca1 }, + { 0x2ca3, 0x2ca3 }, + { 0x2ca5, 0x2ca5 }, + { 0x2ca7, 0x2ca7 }, + { 0x2ca9, 0x2ca9 }, + { 0x2cab, 0x2cab }, + { 0x2cad, 0x2cad }, + { 0x2caf, 0x2caf }, + { 0x2cb1, 0x2cb1 }, + { 0x2cb3, 0x2cb3 }, + { 0x2cb5, 0x2cb5 }, + { 0x2cb7, 0x2cb7 }, + { 0x2cb9, 0x2cb9 }, + { 0x2cbb, 0x2cbb }, + { 0x2cbd, 0x2cbd }, + { 0x2cbf, 0x2cbf }, + { 0x2cc1, 0x2cc1 }, + { 0x2cc3, 0x2cc3 }, + { 0x2cc5, 0x2cc5 }, + { 0x2cc7, 0x2cc7 }, + { 0x2cc9, 0x2cc9 }, + { 0x2ccb, 0x2ccb }, + { 0x2ccd, 0x2ccd }, + { 0x2ccf, 0x2ccf }, + { 0x2cd1, 0x2cd1 }, + { 0x2cd3, 0x2cd3 }, + { 0x2cd5, 0x2cd5 }, + { 0x2cd7, 0x2cd7 }, + { 0x2cd9, 0x2cd9 }, + { 0x2cdb, 0x2cdb }, + { 0x2cdd, 0x2cdd }, + { 0x2cdf, 0x2cdf }, + { 0x2ce1, 0x2ce1 }, + { 0x2ce3, 0x2ce4 }, + { 0x2cec, 0x2cec }, + { 0x2cee, 0x2cee }, + { 0x2cf3, 0x2cf3 }, + { 0x2d00, 0x2d25 }, + { 0x2d27, 0x2d27 }, + { 0x2d2d, 0x2d2d }, + { 0xa641, 0xa641 }, + { 0xa643, 0xa643 }, + { 0xa645, 0xa645 }, + { 0xa647, 0xa647 }, + { 0xa649, 0xa649 }, + { 0xa64b, 0xa64b }, + { 0xa64d, 0xa64d }, + { 0xa64f, 0xa64f }, + { 0xa651, 0xa651 }, + { 0xa653, 0xa653 }, + { 0xa655, 0xa655 }, + { 0xa657, 0xa657 }, + { 0xa659, 0xa659 }, + { 0xa65b, 0xa65b }, + { 0xa65d, 0xa65d }, + { 0xa65f, 0xa65f }, + { 0xa661, 0xa661 }, + { 0xa663, 0xa663 }, + { 0xa665, 0xa665 }, + { 0xa667, 0xa667 }, + { 0xa669, 0xa669 }, + { 0xa66b, 0xa66b }, + { 0xa66d, 0xa66d }, + { 0xa681, 0xa681 }, + { 0xa683, 0xa683 }, + { 0xa685, 0xa685 }, + { 0xa687, 0xa687 }, + { 0xa689, 0xa689 }, + { 0xa68b, 0xa68b }, + { 0xa68d, 0xa68d }, + { 0xa68f, 0xa68f }, + { 0xa691, 0xa691 }, + { 0xa693, 0xa693 }, + { 0xa695, 0xa695 }, + { 0xa697, 0xa697 }, + { 0xa699, 0xa699 }, + { 0xa69b, 0xa69d }, + { 0xa723, 0xa723 }, + { 0xa725, 0xa725 }, + { 0xa727, 0xa727 }, + { 0xa729, 0xa729 }, + { 0xa72b, 0xa72b }, + { 0xa72d, 0xa72d }, + { 0xa72f, 0xa731 }, + { 0xa733, 0xa733 }, + { 0xa735, 0xa735 }, + { 0xa737, 0xa737 }, + { 0xa739, 0xa739 }, + { 0xa73b, 0xa73b }, + { 0xa73d, 0xa73d }, + { 0xa73f, 0xa73f }, + { 0xa741, 0xa741 }, + { 0xa743, 0xa743 }, + { 0xa745, 0xa745 }, + { 0xa747, 0xa747 }, + { 0xa749, 0xa749 }, + { 0xa74b, 0xa74b }, + { 0xa74d, 0xa74d }, + { 0xa74f, 0xa74f }, + { 0xa751, 0xa751 }, + { 0xa753, 0xa753 }, + { 0xa755, 0xa755 }, + { 0xa757, 0xa757 }, + { 0xa759, 0xa759 }, + { 0xa75b, 0xa75b }, + { 0xa75d, 0xa75d }, + { 0xa75f, 0xa75f }, + { 0xa761, 0xa761 }, + { 0xa763, 0xa763 }, + { 0xa765, 0xa765 }, + { 0xa767, 0xa767 }, + { 0xa769, 0xa769 }, + { 0xa76b, 0xa76b }, + { 0xa76d, 0xa76d }, + { 0xa76f, 0xa778 }, + { 0xa77a, 0xa77a }, + { 0xa77c, 0xa77c }, + { 0xa77f, 0xa77f }, + { 0xa781, 0xa781 }, + { 0xa783, 0xa783 }, + { 0xa785, 0xa785 }, + { 0xa787, 0xa787 }, + { 0xa78c, 0xa78c }, + { 0xa78e, 0xa78e }, + { 0xa791, 0xa791 }, + { 0xa793, 0xa795 }, + { 0xa797, 0xa797 }, + { 0xa799, 0xa799 }, + { 0xa79b, 0xa79b }, + { 0xa79d, 0xa79d }, + { 0xa79f, 0xa79f }, + { 0xa7a1, 0xa7a1 }, + { 0xa7a3, 0xa7a3 }, + { 0xa7a5, 0xa7a5 }, + { 0xa7a7, 0xa7a7 }, + { 0xa7a9, 0xa7a9 }, + { 0xa7af, 0xa7af }, + { 0xa7b5, 0xa7b5 }, + { 0xa7b7, 0xa7b7 }, + { 0xa7b9, 0xa7b9 }, + { 0xa7bb, 0xa7bb }, + { 0xa7bd, 0xa7bd }, + { 0xa7bf, 0xa7bf }, + { 0xa7c1, 0xa7c1 }, + { 0xa7c3, 0xa7c3 }, + { 0xa7c8, 0xa7c8 }, + { 0xa7ca, 0xa7ca }, + { 0xa7cd, 0xa7cd }, + { 0xa7d1, 0xa7d1 }, + { 0xa7d3, 0xa7d3 }, + { 0xa7d5, 0xa7d5 }, + { 0xa7d7, 0xa7d7 }, + { 0xa7d9, 0xa7d9 }, + { 0xa7db, 0xa7db }, + { 0xa7f2, 0xa7f4 }, + { 0xa7f6, 0xa7f6 }, + { 0xa7f8, 0xa7fa }, + { 0xab30, 0xab5a }, + { 0xab5c, 0xab69 }, + { 0xab70, 0xabbf }, + { 0xfb00, 0xfb06 }, + { 0xfb13, 0xfb17 }, + { 0xff41, 0xff5a }, + { 0x10428, 0x1044f }, + { 0x104d8, 0x104fb }, + { 0x10597, 0x105a1 }, + { 0x105a3, 0x105b1 }, + { 0x105b3, 0x105b9 }, + { 0x105bb, 0x105bc }, + { 0x10780, 0x10780 }, + { 0x10783, 0x10785 }, + { 0x10787, 0x107b0 }, + { 0x107b2, 0x107ba }, + { 0x10cc0, 0x10cf2 }, + { 0x10d70, 0x10d85 }, + { 0x118c0, 0x118df }, + { 0x16e60, 0x16e7f }, + { 0x1d41a, 0x1d433 }, + { 0x1d44e, 0x1d454 }, + { 0x1d456, 0x1d467 }, + { 0x1d482, 0x1d49b }, + { 0x1d4b6, 0x1d4b9 }, + { 0x1d4bb, 0x1d4bb }, + { 0x1d4bd, 0x1d4c3 }, + { 0x1d4c5, 0x1d4cf }, + { 0x1d4ea, 0x1d503 }, + { 0x1d51e, 0x1d537 }, + { 0x1d552, 0x1d56b }, + { 0x1d586, 0x1d59f }, + { 0x1d5ba, 0x1d5d3 }, + { 0x1d5ee, 0x1d607 }, + { 0x1d622, 0x1d63b }, + { 0x1d656, 0x1d66f }, + { 0x1d68a, 0x1d6a5 }, + { 0x1d6c2, 0x1d6da }, + { 0x1d6dc, 0x1d6e1 }, + { 0x1d6fc, 0x1d714 }, + { 0x1d716, 0x1d71b }, + { 0x1d736, 0x1d74e }, + { 0x1d750, 0x1d755 }, + { 0x1d770, 0x1d788 }, + { 0x1d78a, 0x1d78f }, + { 0x1d7aa, 0x1d7c2 }, + { 0x1d7c4, 0x1d7c9 }, + { 0x1d7cb, 0x1d7cb }, + { 0x1df00, 0x1df09 }, + { 0x1df0b, 0x1df1e }, + { 0x1df25, 0x1df2a }, + { 0x1e030, 0x1e06d }, + { 0x1e922, 0x1e943 }, +}; + +constexpr inline CharRange unicode_letter[] = { + { 0x41, 0x5a }, + { 0x61, 0x7a }, + { 0xaa, 0xaa }, + { 0xb5, 0xb5 }, + { 0xba, 0xba }, + { 0xc0, 0xd6 }, + { 0xd8, 0xf6 }, + { 0xf8, 0x2c1 }, + { 0x2c6, 0x2d1 }, + { 0x2e0, 0x2e4 }, + { 0x2ec, 0x2ec }, + { 0x2ee, 0x2ee }, + { 0x345, 0x345 }, + { 0x363, 0x374 }, + { 0x376, 0x377 }, + { 0x37a, 0x37d }, + { 0x37f, 0x37f }, + { 0x386, 0x386 }, + { 0x388, 0x38a }, + { 0x38c, 0x38c }, + { 0x38e, 0x3a1 }, + { 0x3a3, 0x3f5 }, + { 0x3f7, 0x481 }, + { 0x48a, 0x52f }, + { 0x531, 0x556 }, + { 0x559, 0x559 }, + { 0x560, 0x588 }, + { 0x5b0, 0x5bd }, + { 0x5bf, 0x5bf }, + { 0x5c1, 0x5c2 }, + { 0x5c4, 0x5c5 }, + { 0x5c7, 0x5c7 }, + { 0x5d0, 0x5ea }, + { 0x5ef, 0x5f2 }, + { 0x610, 0x61a }, + { 0x620, 0x657 }, + { 0x659, 0x65f }, + { 0x66e, 0x6d3 }, + { 0x6d5, 0x6dc }, + { 0x6e1, 0x6e8 }, + { 0x6ed, 0x6ef }, + { 0x6fa, 0x6fc }, + { 0x6ff, 0x6ff }, + { 0x710, 0x73f }, + { 0x74d, 0x7b1 }, + { 0x7ca, 0x7ea }, + { 0x7f4, 0x7f5 }, + { 0x7fa, 0x7fa }, + { 0x800, 0x817 }, + { 0x81a, 0x82c }, + { 0x840, 0x858 }, + { 0x860, 0x86a }, + { 0x870, 0x887 }, + { 0x889, 0x88e }, + { 0x897, 0x897 }, + { 0x8a0, 0x8c9 }, + { 0x8d4, 0x8df }, + { 0x8e3, 0x8e9 }, + { 0x8f0, 0x93b }, + { 0x93d, 0x94c }, + { 0x94e, 0x950 }, + { 0x955, 0x963 }, + { 0x971, 0x983 }, + { 0x985, 0x98c }, + { 0x98f, 0x990 }, + { 0x993, 0x9a8 }, + { 0x9aa, 0x9b0 }, + { 0x9b2, 0x9b2 }, + { 0x9b6, 0x9b9 }, + { 0x9bd, 0x9c4 }, + { 0x9c7, 0x9c8 }, + { 0x9cb, 0x9cc }, + { 0x9ce, 0x9ce }, + { 0x9d7, 0x9d7 }, + { 0x9dc, 0x9dd }, + { 0x9df, 0x9e3 }, + { 0x9f0, 0x9f1 }, + { 0x9fc, 0x9fc }, + { 0xa01, 0xa03 }, + { 0xa05, 0xa0a }, + { 0xa0f, 0xa10 }, + { 0xa13, 0xa28 }, + { 0xa2a, 0xa30 }, + { 0xa32, 0xa33 }, + { 0xa35, 0xa36 }, + { 0xa38, 0xa39 }, + { 0xa3e, 0xa42 }, + { 0xa47, 0xa48 }, + { 0xa4b, 0xa4c }, + { 0xa51, 0xa51 }, + { 0xa59, 0xa5c }, + { 0xa5e, 0xa5e }, + { 0xa70, 0xa75 }, + { 0xa81, 0xa83 }, + { 0xa85, 0xa8d }, + { 0xa8f, 0xa91 }, + { 0xa93, 0xaa8 }, + { 0xaaa, 0xab0 }, + { 0xab2, 0xab3 }, + { 0xab5, 0xab9 }, + { 0xabd, 0xac5 }, + { 0xac7, 0xac9 }, + { 0xacb, 0xacc }, + { 0xad0, 0xad0 }, + { 0xae0, 0xae3 }, + { 0xaf9, 0xafc }, + { 0xb01, 0xb03 }, + { 0xb05, 0xb0c }, + { 0xb0f, 0xb10 }, + { 0xb13, 0xb28 }, + { 0xb2a, 0xb30 }, + { 0xb32, 0xb33 }, + { 0xb35, 0xb39 }, + { 0xb3d, 0xb44 }, + { 0xb47, 0xb48 }, + { 0xb4b, 0xb4c }, + { 0xb56, 0xb57 }, + { 0xb5c, 0xb5d }, + { 0xb5f, 0xb63 }, + { 0xb71, 0xb71 }, + { 0xb82, 0xb83 }, + { 0xb85, 0xb8a }, + { 0xb8e, 0xb90 }, + { 0xb92, 0xb95 }, + { 0xb99, 0xb9a }, + { 0xb9c, 0xb9c }, + { 0xb9e, 0xb9f }, + { 0xba3, 0xba4 }, + { 0xba8, 0xbaa }, + { 0xbae, 0xbb9 }, + { 0xbbe, 0xbc2 }, + { 0xbc6, 0xbc8 }, + { 0xbca, 0xbcc }, + { 0xbd0, 0xbd0 }, + { 0xbd7, 0xbd7 }, + { 0xc00, 0xc0c }, + { 0xc0e, 0xc10 }, + { 0xc12, 0xc28 }, + { 0xc2a, 0xc39 }, + { 0xc3d, 0xc44 }, + { 0xc46, 0xc48 }, + { 0xc4a, 0xc4c }, + { 0xc55, 0xc56 }, + { 0xc58, 0xc5a }, + { 0xc5d, 0xc5d }, + { 0xc60, 0xc63 }, + { 0xc80, 0xc83 }, + { 0xc85, 0xc8c }, + { 0xc8e, 0xc90 }, + { 0xc92, 0xca8 }, + { 0xcaa, 0xcb3 }, + { 0xcb5, 0xcb9 }, + { 0xcbd, 0xcc4 }, + { 0xcc6, 0xcc8 }, + { 0xcca, 0xccc }, + { 0xcd5, 0xcd6 }, + { 0xcdd, 0xcde }, + { 0xce0, 0xce3 }, + { 0xcf1, 0xcf3 }, + { 0xd00, 0xd0c }, + { 0xd0e, 0xd10 }, + { 0xd12, 0xd3a }, + { 0xd3d, 0xd44 }, + { 0xd46, 0xd48 }, + { 0xd4a, 0xd4c }, + { 0xd4e, 0xd4e }, + { 0xd54, 0xd57 }, + { 0xd5f, 0xd63 }, + { 0xd7a, 0xd7f }, + { 0xd81, 0xd83 }, + { 0xd85, 0xd96 }, + { 0xd9a, 0xdb1 }, + { 0xdb3, 0xdbb }, + { 0xdbd, 0xdbd }, + { 0xdc0, 0xdc6 }, + { 0xdcf, 0xdd4 }, + { 0xdd6, 0xdd6 }, + { 0xdd8, 0xddf }, + { 0xdf2, 0xdf3 }, + { 0xe01, 0xe3a }, + { 0xe40, 0xe46 }, + { 0xe4d, 0xe4d }, + { 0xe81, 0xe82 }, + { 0xe84, 0xe84 }, + { 0xe86, 0xe8a }, + { 0xe8c, 0xea3 }, + { 0xea5, 0xea5 }, + { 0xea7, 0xeb9 }, + { 0xebb, 0xebd }, + { 0xec0, 0xec4 }, + { 0xec6, 0xec6 }, + { 0xecd, 0xecd }, + { 0xedc, 0xedf }, + { 0xf00, 0xf00 }, + { 0xf40, 0xf47 }, + { 0xf49, 0xf6c }, + { 0xf71, 0xf83 }, + { 0xf88, 0xf97 }, + { 0xf99, 0xfbc }, + { 0x1000, 0x1036 }, + { 0x1038, 0x1038 }, + { 0x103b, 0x103f }, + { 0x1050, 0x108f }, + { 0x109a, 0x109d }, + { 0x10a0, 0x10c5 }, + { 0x10c7, 0x10c7 }, + { 0x10cd, 0x10cd }, + { 0x10d0, 0x10fa }, + { 0x10fc, 0x1248 }, + { 0x124a, 0x124d }, + { 0x1250, 0x1256 }, + { 0x1258, 0x1258 }, + { 0x125a, 0x125d }, + { 0x1260, 0x1288 }, + { 0x128a, 0x128d }, + { 0x1290, 0x12b0 }, + { 0x12b2, 0x12b5 }, + { 0x12b8, 0x12be }, + { 0x12c0, 0x12c0 }, + { 0x12c2, 0x12c5 }, + { 0x12c8, 0x12d6 }, + { 0x12d8, 0x1310 }, + { 0x1312, 0x1315 }, + { 0x1318, 0x135a }, + { 0x1380, 0x138f }, + { 0x13a0, 0x13f5 }, + { 0x13f8, 0x13fd }, + { 0x1401, 0x166c }, + { 0x166f, 0x167f }, + { 0x1681, 0x169a }, + { 0x16a0, 0x16ea }, + { 0x16ee, 0x16f8 }, + { 0x1700, 0x1713 }, + { 0x171f, 0x1733 }, + { 0x1740, 0x1753 }, + { 0x1760, 0x176c }, + { 0x176e, 0x1770 }, + { 0x1772, 0x1773 }, + { 0x1780, 0x17b3 }, + { 0x17b6, 0x17c8 }, + { 0x17d7, 0x17d7 }, + { 0x17dc, 0x17dc }, + { 0x1820, 0x1878 }, + { 0x1880, 0x18aa }, + { 0x18b0, 0x18f5 }, + { 0x1900, 0x191e }, + { 0x1920, 0x192b }, + { 0x1930, 0x1938 }, + { 0x1950, 0x196d }, + { 0x1970, 0x1974 }, + { 0x1980, 0x19ab }, + { 0x19b0, 0x19c9 }, + { 0x1a00, 0x1a1b }, + { 0x1a20, 0x1a5e }, + { 0x1a61, 0x1a74 }, + { 0x1aa7, 0x1aa7 }, + { 0x1abf, 0x1ac0 }, + { 0x1acc, 0x1ace }, + { 0x1b00, 0x1b33 }, + { 0x1b35, 0x1b43 }, + { 0x1b45, 0x1b4c }, + { 0x1b80, 0x1ba9 }, + { 0x1bac, 0x1baf }, + { 0x1bba, 0x1be5 }, + { 0x1be7, 0x1bf1 }, + { 0x1c00, 0x1c36 }, + { 0x1c4d, 0x1c4f }, + { 0x1c5a, 0x1c7d }, + { 0x1c80, 0x1c8a }, + { 0x1c90, 0x1cba }, + { 0x1cbd, 0x1cbf }, + { 0x1ce9, 0x1cec }, + { 0x1cee, 0x1cf3 }, + { 0x1cf5, 0x1cf6 }, + { 0x1cfa, 0x1cfa }, + { 0x1d00, 0x1dbf }, + { 0x1dd3, 0x1df4 }, + { 0x1e00, 0x1f15 }, + { 0x1f18, 0x1f1d }, + { 0x1f20, 0x1f45 }, + { 0x1f48, 0x1f4d }, + { 0x1f50, 0x1f57 }, + { 0x1f59, 0x1f59 }, + { 0x1f5b, 0x1f5b }, + { 0x1f5d, 0x1f5d }, + { 0x1f5f, 0x1f7d }, + { 0x1f80, 0x1fb4 }, + { 0x1fb6, 0x1fbc }, + { 0x1fbe, 0x1fbe }, + { 0x1fc2, 0x1fc4 }, + { 0x1fc6, 0x1fcc }, + { 0x1fd0, 0x1fd3 }, + { 0x1fd6, 0x1fdb }, + { 0x1fe0, 0x1fec }, + { 0x1ff2, 0x1ff4 }, + { 0x1ff6, 0x1ffc }, + { 0x2071, 0x2071 }, + { 0x207f, 0x207f }, + { 0x2090, 0x209c }, + { 0x2102, 0x2102 }, + { 0x2107, 0x2107 }, + { 0x210a, 0x2113 }, + { 0x2115, 0x2115 }, + { 0x2119, 0x211d }, + { 0x2124, 0x2124 }, + { 0x2126, 0x2126 }, + { 0x2128, 0x2128 }, + { 0x212a, 0x212d }, + { 0x212f, 0x2139 }, + { 0x213c, 0x213f }, + { 0x2145, 0x2149 }, + { 0x214e, 0x214e }, + { 0x2160, 0x2188 }, + { 0x24b6, 0x24e9 }, + { 0x2c00, 0x2ce4 }, + { 0x2ceb, 0x2cee }, + { 0x2cf2, 0x2cf3 }, + { 0x2d00, 0x2d25 }, + { 0x2d27, 0x2d27 }, + { 0x2d2d, 0x2d2d }, + { 0x2d30, 0x2d67 }, + { 0x2d6f, 0x2d6f }, + { 0x2d80, 0x2d96 }, + { 0x2da0, 0x2da6 }, + { 0x2da8, 0x2dae }, + { 0x2db0, 0x2db6 }, + { 0x2db8, 0x2dbe }, + { 0x2dc0, 0x2dc6 }, + { 0x2dc8, 0x2dce }, + { 0x2dd0, 0x2dd6 }, + { 0x2dd8, 0x2dde }, + { 0x2de0, 0x2dff }, + { 0x2e2f, 0x2e2f }, + { 0x3005, 0x3007 }, + { 0x3021, 0x3029 }, + { 0x3031, 0x3035 }, + { 0x3038, 0x303c }, + { 0x3041, 0x3096 }, + { 0x309d, 0x309f }, + { 0x30a1, 0x30fa }, + { 0x30fc, 0x30ff }, + { 0x3105, 0x312f }, + { 0x3131, 0x318e }, + { 0x31a0, 0x31bf }, + { 0x31f0, 0x31ff }, + { 0x3400, 0x4dbf }, + { 0x4e00, 0xa48c }, + { 0xa4d0, 0xa4fd }, + { 0xa500, 0xa60c }, + { 0xa610, 0xa61f }, + { 0xa62a, 0xa62b }, + { 0xa640, 0xa66e }, + { 0xa674, 0xa67b }, + { 0xa67f, 0xa6ef }, + { 0xa717, 0xa71f }, + { 0xa722, 0xa788 }, + { 0xa78b, 0xa7cd }, + { 0xa7d0, 0xa7d1 }, + { 0xa7d3, 0xa7d3 }, + { 0xa7d5, 0xa7dc }, + { 0xa7f2, 0xa805 }, + { 0xa807, 0xa827 }, + { 0xa840, 0xa873 }, + { 0xa880, 0xa8c3 }, + { 0xa8c5, 0xa8c5 }, + { 0xa8f2, 0xa8f7 }, + { 0xa8fb, 0xa8fb }, + { 0xa8fd, 0xa8ff }, + { 0xa90a, 0xa92a }, + { 0xa930, 0xa952 }, + { 0xa960, 0xa97c }, + { 0xa980, 0xa9b2 }, + { 0xa9b4, 0xa9bf }, + { 0xa9cf, 0xa9cf }, + { 0xa9e0, 0xa9ef }, + { 0xa9fa, 0xa9fe }, + { 0xaa00, 0xaa36 }, + { 0xaa40, 0xaa4d }, + { 0xaa60, 0xaa76 }, + { 0xaa7a, 0xaabe }, + { 0xaac0, 0xaac0 }, + { 0xaac2, 0xaac2 }, + { 0xaadb, 0xaadd }, + { 0xaae0, 0xaaef }, + { 0xaaf2, 0xaaf5 }, + { 0xab01, 0xab06 }, + { 0xab09, 0xab0e }, + { 0xab11, 0xab16 }, + { 0xab20, 0xab26 }, + { 0xab28, 0xab2e }, + { 0xab30, 0xab5a }, + { 0xab5c, 0xab69 }, + { 0xab70, 0xabea }, + { 0xac00, 0xd7a3 }, + { 0xd7b0, 0xd7c6 }, + { 0xd7cb, 0xd7fb }, + { 0xf900, 0xfa6d }, + { 0xfa70, 0xfad9 }, + { 0xfb00, 0xfb06 }, + { 0xfb13, 0xfb17 }, + { 0xfb1d, 0xfb28 }, + { 0xfb2a, 0xfb36 }, + { 0xfb38, 0xfb3c }, + { 0xfb3e, 0xfb3e }, + { 0xfb40, 0xfb41 }, + { 0xfb43, 0xfb44 }, + { 0xfb46, 0xfbb1 }, + { 0xfbd3, 0xfd3d }, + { 0xfd50, 0xfd8f }, + { 0xfd92, 0xfdc7 }, + { 0xfdf0, 0xfdfb }, + { 0xfe70, 0xfe74 }, + { 0xfe76, 0xfefc }, + { 0xff21, 0xff3a }, + { 0xff41, 0xff5a }, + { 0xff66, 0xffbe }, + { 0xffc2, 0xffc7 }, + { 0xffca, 0xffcf }, + { 0xffd2, 0xffd7 }, + { 0xffda, 0xffdc }, + { 0x10000, 0x1000b }, + { 0x1000d, 0x10026 }, + { 0x10028, 0x1003a }, + { 0x1003c, 0x1003d }, + { 0x1003f, 0x1004d }, + { 0x10050, 0x1005d }, + { 0x10080, 0x100fa }, + { 0x10140, 0x10174 }, + { 0x10280, 0x1029c }, + { 0x102a0, 0x102d0 }, + { 0x10300, 0x1031f }, + { 0x1032d, 0x1034a }, + { 0x10350, 0x1037a }, + { 0x10380, 0x1039d }, + { 0x103a0, 0x103c3 }, + { 0x103c8, 0x103cf }, + { 0x103d1, 0x103d5 }, + { 0x10400, 0x1049d }, + { 0x104b0, 0x104d3 }, + { 0x104d8, 0x104fb }, + { 0x10500, 0x10527 }, + { 0x10530, 0x10563 }, + { 0x10570, 0x1057a }, + { 0x1057c, 0x1058a }, + { 0x1058c, 0x10592 }, + { 0x10594, 0x10595 }, + { 0x10597, 0x105a1 }, + { 0x105a3, 0x105b1 }, + { 0x105b3, 0x105b9 }, + { 0x105bb, 0x105bc }, + { 0x105c0, 0x105f3 }, + { 0x10600, 0x10736 }, + { 0x10740, 0x10755 }, + { 0x10760, 0x10767 }, + { 0x10780, 0x10785 }, + { 0x10787, 0x107b0 }, + { 0x107b2, 0x107ba }, + { 0x10800, 0x10805 }, + { 0x10808, 0x10808 }, + { 0x1080a, 0x10835 }, + { 0x10837, 0x10838 }, + { 0x1083c, 0x1083c }, + { 0x1083f, 0x10855 }, + { 0x10860, 0x10876 }, + { 0x10880, 0x1089e }, + { 0x108e0, 0x108f2 }, + { 0x108f4, 0x108f5 }, + { 0x10900, 0x10915 }, + { 0x10920, 0x10939 }, + { 0x10980, 0x109b7 }, + { 0x109be, 0x109bf }, + { 0x10a00, 0x10a03 }, + { 0x10a05, 0x10a06 }, + { 0x10a0c, 0x10a13 }, + { 0x10a15, 0x10a17 }, + { 0x10a19, 0x10a35 }, + { 0x10a60, 0x10a7c }, + { 0x10a80, 0x10a9c }, + { 0x10ac0, 0x10ac7 }, + { 0x10ac9, 0x10ae4 }, + { 0x10b00, 0x10b35 }, + { 0x10b40, 0x10b55 }, + { 0x10b60, 0x10b72 }, + { 0x10b80, 0x10b91 }, + { 0x10c00, 0x10c48 }, + { 0x10c80, 0x10cb2 }, + { 0x10cc0, 0x10cf2 }, + { 0x10d00, 0x10d27 }, + { 0x10d4a, 0x10d65 }, + { 0x10d69, 0x10d69 }, + { 0x10d6f, 0x10d85 }, + { 0x10e80, 0x10ea9 }, + { 0x10eab, 0x10eac }, + { 0x10eb0, 0x10eb1 }, + { 0x10ec2, 0x10ec4 }, + { 0x10efc, 0x10efc }, + { 0x10f00, 0x10f1c }, + { 0x10f27, 0x10f27 }, + { 0x10f30, 0x10f45 }, + { 0x10f70, 0x10f81 }, + { 0x10fb0, 0x10fc4 }, + { 0x10fe0, 0x10ff6 }, + { 0x11000, 0x11045 }, + { 0x11071, 0x11075 }, + { 0x11080, 0x110b8 }, + { 0x110c2, 0x110c2 }, + { 0x110d0, 0x110e8 }, + { 0x11100, 0x11132 }, + { 0x11144, 0x11147 }, + { 0x11150, 0x11172 }, + { 0x11176, 0x11176 }, + { 0x11180, 0x111bf }, + { 0x111c1, 0x111c4 }, + { 0x111ce, 0x111cf }, + { 0x111da, 0x111da }, + { 0x111dc, 0x111dc }, + { 0x11200, 0x11211 }, + { 0x11213, 0x11234 }, + { 0x11237, 0x11237 }, + { 0x1123e, 0x11241 }, + { 0x11280, 0x11286 }, + { 0x11288, 0x11288 }, + { 0x1128a, 0x1128d }, + { 0x1128f, 0x1129d }, + { 0x1129f, 0x112a8 }, + { 0x112b0, 0x112e8 }, + { 0x11300, 0x11303 }, + { 0x11305, 0x1130c }, + { 0x1130f, 0x11310 }, + { 0x11313, 0x11328 }, + { 0x1132a, 0x11330 }, + { 0x11332, 0x11333 }, + { 0x11335, 0x11339 }, + { 0x1133d, 0x11344 }, + { 0x11347, 0x11348 }, + { 0x1134b, 0x1134c }, + { 0x11350, 0x11350 }, + { 0x11357, 0x11357 }, + { 0x1135d, 0x11363 }, + { 0x11380, 0x11389 }, + { 0x1138b, 0x1138b }, + { 0x1138e, 0x1138e }, + { 0x11390, 0x113b5 }, + { 0x113b7, 0x113c0 }, + { 0x113c2, 0x113c2 }, + { 0x113c5, 0x113c5 }, + { 0x113c7, 0x113ca }, + { 0x113cc, 0x113cd }, + { 0x113d1, 0x113d1 }, + { 0x113d3, 0x113d3 }, + { 0x11400, 0x11441 }, + { 0x11443, 0x11445 }, + { 0x11447, 0x1144a }, + { 0x1145f, 0x11461 }, + { 0x11480, 0x114c1 }, + { 0x114c4, 0x114c5 }, + { 0x114c7, 0x114c7 }, + { 0x11580, 0x115b5 }, + { 0x115b8, 0x115be }, + { 0x115d8, 0x115dd }, + { 0x11600, 0x1163e }, + { 0x11640, 0x11640 }, + { 0x11644, 0x11644 }, + { 0x11680, 0x116b5 }, + { 0x116b8, 0x116b8 }, + { 0x11700, 0x1171a }, + { 0x1171d, 0x1172a }, + { 0x11740, 0x11746 }, + { 0x11800, 0x11838 }, + { 0x118a0, 0x118df }, + { 0x118ff, 0x11906 }, + { 0x11909, 0x11909 }, + { 0x1190c, 0x11913 }, + { 0x11915, 0x11916 }, + { 0x11918, 0x11935 }, + { 0x11937, 0x11938 }, + { 0x1193b, 0x1193c }, + { 0x1193f, 0x11942 }, + { 0x119a0, 0x119a7 }, + { 0x119aa, 0x119d7 }, + { 0x119da, 0x119df }, + { 0x119e1, 0x119e1 }, + { 0x119e3, 0x119e4 }, + { 0x11a00, 0x11a32 }, + { 0x11a35, 0x11a3e }, + { 0x11a50, 0x11a97 }, + { 0x11a9d, 0x11a9d }, + { 0x11ab0, 0x11af8 }, + { 0x11bc0, 0x11be0 }, + { 0x11c00, 0x11c08 }, + { 0x11c0a, 0x11c36 }, + { 0x11c38, 0x11c3e }, + { 0x11c40, 0x11c40 }, + { 0x11c72, 0x11c8f }, + { 0x11c92, 0x11ca7 }, + { 0x11ca9, 0x11cb6 }, + { 0x11d00, 0x11d06 }, + { 0x11d08, 0x11d09 }, + { 0x11d0b, 0x11d36 }, + { 0x11d3a, 0x11d3a }, + { 0x11d3c, 0x11d3d }, + { 0x11d3f, 0x11d41 }, + { 0x11d43, 0x11d43 }, + { 0x11d46, 0x11d47 }, + { 0x11d60, 0x11d65 }, + { 0x11d67, 0x11d68 }, + { 0x11d6a, 0x11d8e }, + { 0x11d90, 0x11d91 }, + { 0x11d93, 0x11d96 }, + { 0x11d98, 0x11d98 }, + { 0x11ee0, 0x11ef6 }, + { 0x11f00, 0x11f10 }, + { 0x11f12, 0x11f3a }, + { 0x11f3e, 0x11f40 }, + { 0x11fb0, 0x11fb0 }, + { 0x12000, 0x12399 }, + { 0x12400, 0x1246e }, + { 0x12480, 0x12543 }, + { 0x12f90, 0x12ff0 }, + { 0x13000, 0x1342f }, + { 0x13441, 0x13446 }, + { 0x13460, 0x143fa }, + { 0x14400, 0x14646 }, + { 0x16100, 0x1612e }, + { 0x16800, 0x16a38 }, + { 0x16a40, 0x16a5e }, + { 0x16a70, 0x16abe }, + { 0x16ad0, 0x16aed }, + { 0x16b00, 0x16b2f }, + { 0x16b40, 0x16b43 }, + { 0x16b63, 0x16b77 }, + { 0x16b7d, 0x16b8f }, + { 0x16d40, 0x16d6c }, + { 0x16e40, 0x16e7f }, + { 0x16f00, 0x16f4a }, + { 0x16f4f, 0x16f87 }, + { 0x16f8f, 0x16f9f }, + { 0x16fe0, 0x16fe1 }, + { 0x16fe3, 0x16fe3 }, + { 0x16ff0, 0x16ff1 }, + { 0x17000, 0x187f7 }, + { 0x18800, 0x18cd5 }, + { 0x18cff, 0x18d08 }, + { 0x1aff0, 0x1aff3 }, + { 0x1aff5, 0x1affb }, + { 0x1affd, 0x1affe }, + { 0x1b000, 0x1b122 }, + { 0x1b132, 0x1b132 }, + { 0x1b150, 0x1b152 }, + { 0x1b155, 0x1b155 }, + { 0x1b164, 0x1b167 }, + { 0x1b170, 0x1b2fb }, + { 0x1bc00, 0x1bc6a }, + { 0x1bc70, 0x1bc7c }, + { 0x1bc80, 0x1bc88 }, + { 0x1bc90, 0x1bc99 }, + { 0x1bc9e, 0x1bc9e }, + { 0x1d400, 0x1d454 }, + { 0x1d456, 0x1d49c }, + { 0x1d49e, 0x1d49f }, + { 0x1d4a2, 0x1d4a2 }, + { 0x1d4a5, 0x1d4a6 }, + { 0x1d4a9, 0x1d4ac }, + { 0x1d4ae, 0x1d4b9 }, + { 0x1d4bb, 0x1d4bb }, + { 0x1d4bd, 0x1d4c3 }, + { 0x1d4c5, 0x1d505 }, + { 0x1d507, 0x1d50a }, + { 0x1d50d, 0x1d514 }, + { 0x1d516, 0x1d51c }, + { 0x1d51e, 0x1d539 }, + { 0x1d53b, 0x1d53e }, + { 0x1d540, 0x1d544 }, + { 0x1d546, 0x1d546 }, + { 0x1d54a, 0x1d550 }, + { 0x1d552, 0x1d6a5 }, + { 0x1d6a8, 0x1d6c0 }, + { 0x1d6c2, 0x1d6da }, + { 0x1d6dc, 0x1d6fa }, + { 0x1d6fc, 0x1d714 }, + { 0x1d716, 0x1d734 }, + { 0x1d736, 0x1d74e }, + { 0x1d750, 0x1d76e }, + { 0x1d770, 0x1d788 }, + { 0x1d78a, 0x1d7a8 }, + { 0x1d7aa, 0x1d7c2 }, + { 0x1d7c4, 0x1d7cb }, + { 0x1df00, 0x1df1e }, + { 0x1df25, 0x1df2a }, + { 0x1e000, 0x1e006 }, + { 0x1e008, 0x1e018 }, + { 0x1e01b, 0x1e021 }, + { 0x1e023, 0x1e024 }, + { 0x1e026, 0x1e02a }, + { 0x1e030, 0x1e06d }, + { 0x1e08f, 0x1e08f }, + { 0x1e100, 0x1e12c }, + { 0x1e137, 0x1e13d }, + { 0x1e14e, 0x1e14e }, + { 0x1e290, 0x1e2ad }, + { 0x1e2c0, 0x1e2eb }, + { 0x1e4d0, 0x1e4eb }, + { 0x1e5d0, 0x1e5ed }, + { 0x1e5f0, 0x1e5f0 }, + { 0x1e7e0, 0x1e7e6 }, + { 0x1e7e8, 0x1e7eb }, + { 0x1e7ed, 0x1e7ee }, + { 0x1e7f0, 0x1e7fe }, + { 0x1e800, 0x1e8c4 }, + { 0x1e900, 0x1e943 }, + { 0x1e947, 0x1e947 }, + { 0x1e94b, 0x1e94b }, + { 0x1ee00, 0x1ee03 }, + { 0x1ee05, 0x1ee1f }, + { 0x1ee21, 0x1ee22 }, + { 0x1ee24, 0x1ee24 }, + { 0x1ee27, 0x1ee27 }, + { 0x1ee29, 0x1ee32 }, + { 0x1ee34, 0x1ee37 }, + { 0x1ee39, 0x1ee39 }, + { 0x1ee3b, 0x1ee3b }, + { 0x1ee42, 0x1ee42 }, + { 0x1ee47, 0x1ee47 }, + { 0x1ee49, 0x1ee49 }, + { 0x1ee4b, 0x1ee4b }, + { 0x1ee4d, 0x1ee4f }, + { 0x1ee51, 0x1ee52 }, + { 0x1ee54, 0x1ee54 }, + { 0x1ee57, 0x1ee57 }, + { 0x1ee59, 0x1ee59 }, + { 0x1ee5b, 0x1ee5b }, + { 0x1ee5d, 0x1ee5d }, + { 0x1ee5f, 0x1ee5f }, + { 0x1ee61, 0x1ee62 }, + { 0x1ee64, 0x1ee64 }, + { 0x1ee67, 0x1ee6a }, + { 0x1ee6c, 0x1ee72 }, + { 0x1ee74, 0x1ee77 }, + { 0x1ee79, 0x1ee7c }, + { 0x1ee7e, 0x1ee7e }, + { 0x1ee80, 0x1ee89 }, + { 0x1ee8b, 0x1ee9b }, + { 0x1eea1, 0x1eea3 }, + { 0x1eea5, 0x1eea9 }, + { 0x1eeab, 0x1eebb }, + { 0x1f130, 0x1f149 }, + { 0x1f150, 0x1f169 }, + { 0x1f170, 0x1f189 }, + { 0x20000, 0x2a6df }, + { 0x2a700, 0x2b739 }, + { 0x2b740, 0x2b81d }, + { 0x2b820, 0x2cea1 }, + { 0x2ceb0, 0x2ebe0 }, + { 0x2ebf0, 0x2ee5d }, + { 0x2f800, 0x2fa1d }, + { 0x30000, 0x3134a }, + { 0x31350, 0x323af }, +}; + +} // namespace godot diff --git a/include/godot_cpp/variant/char_string.hpp b/include/godot_cpp/variant/char_string.hpp index 8f485f2b..445964a0 100644 --- a/include/godot_cpp/variant/char_string.hpp +++ b/include/godot_cpp/variant/char_string.hpp @@ -30,8 +30,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ -#ifndef GODOT_CHAR_STRING_HPP -#define GODOT_CHAR_STRING_HPP +#pragma once #include @@ -140,5 +139,3 @@ typedef CharStringT Char32String; typedef CharStringT CharWideString; } // namespace godot - -#endif // GODOT_CHAR_STRING_HPP diff --git a/include/godot_cpp/variant/char_utils.hpp b/include/godot_cpp/variant/char_utils.hpp index 985ce6d4..19c9d7bb 100644 --- a/include/godot_cpp/variant/char_utils.hpp +++ b/include/godot_cpp/variant/char_utils.hpp @@ -30,63 +30,107 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ -#ifndef GODOT_CHAR_UTILS_HPP -#define GODOT_CHAR_UTILS_HPP +#pragma once + +#include "char_range.inc.hpp" + +namespace godot { + +#define BSEARCH_CHAR_RANGE(m_array) \ + int low = 0; \ + int high = sizeof(m_array) / sizeof(m_array[0]) - 1; \ + int middle = (low + high) / 2; \ + \ + while (low <= high) { \ + if (p_char < m_array[middle].start) { \ + high = middle - 1; \ + } else if (p_char > m_array[middle].end) { \ + low = middle + 1; \ + } else { \ + return true; \ + } \ + \ + middle = (low + high) / 2; \ + } \ + \ + return false + +constexpr bool is_unicode_identifier_start(char32_t p_char) { + BSEARCH_CHAR_RANGE(xid_start); +} + +constexpr bool is_unicode_identifier_continue(char32_t p_char) { + BSEARCH_CHAR_RANGE(xid_continue); +} + +constexpr bool is_unicode_upper_case(char32_t p_char) { + BSEARCH_CHAR_RANGE(uppercase_letter); +} + +constexpr bool is_unicode_lower_case(char32_t p_char) { + BSEARCH_CHAR_RANGE(lowercase_letter); +} + +constexpr bool is_unicode_letter(char32_t p_char) { + BSEARCH_CHAR_RANGE(unicode_letter); +} + +#undef BSEARCH_CHAR_RANGE -static _FORCE_INLINE_ bool is_ascii_upper_case(char32_t c) { - return (c >= 'A' && c <= 'Z'); +constexpr bool is_ascii_upper_case(char32_t p_char) { + return (p_char >= 'A' && p_char <= 'Z'); } -static _FORCE_INLINE_ bool is_ascii_lower_case(char32_t c) { - return (c >= 'a' && c <= 'z'); +constexpr bool is_ascii_lower_case(char32_t p_char) { + return (p_char >= 'a' && p_char <= 'z'); } -static _FORCE_INLINE_ bool is_digit(char32_t c) { - return (c >= '0' && c <= '9'); +constexpr bool is_digit(char32_t p_char) { + return (p_char >= '0' && p_char <= '9'); } -static _FORCE_INLINE_ bool is_hex_digit(char32_t c) { - return (is_digit(c) || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F')); +constexpr bool is_hex_digit(char32_t p_char) { + return (is_digit(p_char) || (p_char >= 'a' && p_char <= 'f') || (p_char >= 'A' && p_char <= 'F')); } -static _FORCE_INLINE_ bool is_binary_digit(char32_t c) { - return (c == '0' || c == '1'); +constexpr bool is_binary_digit(char32_t p_char) { + return (p_char == '0' || p_char == '1'); } -static _FORCE_INLINE_ bool is_ascii_char(char32_t c) { - return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'); +constexpr bool is_ascii_alphabet_char(char32_t p_char) { + return (p_char >= 'a' && p_char <= 'z') || (p_char >= 'A' && p_char <= 'Z'); } -static _FORCE_INLINE_ bool is_ascii_alphanumeric_char(char32_t c) { - return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9'); +constexpr bool is_ascii_alphanumeric_char(char32_t p_char) { + return (p_char >= 'a' && p_char <= 'z') || (p_char >= 'A' && p_char <= 'Z') || (p_char >= '0' && p_char <= '9'); } -static _FORCE_INLINE_ bool is_ascii_identifier_char(char32_t c) { - return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '_'; +constexpr bool is_ascii_identifier_char(char32_t p_char) { + return (p_char >= 'a' && p_char <= 'z') || (p_char >= 'A' && p_char <= 'Z') || (p_char >= '0' && p_char <= '9') || p_char == '_'; } -static _FORCE_INLINE_ bool is_symbol(char32_t c) { - return c != '_' && ((c >= '!' && c <= '/') || (c >= ':' && c <= '@') || (c >= '[' && c <= '`') || (c >= '{' && c <= '~') || c == '\t' || c == ' '); +constexpr bool is_symbol(char32_t p_char) { + return p_char != '_' && ((p_char >= '!' && p_char <= '/') || (p_char >= ':' && p_char <= '@') || (p_char >= '[' && p_char <= '`') || (p_char >= '{' && p_char <= '~') || p_char == '\t' || p_char == ' '); } -static _FORCE_INLINE_ bool is_control(char32_t p_char) { +constexpr bool is_control(char32_t p_char) { return (p_char <= 0x001f) || (p_char >= 0x007f && p_char <= 0x009f); } -static _FORCE_INLINE_ bool is_whitespace(char32_t p_char) { - return (p_char == ' ') || (p_char == 0x00a0) || (p_char == 0x1680) || (p_char >= 0x2000 && p_char <= 0x200a) || (p_char == 0x202f) || (p_char == 0x205f) || (p_char == 0x3000) || (p_char == 0x2028) || (p_char == 0x2029) || (p_char >= 0x0009 && p_char <= 0x000d) || (p_char == 0x0085); +constexpr bool is_whitespace(char32_t p_char) { + return (p_char == ' ') || (p_char == 0x00a0) || (p_char == 0x1680) || (p_char >= 0x2000 && p_char <= 0x200b) || (p_char == 0x202f) || (p_char == 0x205f) || (p_char == 0x3000) || (p_char == 0x2028) || (p_char == 0x2029) || (p_char >= 0x0009 && p_char <= 0x000d) || (p_char == 0x0085); } -static _FORCE_INLINE_ bool is_linebreak(char32_t p_char) { +constexpr bool is_linebreak(char32_t p_char) { return (p_char >= 0x000a && p_char <= 0x000d) || (p_char == 0x0085) || (p_char == 0x2028) || (p_char == 0x2029); } -static _FORCE_INLINE_ bool is_punct(char32_t p_char) { +constexpr bool is_punct(char32_t p_char) { return (p_char >= ' ' && p_char <= '/') || (p_char >= ':' && p_char <= '@') || (p_char >= '[' && p_char <= '^') || (p_char == '`') || (p_char >= '{' && p_char <= '~') || (p_char >= 0x2000 && p_char <= 0x206f) || (p_char >= 0x3000 && p_char <= 0x303f); } -static _FORCE_INLINE_ bool is_underscore(char32_t p_char) { +constexpr bool is_underscore(char32_t p_char) { return (p_char == '_'); } -#endif // GODOT_CHAR_UTILS_HPP +} // namespace godot diff --git a/include/godot_cpp/variant/color.hpp b/include/godot_cpp/variant/color.hpp index 016eeaae..b13e418b 100644 --- a/include/godot_cpp/variant/color.hpp +++ b/include/godot_cpp/variant/color.hpp @@ -30,8 +30,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ -#ifndef GODOT_COLOR_HPP -#define GODOT_COLOR_HPP +#pragma once #include @@ -105,12 +104,10 @@ struct [[nodiscard]] Color { _FORCE_INLINE_ Color lerp(const Color &p_to, float p_weight) const { Color res = *this; - - res.r += (p_weight * (p_to.r - r)); - res.g += (p_weight * (p_to.g - g)); - res.b += (p_weight * (p_to.b - b)); - res.a += (p_weight * (p_to.a - a)); - + res.r = Math::lerp(res.r, p_to.r, p_weight); + res.g = Math::lerp(res.g, p_to.g, p_weight); + res.b = Math::lerp(res.b, p_to.b, p_weight); + res.a = Math::lerp(res.a, p_to.a, p_weight); return res; } @@ -131,33 +128,46 @@ struct [[nodiscard]] Color { } _FORCE_INLINE_ uint32_t to_rgbe9995() const { - const float pow2to9 = 512.0f; - const float B = 15.0f; - const float N = 9.0f; - - float sharedexp = 65408.000f; // Result of: ((pow2to9 - 1.0f) / pow2to9) * powf(2.0f, 31.0f - 15.0f) - - float cRed = MAX(0.0f, MIN(sharedexp, r)); - float cGreen = MAX(0.0f, MIN(sharedexp, g)); - float cBlue = MAX(0.0f, MIN(sharedexp, b)); - - float cMax = MAX(cRed, MAX(cGreen, cBlue)); - - float expp = MAX(-B - 1.0f, floor(Math::log(cMax) / (real_t)Math_LN2)) + 1.0f + B; - - float sMax = (float)floor((cMax / Math::pow(2.0f, expp - B - N)) + 0.5f); - - float exps = expp + 1.0f; - - if (0.0f <= sMax && sMax < pow2to9) { - exps = expp; - } - - float sRed = Math::floor((cRed / pow(2.0f, exps - B - N)) + 0.5f); - float sGreen = Math::floor((cGreen / pow(2.0f, exps - B - N)) + 0.5f); - float sBlue = Math::floor((cBlue / pow(2.0f, exps - B - N)) + 0.5f); - - return (uint32_t(Math::fast_ftoi(sRed)) & 0x1FF) | ((uint32_t(Math::fast_ftoi(sGreen)) & 0x1FF) << 9) | ((uint32_t(Math::fast_ftoi(sBlue)) & 0x1FF) << 18) | ((uint32_t(Math::fast_ftoi(exps)) & 0x1F) << 27); + // https://github.com/microsoft/DirectX-Graphics-Samples/blob/v10.0.19041.0/MiniEngine/Core/Color.cpp + static const float kMaxVal = float(0x1FF << 7); + static const float kMinVal = float(1.f / (1 << 16)); + + // Clamp RGB to [0, 1.FF*2^16] + const float _r = CLAMP(r, 0.0f, kMaxVal); + const float _g = CLAMP(g, 0.0f, kMaxVal); + const float _b = CLAMP(b, 0.0f, kMaxVal); + + // Compute the maximum channel, no less than 1.0*2^-15 + const float MaxChannel = MAX(MAX(_r, _g), MAX(_b, kMinVal)); + + // Take the exponent of the maximum channel (rounding up the 9th bit) and + // add 15 to it. When added to the channels, it causes the implicit '1.0' + // bit and the first 8 mantissa bits to be shifted down to the low 9 bits + // of the mantissa, rounding the truncated bits. + union { + float f; + uint32_t i; + } R, G, B, E; + + E.f = MaxChannel; + E.i += 0x07804000; // Add 15 to the exponent and 0x4000 to the mantissa + E.i &= 0x7F800000; // Zero the mantissa + + // This shifts the 9-bit values we need into the lowest bits, rounding as + // needed. Note that if the channel has a smaller exponent than the max + // channel, it will shift even more. This is intentional. + R.f = _r + E.f; + G.f = _g + E.f; + B.f = _b + E.f; + + // Convert the Bias to the correct exponent in the upper 5 bits. + E.i <<= 4; + E.i += 0x10000000; + + // Combine the fields. RGB floats have unwanted data in the upper 9 + // bits. Only red needs to mask them off because green and blue shift + // it out to the left. + return E.i | (B.i << 18U) | (G.i << 9U) | (R.i & 511U); } _FORCE_INLINE_ Color blend(const Color &p_over) const { @@ -176,16 +186,16 @@ struct [[nodiscard]] Color { _FORCE_INLINE_ Color srgb_to_linear() const { return Color( - r < 0.04045f ? r * (1.0f / 12.92f) : Math::pow((r + 0.055f) * (float)(1.0 / (1.0 + 0.055)), 2.4f), - g < 0.04045f ? g * (1.0f / 12.92f) : Math::pow((g + 0.055f) * (float)(1.0 / (1.0 + 0.055)), 2.4f), - b < 0.04045f ? b * (1.0f / 12.92f) : Math::pow((b + 0.055f) * (float)(1.0 / (1.0 + 0.055)), 2.4f), + r < 0.04045f ? r * (1.0f / 12.92f) : Math::pow(float((r + 0.055) * (1.0 / (1.0 + 0.055))), 2.4f), + g < 0.04045f ? g * (1.0f / 12.92f) : Math::pow(float((g + 0.055) * (1.0 / (1.0 + 0.055))), 2.4f), + b < 0.04045f ? b * (1.0f / 12.92f) : Math::pow(float((b + 0.055) * (1.0 / (1.0 + 0.055))), 2.4f), a); } _FORCE_INLINE_ Color linear_to_srgb() const { return Color( - r < 0.0031308f ? 12.92f * r : (1.0f + 0.055f) * Math::pow(r, 1.0f / 2.4f) - 0.055f, - g < 0.0031308f ? 12.92f * g : (1.0f + 0.055f) * Math::pow(g, 1.0f / 2.4f) - 0.055f, - b < 0.0031308f ? 12.92f * b : (1.0f + 0.055f) * Math::pow(b, 1.0f / 2.4f) - 0.055f, a); + r < 0.0031308f ? 12.92f * r : (1.0 + 0.055) * Math::pow(r, 1.0f / 2.4f) - 0.055, + g < 0.0031308f ? 12.92f * g : (1.0 + 0.055) * Math::pow(g, 1.0f / 2.4f) - 0.055, + b < 0.0031308f ? 12.92f * b : (1.0 + 0.055) * Math::pow(b, 1.0f / 2.4f) - 0.055, a); } static Color hex(uint32_t p_hex); @@ -201,6 +211,7 @@ struct [[nodiscard]] Color { static Color from_string(const String &p_string, const Color &p_default); static Color from_hsv(float p_h, float p_s, float p_v, float p_alpha = 1.0f); static Color from_rgbe9995(uint32_t p_rgbe); + static Color from_rgba8(int64_t p_r8, int64_t p_g8, int64_t p_b8, int64_t p_a8 = 255); _FORCE_INLINE_ bool operator<(const Color &p_color) const; // Used in set keys. operator String() const; @@ -287,5 +298,3 @@ _FORCE_INLINE_ Color operator*(float p_scalar, const Color &p_color) { } } // namespace godot - -#endif // GODOT_COLOR_HPP diff --git a/include/godot_cpp/variant/color_names.inc.hpp b/include/godot_cpp/variant/color_names.inc.hpp index 5b8efa2a..ed61a2f0 100644 --- a/include/godot_cpp/variant/color_names.inc.hpp +++ b/include/godot_cpp/variant/color_names.inc.hpp @@ -30,8 +30,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ -#ifndef GODOT_COLOR_NAMES_INC_HPP -#define GODOT_COLOR_NAMES_INC_HPP +#pragma once namespace godot { @@ -190,9 +189,6 @@ static NamedColor named_colors[] = { { "WHITE_SMOKE", Color::hex(0xF5F5F5FF) }, { "YELLOW", Color::hex(0xFFFF00FF) }, { "YELLOW_GREEN", Color::hex(0x9ACD32FF) }, - { nullptr, Color() }, }; } // namespace godot - -#endif // GODOT_COLOR_NAMES_INC_HPP diff --git a/include/godot_cpp/variant/plane.hpp b/include/godot_cpp/variant/plane.hpp index 4236f5c8..a8f39006 100644 --- a/include/godot_cpp/variant/plane.hpp +++ b/include/godot_cpp/variant/plane.hpp @@ -30,8 +30,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ -#ifndef GODOT_PLANE_HPP -#define GODOT_PLANE_HPP +#pragma once #include #include @@ -52,7 +51,7 @@ struct [[nodiscard]] Plane { /* Plane-Point operations */ - _FORCE_INLINE_ Vector3 center() const { return normal * d; } + _FORCE_INLINE_ Vector3 get_center() const { return normal * d; } Vector3 get_any_perpendicular_normal() const; _FORCE_INLINE_ bool is_point_over(const Vector3 &p_point) const; ///< Point is over plane @@ -139,5 +138,3 @@ bool Plane::operator!=(const Plane &p_plane) const { } } // namespace godot - -#endif // GODOT_PLANE_HPP diff --git a/include/godot_cpp/variant/projection.hpp b/include/godot_cpp/variant/projection.hpp index 22607036..129747a8 100644 --- a/include/godot_cpp/variant/projection.hpp +++ b/include/godot_cpp/variant/projection.hpp @@ -30,10 +30,10 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ -#ifndef GODOT_PROJECTION_HPP -#define GODOT_PROJECTION_HPP +#pragma once #include +#include #include #include @@ -58,21 +58,21 @@ struct [[nodiscard]] Projection { Vector4 columns[4]; - _FORCE_INLINE_ const Vector4 &operator[](const int p_axis) const { + _FORCE_INLINE_ const Vector4 &operator[](int p_axis) const { DEV_ASSERT((unsigned int)p_axis < 4); return columns[p_axis]; } - _FORCE_INLINE_ Vector4 &operator[](const int p_axis) { + _FORCE_INLINE_ Vector4 &operator[](int p_axis) { DEV_ASSERT((unsigned int)p_axis < 4); return columns[p_axis]; } - float determinant() const; + real_t determinant() const; void set_identity(); void set_zero(); void set_light_bias(); - void set_depth_correction(bool p_flip_y = true); + void set_depth_correction(bool p_flip_y = true, bool p_reverse_z = true, bool p_remap_z = true); void set_light_atlas_rect(const Rect2 &p_rect); void set_perspective(real_t p_fovy_degrees, real_t p_aspect, real_t p_z_near, real_t p_z_far, bool p_flip_fov = false); @@ -109,7 +109,7 @@ struct [[nodiscard]] Projection { real_t get_fov() const; bool is_orthogonal() const; - Array get_projection_planes(const Transform3D &p_transform) const; + Vector get_projection_planes(const Transform3D &p_transform) const; bool get_endpoints(const Transform3D &p_transform, Vector3 *p_8points) const; Vector2 get_viewport_half_extents() const; @@ -151,10 +151,11 @@ struct [[nodiscard]] Projection { return !(*this == p_cam); } - float get_lod_multiplier() const; + real_t get_lod_multiplier() const; Projection(); Projection(const Vector4 &p_x, const Vector4 &p_y, const Vector4 &p_z, const Vector4 &p_w); + Projection(real_t p_xx, real_t p_xy, real_t p_xz, real_t p_xw, real_t p_yx, real_t p_yy, real_t p_yz, real_t p_yw, real_t p_zx, real_t p_zy, real_t p_zz, real_t p_zw, real_t p_wx, real_t p_wy, real_t p_wz, real_t p_ww); Projection(const Transform3D &p_transform); ~Projection(); }; @@ -169,5 +170,3 @@ Vector3 Projection::xform(const Vector3 &p_vec3) const { } } // namespace godot - -#endif // GODOT_PROJECTION_HPP diff --git a/include/godot_cpp/variant/quaternion.hpp b/include/godot_cpp/variant/quaternion.hpp index c56a4e44..64427f76 100644 --- a/include/godot_cpp/variant/quaternion.hpp +++ b/include/godot_cpp/variant/quaternion.hpp @@ -30,8 +30,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ -#ifndef GODOT_QUATERNION_HPP -#define GODOT_QUATERNION_HPP +#pragma once #include #include @@ -145,15 +144,24 @@ struct [[nodiscard]] Quaternion { } Quaternion(const Vector3 &p_v0, const Vector3 &p_v1) { // Shortest arc. - Vector3 c = p_v0.cross(p_v1); - real_t d = p_v0.dot(p_v1); - - if (d < -1.0f + (real_t)CMP_EPSILON) { - x = 0; - y = 1; - z = 0; +#ifdef MATH_CHECKS + ERR_FAIL_COND_MSG(p_v0.is_zero_approx() || p_v1.is_zero_approx(), "The vectors must not be zero."); +#endif + constexpr real_t ALMOST_ONE = 1.0f - (real_t)CMP_EPSILON; + Vector3 n0 = p_v0.normalized(); + Vector3 n1 = p_v1.normalized(); + real_t d = n0.dot(n1); + if (Math::abs(d) > ALMOST_ONE) { + if (d >= 0) { + return; // Vectors are same. + } + Vector3 axis = n0.get_any_perpendicular(); + x = axis.x; + y = axis.y; + z = axis.z; w = 0; } else { + Vector3 c = n0.cross(n1); real_t s = Math::sqrt((1.0f + d) * 2.0f); real_t rs = 1.0f / s; @@ -234,5 +242,3 @@ _FORCE_INLINE_ Quaternion operator*(real_t p_real, const Quaternion &p_quaternio } } // namespace godot - -#endif // GODOT_QUATERNION_HPP diff --git a/include/godot_cpp/variant/rect2.hpp b/include/godot_cpp/variant/rect2.hpp index 6f344da9..008f199a 100644 --- a/include/godot_cpp/variant/rect2.hpp +++ b/include/godot_cpp/variant/rect2.hpp @@ -30,8 +30,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ -#ifndef GODOT_RECT2_HPP -#define GODOT_RECT2_HPP +#pragma once #include #include @@ -55,7 +54,7 @@ struct [[nodiscard]] Rect2 { _FORCE_INLINE_ Vector2 get_center() const { return position + (size * 0.5f); } - inline bool intersects(const Rect2 &p_rect, const bool p_include_borders = false) const { + inline bool intersects(const Rect2 &p_rect, bool p_include_borders = false) const { #ifdef MATH_CHECKS if (unlikely(size.x < 0 || size.y < 0 || p_rect.size.x < 0 || p_rect.size.y < 0)) { ERR_PRINT("Rect2 size is negative, this is not supported. Use Rect2.abs() to get a Rect2 with a positive size."); @@ -108,17 +107,17 @@ struct [[nodiscard]] Rect2 { } if (p_point.y < position.y) { real_t d = position.y - p_point.y; - dist = inside ? d : Math::min(dist, d); + dist = inside ? d : MIN(dist, d); inside = false; } if (p_point.x >= (position.x + size.x)) { real_t d = p_point.x - (position.x + size.x); - dist = inside ? d : Math::min(dist, d); + dist = inside ? d : MIN(dist, d); inside = false; } if (p_point.y >= (position.y + size.y)) { real_t d = p_point.y - (position.y + size.y); - dist = inside ? d : Math::min(dist, d); + dist = inside ? d : MIN(dist, d); inside = false; } @@ -148,7 +147,7 @@ struct [[nodiscard]] Rect2 { return size.x > 0.0f && size.y > 0.0f; } - // Returns the intersection between two Rect2s or an empty Rect2 if there is no intersection + // Returns the intersection between two Rect2s or an empty Rect2 if there is no intersection. inline Rect2 intersection(const Rect2 &p_rect) const { Rect2 new_rect = p_rect; @@ -285,13 +284,19 @@ struct [[nodiscard]] Rect2 { return Rect2(position + size.minf(0), size.abs()); } - Vector2 get_support(const Vector2 &p_normal) const { - Vector2 half_extents = size * 0.5f; - Vector2 ofs = position + half_extents; - return Vector2( - (p_normal.x > 0) ? -half_extents.x : half_extents.x, - (p_normal.y > 0) ? -half_extents.y : half_extents.y) + - ofs; + _FORCE_INLINE_ Rect2 round() const { + return Rect2(position.round(), size.round()); + } + + Vector2 get_support(const Vector2 &p_direction) const { + Vector2 support = position; + if (p_direction.x > 0.0f) { + support.x += size.x; + } + if (p_direction.y > 0.0f) { + support.y += size.y; + } + return support; } _FORCE_INLINE_ bool intersects_filled_polygon(const Vector2 *p_points, int p_point_count) const { @@ -307,14 +312,14 @@ struct [[nodiscard]] Rect2 { i_f = i; Vector2 r = (b - a); - float l = r.length(); + const real_t l = r.length(); if (l == 0.0f) { continue; } // Check inside. Vector2 tg = r.orthogonal(); - float s = tg.dot(center) - tg.dot(a); + const real_t s = tg.dot(center) - tg.dot(a); if (s < 0.0f) { side_plus++; } else { @@ -330,8 +335,8 @@ struct [[nodiscard]] Rect2 { Vector2 t13 = (position - a) * ir; Vector2 t24 = (end - a) * ir; - float tmin = Math::max(Math::min(t13.x, t24.x), Math::min(t13.y, t24.y)); - float tmax = Math::min(Math::max(t13.x, t24.x), Math::max(t13.y, t24.y)); + const real_t tmin = MAX(MIN(t13.x, t24.x), MIN(t13.y, t24.y)); + const real_t tmax = MIN(MAX(t13.x, t24.x), MAX(t13.y, t24.y)); // if tmax < 0, ray (line) is intersecting AABB, but the whole AABB is behind us if (tmax < 0 || tmin > tmax || tmin >= l) { @@ -371,5 +376,3 @@ struct [[nodiscard]] Rect2 { }; } // namespace godot - -#endif // GODOT_RECT2_HPP diff --git a/include/godot_cpp/variant/rect2i.hpp b/include/godot_cpp/variant/rect2i.hpp index 551ded09..7c56ac1d 100644 --- a/include/godot_cpp/variant/rect2i.hpp +++ b/include/godot_cpp/variant/rect2i.hpp @@ -30,8 +30,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ -#ifndef GODOT_RECT2I_HPP -#define GODOT_RECT2I_HPP +#pragma once #include #include @@ -91,7 +90,7 @@ struct [[nodiscard]] Rect2i { return size.x > 0 && size.y > 0; } - // Returns the intersection between two Rect2is or an empty Rect2i if there is no intersection + // Returns the intersection between two Rect2is or an empty Rect2i if there is no intersection. inline Rect2i intersection(const Rect2i &p_rect) const { Rect2i new_rect = p_rect; @@ -243,5 +242,3 @@ struct [[nodiscard]] Rect2i { }; } // namespace godot - -#endif // GODOT_RECT2I_HPP diff --git a/include/godot_cpp/variant/transform2d.hpp b/include/godot_cpp/variant/transform2d.hpp index 4a961f5a..83ffb5e8 100644 --- a/include/godot_cpp/variant/transform2d.hpp +++ b/include/godot_cpp/variant/transform2d.hpp @@ -30,8 +30,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ -#ifndef GODOT_TRANSFORM2D_HPP -#define GODOT_TRANSFORM2D_HPP +#pragma once #include #include @@ -42,21 +41,24 @@ namespace godot { class String; struct [[nodiscard]] Transform2D { - // Warning #1: basis of Transform2D is stored differently from Basis. In terms of columns array, the basis matrix looks like "on paper": + // WARNING: The basis of Transform2D is stored differently from Basis. + // In terms of columns array, the basis matrix looks like "on paper": // M = (columns[0][0] columns[1][0]) // (columns[0][1] columns[1][1]) - // This is such that the columns, which can be interpreted as basis vectors of the coordinate system "painted" on the object, can be accessed as columns[i]. - // Note that this is the opposite of the indices in mathematical texts, meaning: $M_{12}$ in a math book corresponds to columns[1][0] here. + // This is such that the columns, which can be interpreted as basis vectors + // of the coordinate system "painted" on the object, can be accessed as columns[i]. + // NOTE: This is the opposite of the indices in mathematical texts, + // meaning: $M_{12}$ in a math book corresponds to columns[1][0] here. // This requires additional care when working with explicit indices. // See https://en.wikipedia.org/wiki/Row-_and_column-major_order for further reading. - // Warning #2: 2D be aware that unlike 3D code, 2D code uses a left-handed coordinate system: Y-axis points down, - // and angle is measure from +X to +Y in a clockwise-fashion. + // WARNING: Be aware that unlike 3D code, 2D code uses a left-handed coordinate system: + // Y-axis points down, and angle is measure from +X to +Y in a clockwise-fashion. Vector2 columns[3]; - _FORCE_INLINE_ real_t tdotx(const Vector2 &v) const { return columns[0][0] * v.x + columns[1][0] * v.y; } - _FORCE_INLINE_ real_t tdoty(const Vector2 &v) const { return columns[0][1] * v.x + columns[1][1] * v.y; } + _FORCE_INLINE_ real_t tdotx(const Vector2 &p_v) const { return columns[0][0] * p_v.x + columns[1][0] * p_v.y; } + _FORCE_INLINE_ real_t tdoty(const Vector2 &p_v) const { return columns[0][1] * p_v.x + columns[1][1] * p_v.y; } const Vector2 &operator[](int p_idx) const { return columns[p_idx]; } Vector2 &operator[](int p_idx) { return columns[p_idx]; } @@ -67,20 +69,20 @@ struct [[nodiscard]] Transform2D { void affine_invert(); Transform2D affine_inverse() const; - void set_rotation(const real_t p_rot); + void set_rotation(real_t p_rot); real_t get_rotation() const; real_t get_skew() const; - void set_skew(const real_t p_angle); - _FORCE_INLINE_ void set_rotation_and_scale(const real_t p_rot, const Size2 &p_scale); - _FORCE_INLINE_ void set_rotation_scale_and_skew(const real_t p_rot, const Size2 &p_scale, const real_t p_skew); - void rotate(const real_t p_angle); + void set_skew(real_t p_angle); + _FORCE_INLINE_ void set_rotation_and_scale(real_t p_rot, const Size2 &p_scale); + _FORCE_INLINE_ void set_rotation_scale_and_skew(real_t p_rot, const Size2 &p_scale, real_t p_skew); + void rotate(real_t p_angle); void scale(const Size2 &p_scale); void scale_basis(const Size2 &p_scale); - void translate_local(const real_t p_tx, const real_t p_ty); + void translate_local(real_t p_tx, real_t p_ty); void translate_local(const Vector2 &p_translation); - real_t basis_determinant() const; + real_t determinant() const; Size2 get_scale() const; void set_scale(const Size2 &p_scale); @@ -88,18 +90,18 @@ struct [[nodiscard]] Transform2D { _FORCE_INLINE_ const Vector2 &get_origin() const { return columns[2]; } _FORCE_INLINE_ void set_origin(const Vector2 &p_origin) { columns[2] = p_origin; } - Transform2D basis_scaled(const Size2 &p_scale) const; Transform2D scaled(const Size2 &p_scale) const; Transform2D scaled_local(const Size2 &p_scale) const; Transform2D translated(const Vector2 &p_offset) const; Transform2D translated_local(const Vector2 &p_offset) const; - Transform2D rotated(const real_t p_angle) const; - Transform2D rotated_local(const real_t p_angle) const; + Transform2D rotated(real_t p_angle) const; + Transform2D rotated_local(real_t p_angle) const; Transform2D untranslated() const; void orthonormalize(); Transform2D orthonormalized() const; + bool is_conformal() const; bool is_equal_approx(const Transform2D &p_transform) const; bool is_finite() const; @@ -110,10 +112,12 @@ struct [[nodiscard]] Transform2D { void operator*=(const Transform2D &p_transform); Transform2D operator*(const Transform2D &p_transform) const; - void operator*=(const real_t p_val); - Transform2D operator*(const real_t p_val) const; + void operator*=(real_t p_val); + Transform2D operator*(real_t p_val) const; + void operator/=(real_t p_val); + Transform2D operator/(real_t p_val) const; - Transform2D interpolate_with(const Transform2D &p_transform, const real_t p_c) const; + Transform2D interpolate_with(const Transform2D &p_transform, real_t p_c) const; _FORCE_INLINE_ Vector2 basis_xform(const Vector2 &p_vec) const; _FORCE_INLINE_ Vector2 basis_xform_inv(const Vector2 &p_vec) const; @@ -126,13 +130,13 @@ struct [[nodiscard]] Transform2D { operator String() const; - Transform2D(const real_t xx, const real_t xy, const real_t yx, const real_t yy, const real_t ox, const real_t oy) { - columns[0][0] = xx; - columns[0][1] = xy; - columns[1][0] = yx; - columns[1][1] = yy; - columns[2][0] = ox; - columns[2][1] = oy; + Transform2D(real_t p_xx, real_t p_xy, real_t p_yx, real_t p_yy, real_t p_ox, real_t p_oy) { + columns[0][0] = p_xx; + columns[0][1] = p_xy; + columns[1][0] = p_yx; + columns[1][1] = p_yy; + columns[2][0] = p_ox; + columns[2][1] = p_oy; } Transform2D(const Vector2 &p_x, const Vector2 &p_y, const Vector2 &p_origin) { @@ -141,9 +145,9 @@ struct [[nodiscard]] Transform2D { columns[2] = p_origin; } - Transform2D(const real_t p_rot, const Vector2 &p_pos); + Transform2D(real_t p_rot, const Vector2 &p_pos); - Transform2D(const real_t p_rot, const Size2 &p_scale, const real_t p_skew, const Vector2 &p_pos); + Transform2D(real_t p_rot, const Size2 &p_scale, real_t p_skew, const Vector2 &p_pos); Transform2D() { columns[0][0] = 1.0; @@ -191,14 +195,14 @@ Rect2 Transform2D::xform(const Rect2 &p_rect) const { return new_rect; } -void Transform2D::set_rotation_and_scale(const real_t p_rot, const Size2 &p_scale) { +void Transform2D::set_rotation_and_scale(real_t p_rot, const Size2 &p_scale) { columns[0][0] = Math::cos(p_rot) * p_scale.x; columns[1][1] = Math::cos(p_rot) * p_scale.y; columns[1][0] = -Math::sin(p_rot) * p_scale.y; columns[0][1] = Math::sin(p_rot) * p_scale.x; } -void Transform2D::set_rotation_scale_and_skew(const real_t p_rot, const Size2 &p_scale, const real_t p_skew) { +void Transform2D::set_rotation_scale_and_skew(real_t p_rot, const Size2 &p_scale, real_t p_skew) { columns[0][0] = Math::cos(p_rot) * p_scale.x; columns[1][1] = Math::cos(p_rot + p_skew) * p_scale.y; columns[1][0] = -Math::sin(p_rot + p_skew) * p_scale.y; @@ -249,5 +253,3 @@ PackedVector2Array Transform2D::xform_inv(const PackedVector2Array &p_array) con } } // namespace godot - -#endif // GODOT_TRANSFORM2D_HPP diff --git a/include/godot_cpp/variant/transform3d.hpp b/include/godot_cpp/variant/transform3d.hpp index b97f47fe..7278d8d5 100644 --- a/include/godot_cpp/variant/transform3d.hpp +++ b/include/godot_cpp/variant/transform3d.hpp @@ -30,8 +30,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ -#ifndef GODOT_TRANSFORM3D_HPP -#define GODOT_TRANSFORM3D_HPP +#pragma once #include #include @@ -57,8 +56,8 @@ struct [[nodiscard]] Transform3D { void rotate(const Vector3 &p_axis, real_t p_angle); void rotate_basis(const Vector3 &p_axis, real_t p_angle); - void set_look_at(const Vector3 &p_eye, const Vector3 &p_target, const Vector3 &p_up = Vector3(0, 1, 0)); - Transform3D looking_at(const Vector3 &p_target, const Vector3 &p_up = Vector3(0, 1, 0)) const; + void set_look_at(const Vector3 &p_eye, const Vector3 &p_target, const Vector3 &p_up = Vector3(0, 1, 0), bool p_use_model_front = false); + Transform3D looking_at(const Vector3 &p_target, const Vector3 &p_up = Vector3(0, 1, 0), bool p_use_model_front = false) const; void scale(const Vector3 &p_scale); Transform3D scaled(const Vector3 &p_scale) const; @@ -107,8 +106,10 @@ struct [[nodiscard]] Transform3D { void operator*=(const Transform3D &p_transform); Transform3D operator*(const Transform3D &p_transform) const; - void operator*=(const real_t p_val); - Transform3D operator*(const real_t p_val) const; + void operator*=(real_t p_val); + Transform3D operator*(real_t p_val) const; + void operator/=(real_t p_val); + Transform3D operator/(real_t p_val) const; Transform3D interpolate_with(const Transform3D &p_transform, real_t p_c) const; @@ -118,11 +119,11 @@ struct [[nodiscard]] Transform3D { basis.xform(v)); } - void set(real_t xx, real_t xy, real_t xz, real_t yx, real_t yy, real_t yz, real_t zx, real_t zy, real_t zz, real_t tx, real_t ty, real_t tz) { - basis.set(xx, xy, xz, yx, yy, yz, zx, zy, zz); - origin.x = tx; - origin.y = ty; - origin.z = tz; + void set(real_t p_xx, real_t p_xy, real_t p_xz, real_t p_yx, real_t p_yy, real_t p_yz, real_t p_zx, real_t p_zy, real_t p_zz, real_t p_tx, real_t p_ty, real_t p_tz) { + basis.set(p_xx, p_xy, p_xz, p_yx, p_yy, p_yz, p_zx, p_zy, p_zz); + origin.x = p_tx; + origin.y = p_ty; + origin.z = p_tz; } operator String() const; @@ -130,7 +131,7 @@ struct [[nodiscard]] Transform3D { Transform3D() {} Transform3D(const Basis &p_basis, const Vector3 &p_origin = Vector3()); Transform3D(const Vector3 &p_x, const Vector3 &p_y, const Vector3 &p_z, const Vector3 &p_origin); - Transform3D(real_t xx, real_t xy, real_t xz, real_t yx, real_t yy, real_t yz, real_t zx, real_t zy, real_t zz, real_t ox, real_t oy, real_t oz); + Transform3D(real_t p_xx, real_t p_xy, real_t p_xz, real_t p_yx, real_t p_yy, real_t p_yz, real_t p_zx, real_t p_zy, real_t p_zz, real_t p_ox, real_t p_oy, real_t p_oz); }; _FORCE_INLINE_ Vector3 Transform3D::xform(const Vector3 &p_vector) const { @@ -274,5 +275,3 @@ _FORCE_INLINE_ Plane Transform3D::xform_inv_fast(const Plane &p_plane, const Tra } } // namespace godot - -#endif // GODOT_TRANSFORM3D_HPP diff --git a/include/godot_cpp/variant/typed_array.hpp b/include/godot_cpp/variant/typed_array.hpp index 672297f1..685cae6e 100644 --- a/include/godot_cpp/variant/typed_array.hpp +++ b/include/godot_cpp/variant/typed_array.hpp @@ -30,8 +30,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ -#ifndef GODOT_TYPED_ARRAY_HPP -#define GODOT_TYPED_ARRAY_HPP +#pragma once #include #include @@ -56,6 +55,8 @@ class TypedArray : public Array { assign(p_array); } } + _FORCE_INLINE_ TypedArray(std::initializer_list p_init) : + TypedArray(Array(p_init)) {} _FORCE_INLINE_ TypedArray() { set_typed(Variant::OBJECT, T::get_class_static(), Variant()); } @@ -71,6 +72,9 @@ class TypedArray : public Array { ERR_FAIL_COND_MSG(!is_same_typed(p_array), "Cannot assign an array with a different element type."); \ _ref(p_array); \ } \ + _FORCE_INLINE_ TypedArray(std::initializer_list p_init) : \ + Array(Array(p_init), m_variant_type, StringName(), Variant()) { \ + } \ _FORCE_INLINE_ TypedArray(const Variant &p_variant) : \ TypedArray(Array(p_variant)) { \ } \ @@ -140,5 +144,3 @@ MAKE_TYPED_ARRAY(PackedColorArray, Variant::PACKED_COLOR_ARRAY) #undef MAKE_TYPED_ARRAY } // namespace godot - -#endif // GODOT_TYPED_ARRAY_HPP diff --git a/include/godot_cpp/variant/typed_dictionary.hpp b/include/godot_cpp/variant/typed_dictionary.hpp index 8d4bf005..103dfc9f 100644 --- a/include/godot_cpp/variant/typed_dictionary.hpp +++ b/include/godot_cpp/variant/typed_dictionary.hpp @@ -30,10 +30,10 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ -#ifndef GODOT_TYPED_DICTIONARY_HPP -#define GODOT_TYPED_DICTIONARY_HPP +#pragma once #include +#include #include #include @@ -60,54 +60,75 @@ class TypedDictionary : public Dictionary { _FORCE_INLINE_ TypedDictionary() { set_typed(Variant::OBJECT, K::get_class_static(), Variant(), Variant::OBJECT, V::get_class_static(), Variant()); } + _FORCE_INLINE_ TypedDictionary(std::initializer_list> p_init) : + Dictionary() { + set_typed(Variant::OBJECT, K::get_class_static(), Variant(), Variant::OBJECT, V::get_class_static(), Variant()); + for (const KeyValue &E : p_init) { + operator[](E.key) = E.value; + } + } }; //specialization for the rest of variant types -#define MAKE_TYPED_DICTIONARY_WITH_OBJECT(m_type, m_variant_type) \ - template \ - class TypedDictionary : public Dictionary { \ - public: \ - _FORCE_INLINE_ void operator=(const Dictionary &p_dictionary) { \ - ERR_FAIL_COND_MSG(!is_same_typed(p_dictionary), "Cannot assign an dictionary with a different element type."); \ - Dictionary::operator=(p_dictionary); \ - } \ - _FORCE_INLINE_ TypedDictionary(const Variant &p_variant) : \ - TypedDictionary(Dictionary(p_variant)) { \ - } \ - _FORCE_INLINE_ TypedDictionary(const Dictionary &p_dictionary) { \ - set_typed(Variant::OBJECT, T::get_class_static(), Variant(), m_variant_type, StringName(), Variant()); \ - if (is_same_typed(p_dictionary)) { \ - Dictionary::operator=(p_dictionary); \ - } else { \ - assign(p_dictionary); \ - } \ - } \ - _FORCE_INLINE_ TypedDictionary() { \ - set_typed(Variant::OBJECT, T::get_class_static(), Variant(), m_variant_type, StringName(), Variant()); \ - } \ - }; \ - template \ - class TypedDictionary : public Dictionary { \ - public: \ - _FORCE_INLINE_ void operator=(const Dictionary &p_dictionary) { \ - ERR_FAIL_COND_MSG(!is_same_typed(p_dictionary), "Cannot assign an dictionary with a different element type."); \ - Dictionary::operator=(p_dictionary); \ - } \ - _FORCE_INLINE_ TypedDictionary(const Variant &p_variant) : \ - TypedDictionary(Dictionary(p_variant)) { \ - } \ - _FORCE_INLINE_ TypedDictionary(const Dictionary &p_dictionary) { \ - set_typed(m_variant_type, StringName(), Variant(), Variant::OBJECT, T::get_class_static(), Variant()); \ - if (is_same_typed(p_dictionary)) { \ - Dictionary::operator=(p_dictionary); \ - } else { \ - assign(p_dictionary); \ - } \ - } \ - _FORCE_INLINE_ TypedDictionary() { \ - set_typed(m_variant_type, StringName(), Variant(), Variant::OBJECT, T::get_class_static(), Variant()); \ - } \ +#define MAKE_TYPED_DICTIONARY_WITH_OBJECT(m_type, m_variant_type) \ + template \ + class TypedDictionary : public Dictionary { \ + public: \ + _FORCE_INLINE_ void operator=(const Dictionary &p_dictionary) { \ + ERR_FAIL_COND_MSG(!is_same_typed(p_dictionary), "Cannot assign an dictionary with a different element type."); \ + Dictionary::operator=(p_dictionary); \ + } \ + _FORCE_INLINE_ TypedDictionary(const Variant &p_variant) : \ + TypedDictionary(Dictionary(p_variant)) { \ + } \ + _FORCE_INLINE_ TypedDictionary(const Dictionary &p_dictionary) { \ + set_typed(Variant::OBJECT, T::get_class_static(), Variant(), m_variant_type, StringName(), Variant()); \ + if (is_same_typed(p_dictionary)) { \ + Dictionary::operator=(p_dictionary); \ + } else { \ + assign(p_dictionary); \ + } \ + } \ + _FORCE_INLINE_ TypedDictionary() { \ + set_typed(Variant::OBJECT, T::get_class_static(), Variant(), m_variant_type, StringName(), Variant()); \ + } \ + _FORCE_INLINE_ TypedDictionary(std::initializer_list> p_init) : \ + Dictionary() { \ + set_typed(Variant::OBJECT, T::get_class_static(), Variant(), m_variant_type, StringName(), Variant()); \ + for (const KeyValue &E : p_init) { \ + operator[](E.key) = E.value; \ + } \ + } \ + }; \ + template \ + class TypedDictionary : public Dictionary { \ + public: \ + _FORCE_INLINE_ void operator=(const Dictionary &p_dictionary) { \ + ERR_FAIL_COND_MSG(!is_same_typed(p_dictionary), "Cannot assign an dictionary with a different element type."); \ + Dictionary::operator=(p_dictionary); \ + } \ + _FORCE_INLINE_ TypedDictionary(const Variant &p_variant) : \ + TypedDictionary(Dictionary(p_variant)) { \ + } \ + _FORCE_INLINE_ TypedDictionary(const Dictionary &p_dictionary) { \ + set_typed(m_variant_type, StringName(), Variant(), Variant::OBJECT, T::get_class_static(), Variant()); \ + if (is_same_typed(p_dictionary)) { \ + Dictionary::operator=(p_dictionary); \ + } else { \ + assign(p_dictionary); \ + } \ + } \ + _FORCE_INLINE_ TypedDictionary() { \ + set_typed(m_variant_type, StringName(), Variant(), Variant::OBJECT, T::get_class_static(), Variant()); \ + } \ + _FORCE_INLINE_ TypedDictionary(std::initializer_list> p_init) : \ + Dictionary() { \ + set_typed(m_variant_type, StringName(), Variant(), Variant::OBJECT, std::remove_pointer::type::get_class_static(), Variant()); \ + for (const KeyValue &E : p_init) { \ + operator[](E.key) = E.value; \ + } \ + } \ }; #define MAKE_TYPED_DICTIONARY_EXPANDED(m_type_key, m_variant_type_key, m_type_value, m_variant_type_value) \ @@ -132,6 +153,13 @@ class TypedDictionary : public Dictionary { _FORCE_INLINE_ TypedDictionary() { \ set_typed(m_variant_type_key, StringName(), Variant(), m_variant_type_value, StringName(), Variant()); \ } \ + _FORCE_INLINE_ TypedDictionary(std::initializer_list> p_init) : \ + Dictionary() { \ + set_typed(m_variant_type_key, StringName(), Variant(), m_variant_type_value, StringName(), Variant()); \ + for (const KeyValue &E : p_init) { \ + operator[](E.key) = E.value; \ + } \ + } \ }; #define MAKE_TYPED_DICTIONARY_NIL(m_type, m_variant_type) \ @@ -437,5 +465,3 @@ MAKE_TYPED_DICTIONARY_INFO(IPAddress, Variant::STRING) #undef MAKE_TYPED_DICTIONARY_INFO_WITH_OBJECT } // namespace godot - -#endif // GODOT_TYPED_DICTIONARY_HPP diff --git a/include/godot_cpp/variant/variant.hpp b/include/godot_cpp/variant/variant.hpp index 1edc8e81..04b70672 100644 --- a/include/godot_cpp/variant/variant.hpp +++ b/include/godot_cpp/variant/variant.hpp @@ -30,11 +30,11 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ -#ifndef GODOT_VARIANT_HPP -#define GODOT_VARIANT_HPP +#pragma once #include +#include #include #include @@ -360,6 +360,65 @@ String vformat(const String &p_text, const VarArgs... p_args) { return p_text % args_array; } +Variant &Array::Iterator::operator*() const { + return *elem_ptr; +} + +Variant *Array::Iterator::operator->() const { + return elem_ptr; +} + +Array::Iterator &Array::Iterator::operator++() { + elem_ptr++; + return *this; +} + +Array::Iterator &Array::Iterator::operator--() { + elem_ptr--; + return *this; +} + +const Variant &Array::ConstIterator::operator*() const { + return *elem_ptr; +} + +const Variant *Array::ConstIterator::operator->() const { + return elem_ptr; +} + +Array::ConstIterator &Array::ConstIterator::operator++() { + elem_ptr++; + return *this; +} + +Array::ConstIterator &Array::ConstIterator::operator--() { + elem_ptr--; + return *this; +} + +Array::Iterator Array::begin() { + return Array::Iterator(ptrw()); +} +Array::Iterator Array::end() { + return Array::Iterator(ptrw() + size()); +} + +Array::ConstIterator Array::begin() const { + return Array::ConstIterator(ptr()); +} +Array::ConstIterator Array::end() const { + return Array::ConstIterator(ptr() + size()); +} + +Array::Array(std::initializer_list p_init) { + ERR_FAIL_COND(resize(p_init.size()) != 0); + + size_t i = 0; + for (const Variant &element : p_init) { + set(i++, element); + } +} + #include #ifdef REAL_T_IS_DOUBLE @@ -369,5 +428,3 @@ using PackedRealArray = PackedFloat32Array; #endif // REAL_T_IS_DOUBLE } // namespace godot - -#endif // GODOT_VARIANT_HPP diff --git a/include/godot_cpp/variant/variant_internal.hpp b/include/godot_cpp/variant/variant_internal.hpp index 12df35c2..9c1fc4ef 100644 --- a/include/godot_cpp/variant/variant_internal.hpp +++ b/include/godot_cpp/variant/variant_internal.hpp @@ -30,8 +30,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ -#ifndef GODOT_VARIANT_INTERNAL_HPP -#define GODOT_VARIANT_INTERNAL_HPP +#pragma once #include #include @@ -507,5 +506,3 @@ struct VariantDefaultInitializer { }; } // namespace godot - -#endif // GODOT_VARIANT_INTERNAL_HPP diff --git a/include/godot_cpp/variant/vector2.hpp b/include/godot_cpp/variant/vector2.hpp index 9511c1b5..b8ec0652 100644 --- a/include/godot_cpp/variant/vector2.hpp +++ b/include/godot_cpp/variant/vector2.hpp @@ -30,8 +30,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ -#ifndef GODOT_VECTOR2_HPP -#define GODOT_VECTOR2_HPP +#pragma once #include #include @@ -64,13 +63,13 @@ struct [[nodiscard]] Vector2 { real_t coord[2] = { 0 }; }; - _FORCE_INLINE_ real_t &operator[](int p_idx) { - DEV_ASSERT((unsigned int)p_idx < 2); - return coord[p_idx]; + _FORCE_INLINE_ real_t &operator[](int p_axis) { + DEV_ASSERT((unsigned int)p_axis < 2); + return coord[p_axis]; } - _FORCE_INLINE_ const real_t &operator[](int p_idx) const { - DEV_ASSERT((unsigned int)p_idx < 2); - return coord[p_idx]; + _FORCE_INLINE_ const real_t &operator[](int p_axis) const { + DEV_ASSERT((unsigned int)p_axis < 2); + return coord[p_axis]; } _FORCE_INLINE_ Vector2::Axis min_axis_index() const { @@ -87,7 +86,7 @@ struct [[nodiscard]] Vector2 { real_t length() const; real_t length_squared() const; - Vector2 limit_length(const real_t p_len = 1.0) const; + Vector2 limit_length(real_t p_len = 1.0) const; Vector2 min(const Vector2 &p_vector2) const { return Vector2(MIN(x, p_vector2.x), MIN(y, p_vector2.y)); @@ -113,19 +112,20 @@ struct [[nodiscard]] Vector2 { real_t dot(const Vector2 &p_other) const; real_t cross(const Vector2 &p_other) const; - Vector2 posmod(const real_t p_mod) const; + Vector2 posmod(real_t p_mod) const; Vector2 posmodv(const Vector2 &p_modv) const; Vector2 project(const Vector2 &p_to) const; - Vector2 plane_project(const real_t p_d, const Vector2 &p_vec) const; + Vector2 plane_project(real_t p_d, const Vector2 &p_vec) const; - _FORCE_INLINE_ Vector2 lerp(const Vector2 &p_to, const real_t p_weight) const; - _FORCE_INLINE_ Vector2 slerp(const Vector2 &p_to, const real_t p_weight) const; - _FORCE_INLINE_ Vector2 cubic_interpolate(const Vector2 &p_b, const Vector2 &p_pre_a, const Vector2 &p_post_b, const real_t p_weight) const; - _FORCE_INLINE_ Vector2 cubic_interpolate_in_time(const Vector2 &p_b, const Vector2 &p_pre_a, const Vector2 &p_post_b, const real_t p_weight, const real_t &p_b_t, const real_t &p_pre_a_t, const real_t &p_post_b_t) const; - _FORCE_INLINE_ Vector2 bezier_interpolate(const Vector2 &p_control_1, const Vector2 &p_control_2, const Vector2 &p_end, const real_t p_t) const; + _FORCE_INLINE_ Vector2 lerp(const Vector2 &p_to, real_t p_weight) const; + _FORCE_INLINE_ Vector2 slerp(const Vector2 &p_to, real_t p_weight) const; + _FORCE_INLINE_ Vector2 cubic_interpolate(const Vector2 &p_b, const Vector2 &p_pre_a, const Vector2 &p_post_b, real_t p_weight) const; + _FORCE_INLINE_ Vector2 cubic_interpolate_in_time(const Vector2 &p_b, const Vector2 &p_pre_a, const Vector2 &p_post_b, real_t p_weight, real_t p_b_t, real_t p_pre_a_t, real_t p_post_b_t) const; + _FORCE_INLINE_ Vector2 bezier_interpolate(const Vector2 &p_control_1, const Vector2 &p_control_2, const Vector2 &p_end, real_t p_t) const; + _FORCE_INLINE_ Vector2 bezier_derivative(const Vector2 &p_control_1, const Vector2 &p_control_2, const Vector2 &p_end, real_t p_t) const; - Vector2 move_toward(const Vector2 &p_to, const real_t p_delta) const; + Vector2 move_toward(const Vector2 &p_to, real_t p_delta) const; Vector2 slide(const Vector2 &p_normal) const; Vector2 bounce(const Vector2 &p_normal) const; @@ -141,16 +141,16 @@ struct [[nodiscard]] Vector2 { void operator-=(const Vector2 &p_v); Vector2 operator*(const Vector2 &p_v1) const; - Vector2 operator*(const real_t &rvalue) const; - void operator*=(const real_t &rvalue); - void operator*=(const Vector2 &rvalue) { *this = *this * rvalue; } + Vector2 operator*(real_t p_rvalue) const; + void operator*=(real_t p_rvalue); + void operator*=(const Vector2 &p_rvalue) { *this = *this * p_rvalue; } Vector2 operator/(const Vector2 &p_v1) const; - Vector2 operator/(const real_t &rvalue) const; + Vector2 operator/(real_t p_rvalue) const; - void operator/=(const real_t &rvalue); - void operator/=(const Vector2 &rvalue) { *this = *this / rvalue; } + void operator/=(real_t p_rvalue); + void operator/=(const Vector2 &p_rvalue) { *this = *this / p_rvalue; } Vector2 operator-() const; @@ -163,13 +163,13 @@ struct [[nodiscard]] Vector2 { bool operator>=(const Vector2 &p_vec2) const { return x == p_vec2.x ? (y >= p_vec2.y) : (x > p_vec2.x); } real_t angle() const; - static Vector2 from_angle(const real_t p_angle); + static Vector2 from_angle(real_t p_angle); _FORCE_INLINE_ Vector2 abs() const { return Vector2(Math::abs(x), Math::abs(y)); } - Vector2 rotated(const real_t p_by) const; + Vector2 rotated(real_t p_by) const; Vector2 orthogonal() const { return Vector2(y, -x); } @@ -188,13 +188,13 @@ struct [[nodiscard]] Vector2 { operator Vector2i() const; _FORCE_INLINE_ Vector2() {} - _FORCE_INLINE_ Vector2(const real_t p_x, const real_t p_y) { + _FORCE_INLINE_ Vector2(real_t p_x, real_t p_y) { x = p_x; y = p_y; } }; -_FORCE_INLINE_ Vector2 Vector2::plane_project(const real_t p_d, const Vector2 &p_vec) const { +_FORCE_INLINE_ Vector2 Vector2::plane_project(real_t p_d, const Vector2 &p_vec) const { return p_vec - *this * (dot(p_vec) - p_d); } @@ -220,26 +220,26 @@ _FORCE_INLINE_ Vector2 Vector2::operator*(const Vector2 &p_v1) const { return Vector2(x * p_v1.x, y * p_v1.y); } -_FORCE_INLINE_ Vector2 Vector2::operator*(const real_t &rvalue) const { - return Vector2(x * rvalue, y * rvalue); +_FORCE_INLINE_ Vector2 Vector2::operator*(real_t p_rvalue) const { + return Vector2(x * p_rvalue, y * p_rvalue); } -_FORCE_INLINE_ void Vector2::operator*=(const real_t &rvalue) { - x *= rvalue; - y *= rvalue; +_FORCE_INLINE_ void Vector2::operator*=(real_t p_rvalue) { + x *= p_rvalue; + y *= p_rvalue; } _FORCE_INLINE_ Vector2 Vector2::operator/(const Vector2 &p_v1) const { return Vector2(x / p_v1.x, y / p_v1.y); } -_FORCE_INLINE_ Vector2 Vector2::operator/(const real_t &rvalue) const { - return Vector2(x / rvalue, y / rvalue); +_FORCE_INLINE_ Vector2 Vector2::operator/(real_t p_rvalue) const { + return Vector2(x / p_rvalue, y / p_rvalue); } -_FORCE_INLINE_ void Vector2::operator/=(const real_t &rvalue) { - x /= rvalue; - y /= rvalue; +_FORCE_INLINE_ void Vector2::operator/=(real_t p_rvalue) { + x /= p_rvalue; + y /= p_rvalue; } _FORCE_INLINE_ Vector2 Vector2::operator-() const { @@ -254,16 +254,14 @@ _FORCE_INLINE_ bool Vector2::operator!=(const Vector2 &p_vec2) const { return x != p_vec2.x || y != p_vec2.y; } -Vector2 Vector2::lerp(const Vector2 &p_to, const real_t p_weight) const { +Vector2 Vector2::lerp(const Vector2 &p_to, real_t p_weight) const { Vector2 res = *this; - - res.x += (p_weight * (p_to.x - x)); - res.y += (p_weight * (p_to.y - y)); - + res.x = Math::lerp(res.x, p_to.x, p_weight); + res.y = Math::lerp(res.y, p_to.y, p_weight); return res; } -Vector2 Vector2::slerp(const Vector2 &p_to, const real_t p_weight) const { +Vector2 Vector2::slerp(const Vector2 &p_to, real_t p_weight) const { real_t start_length_sq = length_squared(); real_t end_length_sq = p_to.length_squared(); if (unlikely(start_length_sq == 0.0f || end_length_sq == 0.0f)) { @@ -276,31 +274,32 @@ Vector2 Vector2::slerp(const Vector2 &p_to, const real_t p_weight) const { return rotated(angle * p_weight) * (result_length / start_length); } -Vector2 Vector2::cubic_interpolate(const Vector2 &p_b, const Vector2 &p_pre_a, const Vector2 &p_post_b, const real_t p_weight) const { +Vector2 Vector2::cubic_interpolate(const Vector2 &p_b, const Vector2 &p_pre_a, const Vector2 &p_post_b, real_t p_weight) const { Vector2 res = *this; res.x = Math::cubic_interpolate(res.x, p_b.x, p_pre_a.x, p_post_b.x, p_weight); res.y = Math::cubic_interpolate(res.y, p_b.y, p_pre_a.y, p_post_b.y, p_weight); return res; } -Vector2 Vector2::cubic_interpolate_in_time(const Vector2 &p_b, const Vector2 &p_pre_a, const Vector2 &p_post_b, const real_t p_weight, const real_t &p_b_t, const real_t &p_pre_a_t, const real_t &p_post_b_t) const { +Vector2 Vector2::cubic_interpolate_in_time(const Vector2 &p_b, const Vector2 &p_pre_a, const Vector2 &p_post_b, real_t p_weight, real_t p_b_t, real_t p_pre_a_t, real_t p_post_b_t) const { Vector2 res = *this; res.x = Math::cubic_interpolate_in_time(res.x, p_b.x, p_pre_a.x, p_post_b.x, p_weight, p_b_t, p_pre_a_t, p_post_b_t); res.y = Math::cubic_interpolate_in_time(res.y, p_b.y, p_pre_a.y, p_post_b.y, p_weight, p_b_t, p_pre_a_t, p_post_b_t); return res; } -Vector2 Vector2::bezier_interpolate(const Vector2 &p_control_1, const Vector2 &p_control_2, const Vector2 &p_end, const real_t p_t) const { +Vector2 Vector2::bezier_interpolate(const Vector2 &p_control_1, const Vector2 &p_control_2, const Vector2 &p_end, real_t p_t) const { Vector2 res = *this; + res.x = Math::bezier_interpolate(res.x, p_control_1.x, p_control_2.x, p_end.x, p_t); + res.y = Math::bezier_interpolate(res.y, p_control_1.y, p_control_2.y, p_end.y, p_t); + return res; +} - /* Formula from Wikipedia article on Bezier curves. */ - real_t omt = (1.0 - p_t); - real_t omt2 = omt * omt; - real_t omt3 = omt2 * omt; - real_t t2 = p_t * p_t; - real_t t3 = t2 * p_t; - - return res * omt3 + p_control_1 * omt2 * p_t * 3.0 + p_control_2 * omt * t2 * 3.0 + p_end * t3; +Vector2 Vector2::bezier_derivative(const Vector2 &p_control_1, const Vector2 &p_control_2, const Vector2 &p_end, real_t p_t) const { + Vector2 res = *this; + res.x = Math::bezier_derivative(res.x, p_control_1.x, p_control_2.x, p_end.x, p_t); + res.y = Math::bezier_derivative(res.y, p_control_1.y, p_control_2.y, p_end.y, p_t); + return res; } Vector2 Vector2::direction_to(const Vector2 &p_to) const { @@ -312,19 +311,19 @@ Vector2 Vector2::direction_to(const Vector2 &p_to) const { // Multiplication operators required to workaround issues with LLVM using implicit conversion // to Vector2i instead for integers where it should not. -_FORCE_INLINE_ Vector2 operator*(const float p_scalar, const Vector2 &p_vec) { +_FORCE_INLINE_ Vector2 operator*(float p_scalar, const Vector2 &p_vec) { return p_vec * p_scalar; } -_FORCE_INLINE_ Vector2 operator*(const double p_scalar, const Vector2 &p_vec) { +_FORCE_INLINE_ Vector2 operator*(double p_scalar, const Vector2 &p_vec) { return p_vec * p_scalar; } -_FORCE_INLINE_ Vector2 operator*(const int32_t p_scalar, const Vector2 &p_vec) { +_FORCE_INLINE_ Vector2 operator*(int32_t p_scalar, const Vector2 &p_vec) { return p_vec * p_scalar; } -_FORCE_INLINE_ Vector2 operator*(const int64_t p_scalar, const Vector2 &p_vec) { +_FORCE_INLINE_ Vector2 operator*(int64_t p_scalar, const Vector2 &p_vec) { return p_vec * p_scalar; } @@ -332,5 +331,3 @@ typedef Vector2 Size2; typedef Vector2 Point2; } // namespace godot - -#endif // GODOT_VECTOR2_HPP diff --git a/include/godot_cpp/variant/vector2i.hpp b/include/godot_cpp/variant/vector2i.hpp index 5504bab0..3ad09446 100644 --- a/include/godot_cpp/variant/vector2i.hpp +++ b/include/godot_cpp/variant/vector2i.hpp @@ -30,8 +30,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ -#ifndef GODOT_VECTOR2I_HPP -#define GODOT_VECTOR2I_HPP +#pragma once #include #include @@ -64,13 +63,13 @@ struct [[nodiscard]] Vector2i { int32_t coord[2] = { 0 }; }; - _FORCE_INLINE_ int32_t &operator[](int p_idx) { - DEV_ASSERT((unsigned int)p_idx < 2); - return coord[p_idx]; + _FORCE_INLINE_ int32_t &operator[](int p_axis) { + DEV_ASSERT((unsigned int)p_axis < 2); + return coord[p_axis]; } - _FORCE_INLINE_ const int32_t &operator[](int p_idx) const { - DEV_ASSERT((unsigned int)p_idx < 2); - return coord[p_idx]; + _FORCE_INLINE_ const int32_t &operator[](int p_axis) const { + DEV_ASSERT((unsigned int)p_axis < 2); + return coord[p_axis]; } _FORCE_INLINE_ Vector2i::Axis min_axis_index() const { @@ -97,22 +96,30 @@ struct [[nodiscard]] Vector2i { return Vector2i(MAX(x, p_scalar), MAX(y, p_scalar)); } + double distance_to(const Vector2i &p_to) const { + return (p_to - *this).length(); + } + + int64_t distance_squared_to(const Vector2i &p_to) const { + return (p_to - *this).length_squared(); + } + Vector2i operator+(const Vector2i &p_v) const; void operator+=(const Vector2i &p_v); Vector2i operator-(const Vector2i &p_v) const; void operator-=(const Vector2i &p_v); Vector2i operator*(const Vector2i &p_v1) const; - Vector2i operator*(const int32_t &rvalue) const; - void operator*=(const int32_t &rvalue); + Vector2i operator*(int32_t p_rvalue) const; + void operator*=(int32_t p_rvalue); Vector2i operator/(const Vector2i &p_v1) const; - Vector2i operator/(const int32_t &rvalue) const; - void operator/=(const int32_t &rvalue); + Vector2i operator/(int32_t p_rvalue) const; + void operator/=(int32_t p_rvalue); Vector2i operator%(const Vector2i &p_v1) const; - Vector2i operator%(const int32_t &rvalue) const; - void operator%=(const int32_t &rvalue); + Vector2i operator%(int32_t p_rvalue) const; + void operator%=(int32_t p_rvalue); Vector2i operator-() const; bool operator<(const Vector2i &p_vec2) const { return (x == p_vec2.x) ? (y < p_vec2.y) : (x < p_vec2.x); } @@ -127,22 +134,19 @@ struct [[nodiscard]] Vector2i { int64_t length_squared() const; double length() const; - int64_t distance_squared_to(const Vector2i &p_to) const; - double distance_to(const Vector2i &p_to) const; - real_t aspect() const { return width / (real_t)height; } Vector2i sign() const { return Vector2i(SIGN(x), SIGN(y)); } Vector2i abs() const { return Vector2i(Math::abs(x), Math::abs(y)); } - Vector2i snapped(const Vector2i &p_step) const; - Vector2i snappedi(int32_t p_step) const; Vector2i clamp(const Vector2i &p_min, const Vector2i &p_max) const; Vector2i clampi(int32_t p_min, int32_t p_max) const; + Vector2i snapped(const Vector2i &p_step) const; + Vector2i snappedi(int32_t p_step) const; operator String() const; operator Vector2() const; inline Vector2i() {} - inline Vector2i(const int32_t p_x, const int32_t p_y) { + inline Vector2i(int32_t p_x, int32_t p_y) { x = p_x; y = p_y; } @@ -150,19 +154,19 @@ struct [[nodiscard]] Vector2i { // Multiplication operators required to workaround issues with LLVM using implicit conversion. -_FORCE_INLINE_ Vector2i operator*(const int32_t p_scalar, const Vector2i &p_vector) { +_FORCE_INLINE_ Vector2i operator*(int32_t p_scalar, const Vector2i &p_vector) { return p_vector * p_scalar; } -_FORCE_INLINE_ Vector2i operator*(const int64_t p_scalar, const Vector2i &p_vector) { +_FORCE_INLINE_ Vector2i operator*(int64_t p_scalar, const Vector2i &p_vector) { return p_vector * p_scalar; } -_FORCE_INLINE_ Vector2i operator*(const float p_scalar, const Vector2i &p_vector) { +_FORCE_INLINE_ Vector2i operator*(float p_scalar, const Vector2i &p_vector) { return p_vector * p_scalar; } -_FORCE_INLINE_ Vector2i operator*(const double p_scalar, const Vector2i &p_vector) { +_FORCE_INLINE_ Vector2i operator*(double p_scalar, const Vector2i &p_vector) { return p_vector * p_scalar; } @@ -170,5 +174,3 @@ typedef Vector2i Size2i; typedef Vector2i Point2i; } // namespace godot - -#endif // GODOT_VECTOR2I_HPP diff --git a/include/godot_cpp/variant/vector3.hpp b/include/godot_cpp/variant/vector3.hpp index a4a9620b..af04e08e 100644 --- a/include/godot_cpp/variant/vector3.hpp +++ b/include/godot_cpp/variant/vector3.hpp @@ -30,15 +30,14 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ -#ifndef GODOT_VECTOR3_HPP -#define GODOT_VECTOR3_HPP +#pragma once #include #include +#include namespace godot { -class String; struct Basis; struct Vector2; struct Vector3i; @@ -62,12 +61,12 @@ struct [[nodiscard]] Vector3 { real_t coord[3] = { 0 }; }; - _FORCE_INLINE_ const real_t &operator[](const int p_axis) const { + _FORCE_INLINE_ const real_t &operator[](int p_axis) const { DEV_ASSERT((unsigned int)p_axis < 3); return coord[p_axis]; } - _FORCE_INLINE_ real_t &operator[](const int p_axis) { + _FORCE_INLINE_ real_t &operator[](int p_axis) { DEV_ASSERT((unsigned int)p_axis < 3); return coord[p_axis]; } @@ -103,36 +102,38 @@ struct [[nodiscard]] Vector3 { _FORCE_INLINE_ Vector3 normalized() const; _FORCE_INLINE_ bool is_normalized() const; _FORCE_INLINE_ Vector3 inverse() const; - Vector3 limit_length(const real_t p_len = 1.0) const; + Vector3 limit_length(real_t p_len = 1.0) const; _FORCE_INLINE_ void zero(); - void snap(const Vector3 p_val); - void snapf(real_t p_val); - Vector3 snapped(const Vector3 p_val) const; - Vector3 snappedf(real_t p_val) const; + void snap(const Vector3 &p_step); + void snapf(real_t p_step); + Vector3 snapped(const Vector3 &p_step) const; + Vector3 snappedf(real_t p_step) const; - void rotate(const Vector3 &p_axis, const real_t p_angle); - Vector3 rotated(const Vector3 &p_axis, const real_t p_angle) const; + void rotate(const Vector3 &p_axis, real_t p_angle); + Vector3 rotated(const Vector3 &p_axis, real_t p_angle) const; /* Static Methods between 2 vector3s */ - _FORCE_INLINE_ Vector3 lerp(const Vector3 &p_to, const real_t p_weight) const; - _FORCE_INLINE_ Vector3 slerp(const Vector3 &p_to, const real_t p_weight) const; - _FORCE_INLINE_ Vector3 cubic_interpolate(const Vector3 &p_b, const Vector3 &p_pre_a, const Vector3 &p_post_b, const real_t p_weight) const; - _FORCE_INLINE_ Vector3 cubic_interpolate_in_time(const Vector3 &p_b, const Vector3 &p_pre_a, const Vector3 &p_post_b, const real_t p_weight, const real_t &p_b_t, const real_t &p_pre_a_t, const real_t &p_post_b_t) const; - _FORCE_INLINE_ Vector3 bezier_interpolate(const Vector3 &p_control_1, const Vector3 &p_control_2, const Vector3 &p_end, const real_t p_t) const; + _FORCE_INLINE_ Vector3 lerp(const Vector3 &p_to, real_t p_weight) const; + _FORCE_INLINE_ Vector3 slerp(const Vector3 &p_to, real_t p_weight) const; + _FORCE_INLINE_ Vector3 cubic_interpolate(const Vector3 &p_b, const Vector3 &p_pre_a, const Vector3 &p_post_b, real_t p_weight) const; + _FORCE_INLINE_ Vector3 cubic_interpolate_in_time(const Vector3 &p_b, const Vector3 &p_pre_a, const Vector3 &p_post_b, real_t p_weight, real_t p_b_t, real_t p_pre_a_t, real_t p_post_b_t) const; + _FORCE_INLINE_ Vector3 bezier_interpolate(const Vector3 &p_control_1, const Vector3 &p_control_2, const Vector3 &p_end, real_t p_t) const; + _FORCE_INLINE_ Vector3 bezier_derivative(const Vector3 &p_control_1, const Vector3 &p_control_2, const Vector3 &p_end, real_t p_t) const; - Vector3 move_toward(const Vector3 &p_to, const real_t p_delta) const; + Vector3 move_toward(const Vector3 &p_to, real_t p_delta) const; Vector2 octahedron_encode() const; static Vector3 octahedron_decode(const Vector2 &p_oct); - Vector2 octahedron_tangent_encode(const float sign) const; - static Vector3 octahedron_tangent_decode(const Vector2 &p_oct, float *sign); + Vector2 octahedron_tangent_encode(float p_sign) const; + static Vector3 octahedron_tangent_decode(const Vector2 &p_oct, float *r_sign); _FORCE_INLINE_ Vector3 cross(const Vector3 &p_with) const; _FORCE_INLINE_ real_t dot(const Vector3 &p_with) const; Basis outer(const Vector3 &p_with) const; + _FORCE_INLINE_ Vector3 get_any_perpendicular() const; _FORCE_INLINE_ Vector3 abs() const; _FORCE_INLINE_ Vector3 floor() const; @@ -145,7 +146,7 @@ struct [[nodiscard]] Vector3 { _FORCE_INLINE_ real_t distance_to(const Vector3 &p_to) const; _FORCE_INLINE_ real_t distance_squared_to(const Vector3 &p_to) const; - _FORCE_INLINE_ Vector3 posmod(const real_t p_mod) const; + _FORCE_INLINE_ Vector3 posmod(real_t p_mod) const; _FORCE_INLINE_ Vector3 posmodv(const Vector3 &p_modv) const; _FORCE_INLINE_ Vector3 project(const Vector3 &p_to) const; @@ -172,10 +173,10 @@ struct [[nodiscard]] Vector3 { _FORCE_INLINE_ Vector3 &operator/=(const Vector3 &p_v); _FORCE_INLINE_ Vector3 operator/(const Vector3 &p_v) const; - _FORCE_INLINE_ Vector3 &operator*=(const real_t p_scalar); - _FORCE_INLINE_ Vector3 operator*(const real_t p_scalar) const; - _FORCE_INLINE_ Vector3 &operator/=(const real_t p_scalar); - _FORCE_INLINE_ Vector3 operator/(const real_t p_scalar) const; + _FORCE_INLINE_ Vector3 &operator*=(real_t p_scalar); + _FORCE_INLINE_ Vector3 operator*(real_t p_scalar) const; + _FORCE_INLINE_ Vector3 &operator/=(real_t p_scalar); + _FORCE_INLINE_ Vector3 operator/(real_t p_scalar) const; _FORCE_INLINE_ Vector3 operator-() const; @@ -190,7 +191,7 @@ struct [[nodiscard]] Vector3 { operator Vector3i() const; _FORCE_INLINE_ Vector3() {} - _FORCE_INLINE_ Vector3(const real_t p_x, const real_t p_y, const real_t p_z) { + _FORCE_INLINE_ Vector3(real_t p_x, real_t p_y, real_t p_z) { x = p_x; y = p_y; z = p_z; @@ -230,14 +231,15 @@ Vector3 Vector3::round() const { return Vector3(Math::round(x), Math::round(y), Math::round(z)); } -Vector3 Vector3::lerp(const Vector3 &p_to, const real_t p_weight) const { - return Vector3( - x + (p_weight * (p_to.x - x)), - y + (p_weight * (p_to.y - y)), - z + (p_weight * (p_to.z - z))); +Vector3 Vector3::lerp(const Vector3 &p_to, real_t p_weight) const { + Vector3 res = *this; + res.x = Math::lerp(res.x, p_to.x, p_weight); + res.y = Math::lerp(res.y, p_to.y, p_weight); + res.z = Math::lerp(res.z, p_to.z, p_weight); + return res; } -Vector3 Vector3::slerp(const Vector3 &p_to, const real_t p_weight) const { +Vector3 Vector3::slerp(const Vector3 &p_to, real_t p_weight) const { // This method seems more complicated than it really is, since we write out // the internals of some methods for efficiency (mainly, checking length). real_t start_length_sq = length_squared(); @@ -259,7 +261,7 @@ Vector3 Vector3::slerp(const Vector3 &p_to, const real_t p_weight) const { return rotated(axis, angle * p_weight) * (result_length / start_length); } -Vector3 Vector3::cubic_interpolate(const Vector3 &p_b, const Vector3 &p_pre_a, const Vector3 &p_post_b, const real_t p_weight) const { +Vector3 Vector3::cubic_interpolate(const Vector3 &p_b, const Vector3 &p_pre_a, const Vector3 &p_post_b, real_t p_weight) const { Vector3 res = *this; res.x = Math::cubic_interpolate(res.x, p_b.x, p_pre_a.x, p_post_b.x, p_weight); res.y = Math::cubic_interpolate(res.y, p_b.y, p_pre_a.y, p_post_b.y, p_weight); @@ -267,7 +269,7 @@ Vector3 Vector3::cubic_interpolate(const Vector3 &p_b, const Vector3 &p_pre_a, c return res; } -Vector3 Vector3::cubic_interpolate_in_time(const Vector3 &p_b, const Vector3 &p_pre_a, const Vector3 &p_post_b, const real_t p_weight, const real_t &p_b_t, const real_t &p_pre_a_t, const real_t &p_post_b_t) const { +Vector3 Vector3::cubic_interpolate_in_time(const Vector3 &p_b, const Vector3 &p_pre_a, const Vector3 &p_post_b, real_t p_weight, real_t p_b_t, real_t p_pre_a_t, real_t p_post_b_t) const { Vector3 res = *this; res.x = Math::cubic_interpolate_in_time(res.x, p_b.x, p_pre_a.x, p_post_b.x, p_weight, p_b_t, p_pre_a_t, p_post_b_t); res.y = Math::cubic_interpolate_in_time(res.y, p_b.y, p_pre_a.y, p_post_b.y, p_weight, p_b_t, p_pre_a_t, p_post_b_t); @@ -275,17 +277,20 @@ Vector3 Vector3::cubic_interpolate_in_time(const Vector3 &p_b, const Vector3 &p_ return res; } -Vector3 Vector3::bezier_interpolate(const Vector3 &p_control_1, const Vector3 &p_control_2, const Vector3 &p_end, const real_t p_t) const { +Vector3 Vector3::bezier_interpolate(const Vector3 &p_control_1, const Vector3 &p_control_2, const Vector3 &p_end, real_t p_t) const { Vector3 res = *this; + res.x = Math::bezier_interpolate(res.x, p_control_1.x, p_control_2.x, p_end.x, p_t); + res.y = Math::bezier_interpolate(res.y, p_control_1.y, p_control_2.y, p_end.y, p_t); + res.z = Math::bezier_interpolate(res.z, p_control_1.z, p_control_2.z, p_end.z, p_t); + return res; +} - /* Formula from Wikipedia article on Bezier curves. */ - real_t omt = (1.0 - p_t); - real_t omt2 = omt * omt; - real_t omt3 = omt2 * omt; - real_t t2 = p_t * p_t; - real_t t3 = t2 * p_t; - - return res * omt3 + p_control_1 * omt2 * p_t * 3.0 + p_control_2 * omt * t2 * 3.0 + p_end * t3; +Vector3 Vector3::bezier_derivative(const Vector3 &p_control_1, const Vector3 &p_control_2, const Vector3 &p_end, real_t p_t) const { + Vector3 res = *this; + res.x = Math::bezier_derivative(res.x, p_control_1.x, p_control_2.x, p_end.x, p_t); + res.y = Math::bezier_derivative(res.y, p_control_1.y, p_control_2.y, p_end.y, p_t); + res.z = Math::bezier_derivative(res.z, p_control_1.z, p_control_2.z, p_end.z, p_t); + return res; } real_t Vector3::distance_to(const Vector3 &p_to) const { @@ -296,7 +301,7 @@ real_t Vector3::distance_squared_to(const Vector3 &p_to) const { return (p_to - *this).length_squared(); } -Vector3 Vector3::posmod(const real_t p_mod) const { +Vector3 Vector3::posmod(real_t p_mod) const { return Vector3(Math::fposmod(x, p_mod), Math::fposmod(y, p_mod), Math::fposmod(z, p_mod)); } @@ -325,6 +330,16 @@ Vector3 Vector3::direction_to(const Vector3 &p_to) const { return ret; } +Vector3 Vector3::get_any_perpendicular() const { + // Return the any perpendicular vector by cross product with the Vector3.RIGHT or Vector3.UP, + // whichever has the greater angle to the current vector with the sign of each element positive. + // The only essence is "to avoid being parallel to the current vector", and there is no mathematical basis for using Vector3.RIGHT and Vector3.UP, + // since it could be a different vector depending on the prior branching code Math::abs(x) <= Math::abs(y) && Math::abs(x) <= Math::abs(z). + // However, it would be reasonable to use any of the axes of the basis, as it is simpler to calculate. + ERR_FAIL_COND_V_MSG(is_zero_approx(), Vector3(0, 0, 0), "The Vector3 must not be zero."); + return cross((Math::abs(x) <= Math::abs(y) && Math::abs(x) <= Math::abs(z)) ? Vector3(1, 0, 0) : Vector3(0, 1, 0)).normalized(); +} + /* Operators */ Vector3 &Vector3::operator+=(const Vector3 &p_v) { @@ -371,7 +386,7 @@ Vector3 Vector3::operator/(const Vector3 &p_v) const { return Vector3(x / p_v.x, y / p_v.y, z / p_v.z); } -Vector3 &Vector3::operator*=(const real_t p_scalar) { +Vector3 &Vector3::operator*=(real_t p_scalar) { x *= p_scalar; y *= p_scalar; z *= p_scalar; @@ -381,34 +396,34 @@ Vector3 &Vector3::operator*=(const real_t p_scalar) { // Multiplication operators required to workaround issues with LLVM using implicit conversion // to Vector3i instead for integers where it should not. -_FORCE_INLINE_ Vector3 operator*(const float p_scalar, const Vector3 &p_vec) { +_FORCE_INLINE_ Vector3 operator*(float p_scalar, const Vector3 &p_vec) { return p_vec * p_scalar; } -_FORCE_INLINE_ Vector3 operator*(const double p_scalar, const Vector3 &p_vec) { +_FORCE_INLINE_ Vector3 operator*(double p_scalar, const Vector3 &p_vec) { return p_vec * p_scalar; } -_FORCE_INLINE_ Vector3 operator*(const int32_t p_scalar, const Vector3 &p_vec) { +_FORCE_INLINE_ Vector3 operator*(int32_t p_scalar, const Vector3 &p_vec) { return p_vec * p_scalar; } -_FORCE_INLINE_ Vector3 operator*(const int64_t p_scalar, const Vector3 &p_vec) { +_FORCE_INLINE_ Vector3 operator*(int64_t p_scalar, const Vector3 &p_vec) { return p_vec * p_scalar; } -Vector3 Vector3::operator*(const real_t p_scalar) const { +Vector3 Vector3::operator*(real_t p_scalar) const { return Vector3(x * p_scalar, y * p_scalar, z * p_scalar); } -Vector3 &Vector3::operator/=(const real_t p_scalar) { +Vector3 &Vector3::operator/=(real_t p_scalar) { x /= p_scalar; y /= p_scalar; z /= p_scalar; return *this; } -Vector3 Vector3::operator/(const real_t p_scalar) const { +Vector3 Vector3::operator/(real_t p_scalar) const { return Vector3(x / p_scalar, y / p_scalar, z / p_scalar); } @@ -522,9 +537,9 @@ void Vector3::zero() { // slide returns the component of the vector along the given plane, specified by its normal vector. Vector3 Vector3::slide(const Vector3 &p_normal) const { #ifdef MATH_CHECKS - ERR_FAIL_COND_V_MSG(!p_normal.is_normalized(), Vector3(), "The normal Vector3 must be normalized."); + ERR_FAIL_COND_V_MSG(!p_normal.is_normalized(), Vector3(), "The normal Vector3 " + p_normal.operator String() + " must be normalized."); #endif - return *this - p_normal * this->dot(p_normal); + return *this - p_normal * dot(p_normal); } Vector3 Vector3::bounce(const Vector3 &p_normal) const { @@ -533,11 +548,9 @@ Vector3 Vector3::bounce(const Vector3 &p_normal) const { Vector3 Vector3::reflect(const Vector3 &p_normal) const { #ifdef MATH_CHECKS - ERR_FAIL_COND_V_MSG(!p_normal.is_normalized(), Vector3(), "The normal Vector3 must be normalized."); + ERR_FAIL_COND_V_MSG(!p_normal.is_normalized(), Vector3(), "The normal Vector3 " + p_normal.operator String() + " must be normalized."); #endif - return 2.0f * p_normal * this->dot(p_normal) - *this; + return 2.0f * p_normal * dot(p_normal) - *this; } } // namespace godot - -#endif // GODOT_VECTOR3_HPP diff --git a/include/godot_cpp/variant/vector3i.hpp b/include/godot_cpp/variant/vector3i.hpp index e955bc12..18881812 100644 --- a/include/godot_cpp/variant/vector3i.hpp +++ b/include/godot_cpp/variant/vector3i.hpp @@ -30,8 +30,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ -#ifndef GODOT_VECTOR3I_HPP -#define GODOT_VECTOR3I_HPP +#pragma once #include #include @@ -60,12 +59,12 @@ struct [[nodiscard]] Vector3i { int32_t coord[3] = { 0 }; }; - _FORCE_INLINE_ const int32_t &operator[](const int p_axis) const { + _FORCE_INLINE_ const int32_t &operator[](int p_axis) const { DEV_ASSERT((unsigned int)p_axis < 3); return coord[p_axis]; } - _FORCE_INLINE_ int32_t &operator[](const int p_axis) { + _FORCE_INLINE_ int32_t &operator[](int p_axis) { DEV_ASSERT((unsigned int)p_axis < 3); return coord[p_axis]; } @@ -92,17 +91,17 @@ struct [[nodiscard]] Vector3i { _FORCE_INLINE_ int64_t length_squared() const; _FORCE_INLINE_ double length() const; - _FORCE_INLINE_ int64_t distance_squared_to(const Vector3i &p_to) const; - _FORCE_INLINE_ double distance_to(const Vector3i &p_to) const; - _FORCE_INLINE_ void zero(); _FORCE_INLINE_ Vector3i abs() const; _FORCE_INLINE_ Vector3i sign() const; - Vector3i snapped(const Vector3i &p_step) const; - Vector3i snappedi(int32_t p_step) const; Vector3i clamp(const Vector3i &p_min, const Vector3i &p_max) const; Vector3i clampi(int32_t p_min, int32_t p_max) const; + Vector3i snapped(const Vector3i &p_step) const; + Vector3i snappedi(int32_t p_step) const; + + _FORCE_INLINE_ double distance_to(const Vector3i &p_to) const; + _FORCE_INLINE_ int64_t distance_squared_to(const Vector3i &p_to) const; /* Operators */ @@ -117,12 +116,12 @@ struct [[nodiscard]] Vector3i { _FORCE_INLINE_ Vector3i &operator%=(const Vector3i &p_v); _FORCE_INLINE_ Vector3i operator%(const Vector3i &p_v) const; - _FORCE_INLINE_ Vector3i &operator*=(const int32_t p_scalar); - _FORCE_INLINE_ Vector3i operator*(const int32_t p_scalar) const; - _FORCE_INLINE_ Vector3i &operator/=(const int32_t p_scalar); - _FORCE_INLINE_ Vector3i operator/(const int32_t p_scalar) const; - _FORCE_INLINE_ Vector3i &operator%=(const int32_t p_scalar); - _FORCE_INLINE_ Vector3i operator%(const int32_t p_scalar) const; + _FORCE_INLINE_ Vector3i &operator*=(int32_t p_scalar); + _FORCE_INLINE_ Vector3i operator*(int32_t p_scalar) const; + _FORCE_INLINE_ Vector3i &operator/=(int32_t p_scalar); + _FORCE_INLINE_ Vector3i operator/(int32_t p_scalar) const; + _FORCE_INLINE_ Vector3i &operator%=(int32_t p_scalar); + _FORCE_INLINE_ Vector3i operator%(int32_t p_scalar) const; _FORCE_INLINE_ Vector3i operator-() const; @@ -137,7 +136,7 @@ struct [[nodiscard]] Vector3i { operator Vector3() const; _FORCE_INLINE_ Vector3i() {} - _FORCE_INLINE_ Vector3i(const int32_t p_x, const int32_t p_y, const int32_t p_z) { + _FORCE_INLINE_ Vector3i(int32_t p_x, int32_t p_y, int32_t p_z) { x = p_x; y = p_y; z = p_z; @@ -152,14 +151,6 @@ double Vector3i::length() const { return Math::sqrt((double)length_squared()); } -int64_t Vector3i::distance_squared_to(const Vector3i &p_to) const { - return (p_to - *this).length_squared(); -} - -double Vector3i::distance_to(const Vector3i &p_to) const { - return (p_to - *this).length(); -} - Vector3i Vector3i::abs() const { return Vector3i(Math::abs(x), Math::abs(y), Math::abs(z)); } @@ -168,6 +159,14 @@ Vector3i Vector3i::sign() const { return Vector3i(SIGN(x), SIGN(y), SIGN(z)); } +double Vector3i::distance_to(const Vector3i &p_to) const { + return (p_to - *this).length(); +} + +int64_t Vector3i::distance_squared_to(const Vector3i &p_to) const { + return (p_to - *this).length_squared(); +} + /* Operators */ Vector3i &Vector3i::operator+=(const Vector3i &p_v) { @@ -225,54 +224,54 @@ Vector3i Vector3i::operator%(const Vector3i &p_v) const { return Vector3i(x % p_v.x, y % p_v.y, z % p_v.z); } -Vector3i &Vector3i::operator*=(const int32_t p_scalar) { +Vector3i &Vector3i::operator*=(int32_t p_scalar) { x *= p_scalar; y *= p_scalar; z *= p_scalar; return *this; } -Vector3i Vector3i::operator*(const int32_t p_scalar) const { +Vector3i Vector3i::operator*(int32_t p_scalar) const { return Vector3i(x * p_scalar, y * p_scalar, z * p_scalar); } // Multiplication operators required to workaround issues with LLVM using implicit conversion. -_FORCE_INLINE_ Vector3i operator*(const int32_t p_scalar, const Vector3i &p_vector) { +_FORCE_INLINE_ Vector3i operator*(int32_t p_scalar, const Vector3i &p_vector) { return p_vector * p_scalar; } -_FORCE_INLINE_ Vector3i operator*(const int64_t p_scalar, const Vector3i &p_vector) { +_FORCE_INLINE_ Vector3i operator*(int64_t p_scalar, const Vector3i &p_vector) { return p_vector * p_scalar; } -_FORCE_INLINE_ Vector3i operator*(const float p_scalar, const Vector3i &p_vector) { +_FORCE_INLINE_ Vector3i operator*(float p_scalar, const Vector3i &p_vector) { return p_vector * p_scalar; } -_FORCE_INLINE_ Vector3i operator*(const double p_scalar, const Vector3i &p_vector) { +_FORCE_INLINE_ Vector3i operator*(double p_scalar, const Vector3i &p_vector) { return p_vector * p_scalar; } -Vector3i &Vector3i::operator/=(const int32_t p_scalar) { +Vector3i &Vector3i::operator/=(int32_t p_scalar) { x /= p_scalar; y /= p_scalar; z /= p_scalar; return *this; } -Vector3i Vector3i::operator/(const int32_t p_scalar) const { +Vector3i Vector3i::operator/(int32_t p_scalar) const { return Vector3i(x / p_scalar, y / p_scalar, z / p_scalar); } -Vector3i &Vector3i::operator%=(const int32_t p_scalar) { +Vector3i &Vector3i::operator%=(int32_t p_scalar) { x %= p_scalar; y %= p_scalar; z %= p_scalar; return *this; } -Vector3i Vector3i::operator%(const int32_t p_scalar) const { +Vector3i Vector3i::operator%(int32_t p_scalar) const { return Vector3i(x % p_scalar, y % p_scalar, z % p_scalar); } @@ -341,5 +340,3 @@ void Vector3i::zero() { } } // namespace godot - -#endif // GODOT_VECTOR3I_HPP diff --git a/include/godot_cpp/variant/vector4.hpp b/include/godot_cpp/variant/vector4.hpp index 86b827f2..467eec51 100644 --- a/include/godot_cpp/variant/vector4.hpp +++ b/include/godot_cpp/variant/vector4.hpp @@ -30,8 +30,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ -#ifndef GODOT_VECTOR4_HPP -#define GODOT_VECTOR4_HPP +#pragma once #include #include @@ -39,6 +38,7 @@ namespace godot { class String; +struct Vector4i; struct [[nodiscard]] Vector4 { static const int AXIS_COUNT = 4; @@ -57,15 +57,14 @@ struct [[nodiscard]] Vector4 { real_t z; real_t w; }; - [[deprecated("Use coord instead")]] real_t components[4]; real_t coord[4] = { 0, 0, 0, 0 }; }; - _FORCE_INLINE_ real_t &operator[](const int p_axis) { + _FORCE_INLINE_ real_t &operator[](int p_axis) { DEV_ASSERT((unsigned int)p_axis < 4); return coord[p_axis]; } - _FORCE_INLINE_ const real_t &operator[](const int p_axis) const { + _FORCE_INLINE_ const real_t &operator[](int p_axis) const { DEV_ASSERT((unsigned int)p_axis < 4); return coord[p_axis]; } @@ -107,11 +106,11 @@ struct [[nodiscard]] Vector4 { Vector4 floor() const; Vector4 ceil() const; Vector4 round() const; - Vector4 lerp(const Vector4 &p_to, const real_t p_weight) const; - Vector4 cubic_interpolate(const Vector4 &p_b, const Vector4 &p_pre_a, const Vector4 &p_post_b, const real_t p_weight) const; - Vector4 cubic_interpolate_in_time(const Vector4 &p_b, const Vector4 &p_pre_a, const Vector4 &p_post_b, const real_t p_weight, const real_t &p_b_t, const real_t &p_pre_a_t, const real_t &p_post_b_t) const; + Vector4 lerp(const Vector4 &p_to, real_t p_weight) const; + Vector4 cubic_interpolate(const Vector4 &p_b, const Vector4 &p_pre_a, const Vector4 &p_post_b, real_t p_weight) const; + Vector4 cubic_interpolate_in_time(const Vector4 &p_b, const Vector4 &p_pre_a, const Vector4 &p_post_b, real_t p_weight, real_t p_b_t, real_t p_pre_a_t, real_t p_post_b_t) const; - Vector4 posmod(const real_t p_mod) const; + Vector4 posmod(real_t p_mod) const; Vector4 posmodv(const Vector4 &p_modv) const; void snap(const Vector4 &p_step); void snapf(real_t p_step); @@ -127,15 +126,15 @@ struct [[nodiscard]] Vector4 { _FORCE_INLINE_ void operator-=(const Vector4 &p_vec4); _FORCE_INLINE_ void operator*=(const Vector4 &p_vec4); _FORCE_INLINE_ void operator/=(const Vector4 &p_vec4); - _FORCE_INLINE_ void operator*=(const real_t &s); - _FORCE_INLINE_ void operator/=(const real_t &s); + _FORCE_INLINE_ void operator*=(real_t p_s); + _FORCE_INLINE_ void operator/=(real_t p_s); _FORCE_INLINE_ Vector4 operator+(const Vector4 &p_vec4) const; _FORCE_INLINE_ Vector4 operator-(const Vector4 &p_vec4) const; _FORCE_INLINE_ Vector4 operator*(const Vector4 &p_vec4) const; _FORCE_INLINE_ Vector4 operator/(const Vector4 &p_vec4) const; _FORCE_INLINE_ Vector4 operator-() const; - _FORCE_INLINE_ Vector4 operator*(const real_t &s) const; - _FORCE_INLINE_ Vector4 operator/(const real_t &s) const; + _FORCE_INLINE_ Vector4 operator*(real_t p_s) const; + _FORCE_INLINE_ Vector4 operator/(real_t p_s) const; _FORCE_INLINE_ bool operator==(const Vector4 &p_vec4) const; _FORCE_INLINE_ bool operator!=(const Vector4 &p_vec4) const; @@ -145,28 +144,14 @@ struct [[nodiscard]] Vector4 { _FORCE_INLINE_ bool operator<=(const Vector4 &p_vec4) const; operator String() const; + operator Vector4i() const; _FORCE_INLINE_ Vector4() {} - - _FORCE_INLINE_ Vector4(real_t p_x, real_t p_y, real_t p_z, real_t p_w) : - x(p_x), - y(p_y), - z(p_z), - w(p_w) { - } - - Vector4(const Vector4 &p_vec4) : - x(p_vec4.x), - y(p_vec4.y), - z(p_vec4.z), - w(p_vec4.w) { - } - - void operator=(const Vector4 &p_vec4) { - x = p_vec4.x; - y = p_vec4.y; - z = p_vec4.z; - w = p_vec4.w; + _FORCE_INLINE_ Vector4(real_t p_x, real_t p_y, real_t p_z, real_t p_w) { + x = p_x; + y = p_y; + z = p_z; + w = p_w; } }; @@ -205,15 +190,15 @@ void Vector4::operator/=(const Vector4 &p_vec4) { z /= p_vec4.z; w /= p_vec4.w; } -void Vector4::operator*=(const real_t &s) { - x *= s; - y *= s; - z *= s; - w *= s; +void Vector4::operator*=(real_t p_s) { + x *= p_s; + y *= p_s; + z *= p_s; + w *= p_s; } -void Vector4::operator/=(const real_t &s) { - *this *= 1.0f / s; +void Vector4::operator/=(real_t p_s) { + *this *= 1.0f / p_s; } Vector4 Vector4::operator+(const Vector4 &p_vec4) const { @@ -236,12 +221,12 @@ Vector4 Vector4::operator-() const { return Vector4(-x, -y, -z, -w); } -Vector4 Vector4::operator*(const real_t &s) const { - return Vector4(x * s, y * s, z * s, w * s); +Vector4 Vector4::operator*(real_t p_s) const { + return Vector4(x * p_s, y * p_s, z * p_s, w * p_s); } -Vector4 Vector4::operator/(const real_t &s) const { - return *this * (1.0f / s); +Vector4 Vector4::operator/(real_t p_s) const { + return *this * (1.0f / p_s); } bool Vector4::operator==(const Vector4 &p_vec4) const { @@ -304,22 +289,20 @@ bool Vector4::operator>=(const Vector4 &p_v) const { return x > p_v.x; } -_FORCE_INLINE_ Vector4 operator*(const float p_scalar, const Vector4 &p_vec) { +_FORCE_INLINE_ Vector4 operator*(float p_scalar, const Vector4 &p_vec) { return p_vec * p_scalar; } -_FORCE_INLINE_ Vector4 operator*(const double p_scalar, const Vector4 &p_vec) { +_FORCE_INLINE_ Vector4 operator*(double p_scalar, const Vector4 &p_vec) { return p_vec * p_scalar; } -_FORCE_INLINE_ Vector4 operator*(const int32_t p_scalar, const Vector4 &p_vec) { +_FORCE_INLINE_ Vector4 operator*(int32_t p_scalar, const Vector4 &p_vec) { return p_vec * p_scalar; } -_FORCE_INLINE_ Vector4 operator*(const int64_t p_scalar, const Vector4 &p_vec) { +_FORCE_INLINE_ Vector4 operator*(int64_t p_scalar, const Vector4 &p_vec) { return p_vec * p_scalar; } } // namespace godot - -#endif // GODOT_VECTOR4_HPP diff --git a/include/godot_cpp/variant/vector4i.hpp b/include/godot_cpp/variant/vector4i.hpp index e9a36fd7..2efc2e3e 100644 --- a/include/godot_cpp/variant/vector4i.hpp +++ b/include/godot_cpp/variant/vector4i.hpp @@ -30,8 +30,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ -#ifndef GODOT_VECTOR4I_HPP -#define GODOT_VECTOR4I_HPP +#pragma once #include #include @@ -62,12 +61,12 @@ struct [[nodiscard]] Vector4i { int32_t coord[4] = { 0 }; }; - _FORCE_INLINE_ const int32_t &operator[](const int p_axis) const { + _FORCE_INLINE_ const int32_t &operator[](int p_axis) const { DEV_ASSERT((unsigned int)p_axis < 4); return coord[p_axis]; } - _FORCE_INLINE_ int32_t &operator[](const int p_axis) { + _FORCE_INLINE_ int32_t &operator[](int p_axis) { DEV_ASSERT((unsigned int)p_axis < 4); return coord[p_axis]; } @@ -94,17 +93,17 @@ struct [[nodiscard]] Vector4i { _FORCE_INLINE_ int64_t length_squared() const; _FORCE_INLINE_ double length() const; - _FORCE_INLINE_ int64_t distance_squared_to(const Vector4i &p_to) const; - _FORCE_INLINE_ double distance_to(const Vector4i &p_to) const; - _FORCE_INLINE_ void zero(); + _FORCE_INLINE_ double distance_to(const Vector4i &p_to) const; + _FORCE_INLINE_ int64_t distance_squared_to(const Vector4i &p_to) const; + _FORCE_INLINE_ Vector4i abs() const; _FORCE_INLINE_ Vector4i sign() const; - Vector4i snapped(const Vector4i &p_step) const; - Vector4i snappedi(int32_t p_step) const; Vector4i clamp(const Vector4i &p_min, const Vector4i &p_max) const; Vector4i clampi(int32_t p_min, int32_t p_max) const; + Vector4i snapped(const Vector4i &p_step) const; + Vector4i snappedi(int32_t p_step) const; /* Operators */ @@ -119,12 +118,12 @@ struct [[nodiscard]] Vector4i { _FORCE_INLINE_ Vector4i &operator%=(const Vector4i &p_v); _FORCE_INLINE_ Vector4i operator%(const Vector4i &p_v) const; - _FORCE_INLINE_ Vector4i &operator*=(const int32_t p_scalar); - _FORCE_INLINE_ Vector4i operator*(const int32_t p_scalar) const; - _FORCE_INLINE_ Vector4i &operator/=(const int32_t p_scalar); - _FORCE_INLINE_ Vector4i operator/(const int32_t p_scalar) const; - _FORCE_INLINE_ Vector4i &operator%=(const int32_t p_scalar); - _FORCE_INLINE_ Vector4i operator%(const int32_t p_scalar) const; + _FORCE_INLINE_ Vector4i &operator*=(int32_t p_scalar); + _FORCE_INLINE_ Vector4i operator*(int32_t p_scalar) const; + _FORCE_INLINE_ Vector4i &operator/=(int32_t p_scalar); + _FORCE_INLINE_ Vector4i operator/(int32_t p_scalar) const; + _FORCE_INLINE_ Vector4i &operator%=(int32_t p_scalar); + _FORCE_INLINE_ Vector4i operator%(int32_t p_scalar) const; _FORCE_INLINE_ Vector4i operator-() const; @@ -140,7 +139,7 @@ struct [[nodiscard]] Vector4i { _FORCE_INLINE_ Vector4i() {} Vector4i(const Vector4 &p_vec4); - _FORCE_INLINE_ Vector4i(const int32_t p_x, const int32_t p_y, const int32_t p_z, const int32_t p_w) { + _FORCE_INLINE_ Vector4i(int32_t p_x, int32_t p_y, int32_t p_z, int32_t p_w) { x = p_x; y = p_y; z = p_z; @@ -156,20 +155,20 @@ double Vector4i::length() const { return Math::sqrt((double)length_squared()); } -int64_t Vector4i::distance_squared_to(const Vector4i &p_to) const { - return (p_to - *this).length_squared(); -} - double Vector4i::distance_to(const Vector4i &p_to) const { return (p_to - *this).length(); } +int64_t Vector4i::distance_squared_to(const Vector4i &p_to) const { + return (p_to - *this).length_squared(); +} + Vector4i Vector4i::abs() const { return Vector4i(Math::abs(x), Math::abs(y), Math::abs(z), Math::abs(w)); } Vector4i Vector4i::sign() const { - return Vector4i(Math::sign(x), Math::sign(y), Math::sign(z), Math::sign(w)); + return Vector4i(SIGN(x), SIGN(y), SIGN(z), SIGN(w)); } /* Operators */ @@ -234,7 +233,7 @@ Vector4i Vector4i::operator%(const Vector4i &p_v) const { return Vector4i(x % p_v.x, y % p_v.y, z % p_v.z, w % p_v.w); } -Vector4i &Vector4i::operator*=(const int32_t p_scalar) { +Vector4i &Vector4i::operator*=(int32_t p_scalar) { x *= p_scalar; y *= p_scalar; z *= p_scalar; @@ -242,29 +241,29 @@ Vector4i &Vector4i::operator*=(const int32_t p_scalar) { return *this; } -Vector4i Vector4i::operator*(const int32_t p_scalar) const { +Vector4i Vector4i::operator*(int32_t p_scalar) const { return Vector4i(x * p_scalar, y * p_scalar, z * p_scalar, w * p_scalar); } // Multiplication operators required to workaround issues with LLVM using implicit conversion. -_FORCE_INLINE_ Vector4i operator*(const int32_t p_scalar, const Vector4i &p_vector) { +_FORCE_INLINE_ Vector4i operator*(int32_t p_scalar, const Vector4i &p_vector) { return p_vector * p_scalar; } -_FORCE_INLINE_ Vector4i operator*(const int64_t p_scalar, const Vector4i &p_vector) { +_FORCE_INLINE_ Vector4i operator*(int64_t p_scalar, const Vector4i &p_vector) { return p_vector * p_scalar; } -_FORCE_INLINE_ Vector4i operator*(const float p_scalar, const Vector4i &p_vector) { +_FORCE_INLINE_ Vector4i operator*(float p_scalar, const Vector4i &p_vector) { return p_vector * p_scalar; } -_FORCE_INLINE_ Vector4i operator*(const double p_scalar, const Vector4i &p_vector) { +_FORCE_INLINE_ Vector4i operator*(double p_scalar, const Vector4i &p_vector) { return p_vector * p_scalar; } -Vector4i &Vector4i::operator/=(const int32_t p_scalar) { +Vector4i &Vector4i::operator/=(int32_t p_scalar) { x /= p_scalar; y /= p_scalar; z /= p_scalar; @@ -272,11 +271,11 @@ Vector4i &Vector4i::operator/=(const int32_t p_scalar) { return *this; } -Vector4i Vector4i::operator/(const int32_t p_scalar) const { +Vector4i Vector4i::operator/(int32_t p_scalar) const { return Vector4i(x / p_scalar, y / p_scalar, z / p_scalar, w / p_scalar); } -Vector4i &Vector4i::operator%=(const int32_t p_scalar) { +Vector4i &Vector4i::operator%=(int32_t p_scalar) { x %= p_scalar; y %= p_scalar; z %= p_scalar; @@ -284,7 +283,7 @@ Vector4i &Vector4i::operator%=(const int32_t p_scalar) { return *this; } -Vector4i Vector4i::operator%(const int32_t p_scalar) const { +Vector4i Vector4i::operator%(int32_t p_scalar) const { return Vector4i(x % p_scalar, y % p_scalar, z % p_scalar, w % p_scalar); } @@ -369,5 +368,3 @@ void Vector4i::zero() { } } // namespace godot - -#endif // GODOT_VECTOR4I_HPP diff --git a/misc/scripts/check_get_file_list.py b/misc/scripts/check_get_file_list.py index ac90777a..6ea5d6f7 100755 --- a/misc/scripts/check_get_file_list.py +++ b/misc/scripts/check_get_file_list.py @@ -19,6 +19,7 @@ def test(profile_filepath=""): api = generate_trimmed_api(api_filepath, profile_filepath) _generate_bindings( api, + api_filepath, use_template_get_node=False, bits=bits, precision=precision, diff --git a/misc/scripts/header_guards.py b/misc/scripts/header_guards.py index 15672d38..63a6b75f 100644 --- a/misc/scripts/header_guards.py +++ b/misc/scripts/header_guards.py @@ -2,121 +2,82 @@ # -*- coding: utf-8 -*- import sys -from pathlib import Path if len(sys.argv) < 2: print("Invalid usage of header_guards.py, it should be called with a path to one or multiple files.") sys.exit(1) -HEADER_CHECK_OFFSET = 32 -HEADER_BEGIN_OFFSET = 33 -HEADER_END_OFFSET = -1 - changed = [] invalid = [] for file in sys.argv[1:]: - with open(file, "rt", encoding="utf-8", newline="\n") as f: - lines = f.readlines() + header_start = -1 + header_end = -1 - if len(lines) <= HEADER_BEGIN_OFFSET: - continue # Most likely a dummy file. + with open(file.strip(), "rt", encoding="utf-8", newline="\n") as f: + lines = f.readlines() - if lines[HEADER_CHECK_OFFSET].startswith("#import"): - continue # Early catch obj-c file. + for idx, line in enumerate(lines): + sline = line.strip() + + if header_start < 0: + if sline == "": # Skip empty lines at the top. + continue + + if sline.startswith("/**********"): # Godot header starts this way. + header_start = idx + else: + header_end = 0 # There is no Godot header. + break + else: + if not sline.startswith(("*", "/*")): # Not in the Godot header anymore. + header_end = idx + 1 # The guard should be two lines below the Godot header. + break + + if (HEADER_CHECK_OFFSET := header_end) < 0 or HEADER_CHECK_OFFSET >= len(lines): + invalid.append(file) + continue - name = f"GODOT_{Path(file).name}".upper().replace(".", "_").replace("-", "_").replace(" ", "_") + if lines[HEADER_CHECK_OFFSET].startswith("#pragma once"): + continue - HEADER_CHECK = f"#ifndef {name}\n" - HEADER_BEGIN = f"#define {name}\n" - HEADER_END = f"#endif // {name}\n" + # Might be using legacy header guards. + HEADER_BEGIN_OFFSET = HEADER_CHECK_OFFSET + 1 + HEADER_END_OFFSET = len(lines) - 1 - if ( - lines[HEADER_CHECK_OFFSET] == HEADER_CHECK - and lines[HEADER_BEGIN_OFFSET] == HEADER_BEGIN - and lines[HEADER_END_OFFSET] == HEADER_END - ): + if HEADER_BEGIN_OFFSET >= HEADER_END_OFFSET: + invalid.append(file) continue - # Guards might exist but with the wrong names. if ( lines[HEADER_CHECK_OFFSET].startswith("#ifndef") and lines[HEADER_BEGIN_OFFSET].startswith("#define") and lines[HEADER_END_OFFSET].startswith("#endif") ): - lines[HEADER_CHECK_OFFSET] = HEADER_CHECK - lines[HEADER_BEGIN_OFFSET] = HEADER_BEGIN - lines[HEADER_END_OFFSET] = HEADER_END + lines[HEADER_CHECK_OFFSET] = "#pragma once" + lines[HEADER_BEGIN_OFFSET] = "\n" + lines.pop() with open(file, "wt", encoding="utf-8", newline="\n") as f: f.writelines(lines) changed.append(file) continue - header_check = -1 - header_begin = -1 - header_end = -1 - pragma_once = -1 - objc = False - - for idx, line in enumerate(lines): - if not line.startswith("#"): - continue - elif line.startswith("#ifndef") and header_check == -1: - header_check = idx - elif line.startswith("#define") and header_begin == -1: - header_begin = idx - elif line.startswith("#endif") and header_end == -1: - header_end = idx - elif line.startswith("#pragma once"): - pragma_once = idx + # Verify `#pragma once` doesn't exist at invalid location. + misplaced = False + for line in lines: + if line.startswith("#pragma once"): + misplaced = True break - elif line.startswith("#import"): - objc = True - break - - if objc: - continue - if pragma_once != -1: - lines.pop(pragma_once) - lines.insert(HEADER_CHECK_OFFSET, HEADER_CHECK) - lines.insert(HEADER_BEGIN_OFFSET, HEADER_BEGIN) - lines.append("\n") - lines.append(HEADER_END) - with open(file, "wt", encoding="utf-8", newline="\n") as f: - f.writelines(lines) - changed.append(file) - continue - - if header_check == -1 and header_begin == -1 and header_end == -1: - # Guards simply didn't exist - lines.insert(HEADER_CHECK_OFFSET, HEADER_CHECK) - lines.insert(HEADER_BEGIN_OFFSET, HEADER_BEGIN) - lines.append("\n") - lines.append(HEADER_END) - with open(file, "wt", encoding="utf-8", newline="\n") as f: - f.writelines(lines) - changed.append(file) + if misplaced: + invalid.append(file) continue - if header_check != -1 and header_begin != -1 and header_end != -1: - # All prepends "found", see if we can salvage this. - if header_check == header_begin - 1 and header_begin < header_end: - lines.pop(header_check) - lines.pop(header_begin - 1) - lines.pop(header_end - 2) - if lines[header_end - 3] == "\n": - lines.pop(header_end - 3) - lines.insert(HEADER_CHECK_OFFSET, HEADER_CHECK) - lines.insert(HEADER_BEGIN_OFFSET, HEADER_BEGIN) - lines.append("\n") - lines.append(HEADER_END) - with open(file, "wt", encoding="utf-8", newline="\n") as f: - f.writelines(lines) - changed.append(file) - continue - - invalid.append(file) + # Assume that we're simply missing a guard entirely. + lines.insert(HEADER_CHECK_OFFSET, "#pragma once\n\n") + with open(file, "wt", encoding="utf-8", newline="\n") as f: + f.writelines(lines) + changed.append(file) if changed: for file in changed: diff --git a/src/core/class_db.cpp b/src/core/class_db.cpp index 521a5817..bec51f49 100644 --- a/src/core/class_db.cpp +++ b/src/core/class_db.cpp @@ -390,6 +390,15 @@ void ClassDB::add_virtual_method(const StringName &p_class, const MethodInfo &p_ } } +void ClassDB::_editor_get_classes_used_callback(GDExtensionTypePtr p_packed_string_array) { + PackedStringArray *arr = reinterpret_cast(p_packed_string_array); + arr->resize(instance_binding_callbacks.size()); + int index = 0; + for (const std::pair &pair : instance_binding_callbacks) { + (*arr)[index++] = pair.first; + } +} + void ClassDB::initialize_class(const ClassInfo &p_cl) { } diff --git a/src/godot.cpp b/src/godot.cpp index 70a02962..953b42b1 100644 --- a/src/godot.cpp +++ b/src/godot.cpp @@ -206,6 +206,7 @@ GDExtensionInterfaceClassdbUnregisterExtensionClass gdextension_interface_classd GDExtensionInterfaceGetLibraryPath gdextension_interface_get_library_path = nullptr; GDExtensionInterfaceEditorAddPlugin gdextension_interface_editor_add_plugin = nullptr; GDExtensionInterfaceEditorRemovePlugin gdextension_interface_editor_remove_plugin = nullptr; +GDExtensionInterfaceEditorRegisterGetClassesUsedCallback gdextension_interface_editor_register_get_classes_used_callback = nullptr; GDExtensionsInterfaceEditorHelpLoadXmlFromUtf8Chars gdextension_interface_editor_help_load_xml_from_utf8_chars = nullptr; GDExtensionsInterfaceEditorHelpLoadXmlFromUtf8CharsAndLen gdextension_interface_editor_help_load_xml_from_utf8_chars_and_len = nullptr; GDExtensionInterfaceImagePtrw gdextension_interface_image_ptrw = nullptr; @@ -488,6 +489,7 @@ GDExtensionBool GDExtensionBinding::init(GDExtensionInterfaceGetProcAddress p_ge LOAD_PROC_ADDRESS(get_library_path, GDExtensionInterfaceGetLibraryPath); LOAD_PROC_ADDRESS(editor_add_plugin, GDExtensionInterfaceEditorAddPlugin); LOAD_PROC_ADDRESS(editor_remove_plugin, GDExtensionInterfaceEditorRemovePlugin); + LOAD_PROC_ADDRESS(editor_register_get_classes_used_callback, GDExtensionInterfaceEditorRegisterGetClassesUsedCallback); LOAD_PROC_ADDRESS(editor_help_load_xml_from_utf8_chars, GDExtensionsInterfaceEditorHelpLoadXmlFromUtf8Chars); LOAD_PROC_ADDRESS(editor_help_load_xml_from_utf8_chars_and_len, GDExtensionsInterfaceEditorHelpLoadXmlFromUtf8CharsAndLen); LOAD_PROC_ADDRESS(image_ptrw, GDExtensionInterfaceImagePtrw); @@ -523,6 +525,8 @@ void GDExtensionBinding::initialize_level(void *p_userdata, GDExtensionInitializ level_initialized[p_level]++; if ((ModuleInitializationLevel)p_level == MODULE_INITIALIZATION_LEVEL_EDITOR) { + internal::gdextension_interface_editor_register_get_classes_used_callback(internal::library, &ClassDB::_editor_get_classes_used_callback); + const internal::DocData &doc_data = internal::get_doc_data(); if (doc_data.is_valid()) { doc_data.load_data(); diff --git a/src/variant/aabb.cpp b/src/variant/aabb.cpp index 66de9c69..17ae8663 100644 --- a/src/variant/aabb.cpp +++ b/src/variant/aabb.cpp @@ -121,55 +121,75 @@ AABB AABB::intersection(const AABB &p_aabb) const { return AABB(min, max - min); } -bool AABB::intersects_ray(const Vector3 &p_from, const Vector3 &p_dir, Vector3 *r_clip, Vector3 *r_normal) const { +// Note that this routine returns the BACKTRACKED (i.e. behind the ray origin) +// intersection point + normal if INSIDE the AABB. +// The caller can therefore decide when INSIDE whether to use the +// backtracked intersection, or use p_from as the intersection, and +// carry on progressing without e.g. reflecting against the normal. +bool AABB::find_intersects_ray(const Vector3 &p_from, const Vector3 &p_dir, bool &r_inside, Vector3 *r_intersection_point, Vector3 *r_normal) const { #ifdef MATH_CHECKS if (unlikely(size.x < 0 || size.y < 0 || size.z < 0)) { ERR_PRINT("AABB size is negative, this is not supported. Use AABB.abs() to get an AABB with a positive size."); } #endif - Vector3 c1, c2; Vector3 end = position + size; - real_t near = -1e20; - real_t far = 1e20; + real_t tmin = -1e20; + real_t tmax = 1e20; int axis = 0; + // Make sure r_inside is always initialized, + // to prevent reading uninitialized data in the client code. + r_inside = false; + for (int i = 0; i < 3; i++) { if (p_dir[i] == 0) { if ((p_from[i] < position[i]) || (p_from[i] > end[i])) { return false; } } else { // ray not parallel to planes in this direction - c1[i] = (position[i] - p_from[i]) / p_dir[i]; - c2[i] = (end[i] - p_from[i]) / p_dir[i]; + real_t t1 = (position[i] - p_from[i]) / p_dir[i]; + real_t t2 = (end[i] - p_from[i]) / p_dir[i]; - if (c1[i] > c2[i]) { - SWAP(c1, c2); + if (t1 > t2) { + SWAP(t1, t2); } - if (c1[i] > near) { - near = c1[i]; + if (t1 >= tmin) { + tmin = t1; axis = i; } - if (c2[i] < far) { - far = c2[i]; + if (t2 < tmax) { + if (t2 < 0) { + return false; + } + tmax = t2; } - if ((near > far) || (far < 0)) { + if (tmin > tmax) { return false; } } } - if (r_clip) { - *r_clip = c1; + // Did the ray start from inside the box? + // In which case the intersection returned is the point of entry + // (behind the ray start) or the calling routine can use the ray origin as intersection point. + r_inside = tmin < 0; + + if (r_intersection_point) { + *r_intersection_point = p_from + p_dir * tmin; + + // Prevent float error by making sure the point is exactly + // on the AABB border on the relevant axis. + r_intersection_point->coord[axis] = (p_dir[axis] >= 0) ? position.coord[axis] : end.coord[axis]; } if (r_normal) { *r_normal = Vector3(); - (*r_normal)[axis] = p_dir[axis] ? -1 : 1; + (*r_normal)[axis] = (p_dir[axis] >= 0) ? -1 : 1; } return true; } -bool AABB::intersects_segment(const Vector3 &p_from, const Vector3 &p_to, Vector3 *r_clip, Vector3 *r_normal) const { +bool AABB::intersects_segment(const Vector3 &p_from, const Vector3 &p_to, Vector3 *r_intersection_point, Vector3 *r_normal) const { #ifdef MATH_CHECKS if (unlikely(size.x < 0 || size.y < 0 || size.z < 0)) { ERR_PRINT("AABB size is negative, this is not supported. Use AABB.abs() to get an AABB with a positive size."); @@ -227,8 +247,8 @@ bool AABB::intersects_segment(const Vector3 &p_from, const Vector3 &p_to, Vector *r_normal = normal; } - if (r_clip) { - *r_clip = p_from + rel * min; + if (r_intersection_point) { + *r_intersection_point = p_from + rel * min; } return true; @@ -414,7 +434,15 @@ Variant AABB::intersects_segment_bind(const Vector3 &p_from, const Vector3 &p_to Variant AABB::intersects_ray_bind(const Vector3 &p_from, const Vector3 &p_dir) const { Vector3 inters; - if (intersects_ray(p_from, p_dir, &inters)) { + bool inside = false; + + if (find_intersects_ray(p_from, p_dir, inside, &inters)) { + // When inside the intersection point may be BEHIND the ray, + // so for general use we return the ray origin. + if (inside) { + return p_from; + } + return inters; } return Variant(); diff --git a/src/variant/basis.cpp b/src/variant/basis.cpp index ba91e93b..8995b7ec 100644 --- a/src/variant/basis.cpp +++ b/src/variant/basis.cpp @@ -31,31 +31,17 @@ /**************************************************************************/ #include +#include #include #include +using namespace godot; + #define cofac(row1, col1, row2, col2) \ (rows[row1][col1] * rows[row2][col2] - rows[row1][col2] * rows[row2][col1]) namespace godot { -void Basis::from_z(const Vector3 &p_z) { - if (Math::abs(p_z.z) > (real_t)Math_SQRT12) { - // choose p in y-z plane - real_t a = p_z[1] * p_z[1] + p_z[2] * p_z[2]; - real_t k = 1.0f / Math::sqrt(a); - rows[0] = Vector3(0, -p_z[2] * k, p_z[1] * k); - rows[1] = Vector3(a * k, -p_z[0] * rows[0][2], p_z[0] * rows[0][1]); - } else { - // choose p in x-y plane - real_t a = p_z.x * p_z.x + p_z.y * p_z.y; - real_t k = 1.0f / Math::sqrt(a); - rows[0] = Vector3(-p_z.y * k, p_z.x * k, 0); - rows[1] = Vector3(-p_z.z * rows[0].y, p_z.z * rows[0].x, a * k); - } - rows[2] = p_z; -} - void Basis::invert() { real_t co[3] = { cofac(1, 1, 2, 2), cofac(1, 2, 2, 0), cofac(1, 0, 2, 1) @@ -109,13 +95,35 @@ Basis Basis::orthogonalized() const { return c; } +// Returns true if the basis vectors are orthogonal (perpendicular), so it has no skew or shear, and can be decomposed into rotation and scale. +// See https://en.wikipedia.org/wiki/Orthogonal_basis bool Basis::is_orthogonal() const { - Basis identity; - Basis m = (*this) * transposed(); + const Vector3 x = get_column(0); + const Vector3 y = get_column(1); + const Vector3 z = get_column(2); + return Math::is_zero_approx(x.dot(y)) && Math::is_zero_approx(x.dot(z)) && Math::is_zero_approx(y.dot(z)); +} - return m.is_equal_approx(identity); +// Returns true if the basis vectors are orthonormal (orthogonal and normalized), so it has no scale, skew, or shear. +// See https://en.wikipedia.org/wiki/Orthonormal_basis +bool Basis::is_orthonormal() const { + const Vector3 x = get_column(0); + const Vector3 y = get_column(1); + const Vector3 z = get_column(2); + return Math::is_equal_approx(x.length_squared(), 1) && Math::is_equal_approx(y.length_squared(), 1) && Math::is_equal_approx(z.length_squared(), 1) && Math::is_zero_approx(x.dot(y)) && Math::is_zero_approx(x.dot(z)) && Math::is_zero_approx(y.dot(z)); } +// Returns true if the basis is conformal (orthogonal, uniform scale, preserves angles and distance ratios). +// See https://en.wikipedia.org/wiki/Conformal_linear_transformation +bool Basis::is_conformal() const { + const Vector3 x = get_column(0); + const Vector3 y = get_column(1); + const Vector3 z = get_column(2); + const real_t x_len_sq = x.length_squared(); + return Math::is_equal_approx(x_len_sq, y.length_squared()) && Math::is_equal_approx(x_len_sq, z.length_squared()) && Math::is_zero_approx(x.dot(y)) && Math::is_zero_approx(x.dot(z)) && Math::is_zero_approx(y.dot(z)); +} + +// Returns true if the basis only has diagonal elements, so it may only have scale or flip, but no rotation, skew, or shear. bool Basis::is_diagonal() const { return ( Math::is_zero_approx(rows[0][1]) && Math::is_zero_approx(rows[0][2]) && @@ -123,8 +131,9 @@ bool Basis::is_diagonal() const { Math::is_zero_approx(rows[2][0]) && Math::is_zero_approx(rows[2][1])); } +// Returns true if the basis is a pure rotation matrix, so it has no scale, skew, shear, or flip. bool Basis::is_rotation() const { - return Math::is_equal_approx(determinant(), 1, (real_t)UNIT_EPSILON) && is_orthogonal(); + return is_conformal() && Math::is_equal_approx(determinant(), 1, (real_t)UNIT_EPSILON); } #ifdef MATH_CHECKS @@ -259,29 +268,26 @@ void Basis::scale_orthogonal(const Vector3 &p_scale) { Basis Basis::scaled_orthogonal(const Vector3 &p_scale) const { Basis m = *this; Vector3 s = Vector3(-1, -1, -1) + p_scale; + bool sign = std::signbit(s.x + s.y + s.z); + Basis b = m.orthonormalized(); + s = b.xform_inv(s); Vector3 dots; - Basis b; for (int i = 0; i < 3; i++) { for (int j = 0; j < 3; j++) { dots[j] += s[i] * Math::abs(m.get_column(i).normalized().dot(b.get_column(j))); } } + if (sign != std::signbit(dots.x + dots.y + dots.z)) { + dots = -dots; + } m.scale_local(Vector3(1, 1, 1) + dots); return m; } -float Basis::get_uniform_scale() const { +real_t Basis::get_uniform_scale() const { return (rows[0].length() + rows[1].length() + rows[2].length()) / 3.0f; } -void Basis::make_scale_uniform() { - float l = (rows[0].length() + rows[1].length() + rows[2].length()) / 3.0f; - for (int i = 0; i < 3; i++) { - rows[i].normalize(); - rows[i] *= l; - } -} - Basis Basis::scaled_local(const Vector3 &p_scale) const { return (*this) * Basis::from_scale(p_scale); } @@ -293,7 +299,7 @@ Vector3 Basis::get_scale_abs() const { Vector3(rows[0][2], rows[1][2], rows[2][2]).length()); } -Vector3 Basis::get_scale_local() const { +Vector3 Basis::get_scale_global() const { real_t det_sign = SIGN(determinant()); return det_sign * Vector3(rows[0].length(), rows[1].length(), rows[2].length()); } @@ -420,7 +426,7 @@ void Basis::rotate_to_align(Vector3 p_start_direction, Vector3 p_end_direction) real_t dot = p_start_direction.dot(p_end_direction); dot = CLAMP(dot, -1.0f, 1.0f); const real_t angle_rads = Math::acos(dot); - set_axis_angle(axis, angle_rads); + *this = Basis(axis, angle_rads) * (*this); } } @@ -455,8 +461,13 @@ void Basis::get_rotation_axis_angle_local(Vector3 &p_axis, real_t &p_angle) cons } Vector3 Basis::get_euler(EulerOrder p_order) const { + // This epsilon value results in angles within a +/- 0.04 degree range being simplified/truncated. + // Based on testing, this is the largest the epsilon can be without the angle truncation becoming + // visually noticeable. + const real_t epsilon = 0.00000025; + switch (p_order) { - case EULER_ORDER_XYZ: { + case EulerOrder::EULER_ORDER_XYZ: { // Euler angles in XYZ convention. // See https://en.wikipedia.org/wiki/Euler_angles#Rotation_matrix // @@ -466,8 +477,8 @@ Vector3 Basis::get_euler(EulerOrder p_order) const { Vector3 euler; real_t sy = rows[0][2]; - if (sy < (1.0f - (real_t)CMP_EPSILON)) { - if (sy > -(1.0f - (real_t)CMP_EPSILON)) { + if (sy < (1.0f - epsilon)) { + if (sy > -(1.0f - epsilon)) { // is this a pure Y rotation? if (rows[1][0] == 0 && rows[0][1] == 0 && rows[1][2] == 0 && rows[2][1] == 0 && rows[1][1] == 1) { // return the simplest form (human friendlier in editor and scripts) @@ -491,7 +502,7 @@ Vector3 Basis::get_euler(EulerOrder p_order) const { } return euler; } - case EULER_ORDER_XZY: { + case EulerOrder::EULER_ORDER_XZY: { // Euler angles in XZY convention. // See https://en.wikipedia.org/wiki/Euler_angles#Rotation_matrix // @@ -501,8 +512,8 @@ Vector3 Basis::get_euler(EulerOrder p_order) const { Vector3 euler; real_t sz = rows[0][1]; - if (sz < (1.0f - (real_t)CMP_EPSILON)) { - if (sz > -(1.0f - (real_t)CMP_EPSILON)) { + if (sz < (1.0f - epsilon)) { + if (sz > -(1.0f - epsilon)) { euler.x = Math::atan2(rows[2][1], rows[1][1]); euler.y = Math::atan2(rows[0][2], rows[0][0]); euler.z = Math::asin(-sz); @@ -520,7 +531,7 @@ Vector3 Basis::get_euler(EulerOrder p_order) const { } return euler; } - case EULER_ORDER_YXZ: { + case EulerOrder::EULER_ORDER_YXZ: { // Euler angles in YXZ convention. // See https://en.wikipedia.org/wiki/Euler_angles#Rotation_matrix // @@ -532,8 +543,8 @@ Vector3 Basis::get_euler(EulerOrder p_order) const { real_t m12 = rows[1][2]; - if (m12 < (1 - (real_t)CMP_EPSILON)) { - if (m12 > -(1 - (real_t)CMP_EPSILON)) { + if (m12 < (1 - epsilon)) { + if (m12 > -(1 - epsilon)) { // is this a pure X rotation? if (rows[1][0] == 0 && rows[0][1] == 0 && rows[0][2] == 0 && rows[2][0] == 0 && rows[0][0] == 1) { // return the simplest form (human friendlier in editor and scripts) @@ -558,7 +569,7 @@ Vector3 Basis::get_euler(EulerOrder p_order) const { return euler; } - case EULER_ORDER_YZX: { + case EulerOrder::EULER_ORDER_YZX: { // Euler angles in YZX convention. // See https://en.wikipedia.org/wiki/Euler_angles#Rotation_matrix // @@ -568,8 +579,8 @@ Vector3 Basis::get_euler(EulerOrder p_order) const { Vector3 euler; real_t sz = rows[1][0]; - if (sz < (1.0f - (real_t)CMP_EPSILON)) { - if (sz > -(1.0f - (real_t)CMP_EPSILON)) { + if (sz < (1.0f - epsilon)) { + if (sz > -(1.0f - epsilon)) { euler.x = Math::atan2(-rows[1][2], rows[1][1]); euler.y = Math::atan2(-rows[2][0], rows[0][0]); euler.z = Math::asin(sz); @@ -586,8 +597,8 @@ Vector3 Basis::get_euler(EulerOrder p_order) const { euler.z = Math_PI / 2.0f; } return euler; - } - case EULER_ORDER_ZXY: { + } break; + case EulerOrder::EULER_ORDER_ZXY: { // Euler angles in ZXY convention. // See https://en.wikipedia.org/wiki/Euler_angles#Rotation_matrix // @@ -596,8 +607,8 @@ Vector3 Basis::get_euler(EulerOrder p_order) const { // -cx*sy sx cx*cy Vector3 euler; real_t sx = rows[2][1]; - if (sx < (1.0f - (real_t)CMP_EPSILON)) { - if (sx > -(1.0f - (real_t)CMP_EPSILON)) { + if (sx < (1.0f - epsilon)) { + if (sx > -(1.0f - epsilon)) { euler.x = Math::asin(sx); euler.y = Math::atan2(-rows[2][0], rows[2][2]); euler.z = Math::atan2(-rows[0][1], rows[1][1]); @@ -614,8 +625,8 @@ Vector3 Basis::get_euler(EulerOrder p_order) const { euler.z = 0; } return euler; - } - case EULER_ORDER_ZYX: { + } break; + case EulerOrder::EULER_ORDER_ZYX: { // Euler angles in ZYX convention. // See https://en.wikipedia.org/wiki/Euler_angles#Rotation_matrix // @@ -624,8 +635,8 @@ Vector3 Basis::get_euler(EulerOrder p_order) const { // -sy cy*sx cy*cx Vector3 euler; real_t sy = rows[2][0]; - if (sy < (1.0f - (real_t)CMP_EPSILON)) { - if (sy > -(1.0f - (real_t)CMP_EPSILON)) { + if (sy < (1.0f - epsilon)) { + if (sy > -(1.0f - epsilon)) { euler.x = Math::atan2(rows[2][1], rows[2][2]); euler.y = Math::asin(-sy); euler.z = Math::atan2(rows[1][0], rows[0][0]); @@ -666,26 +677,26 @@ void Basis::set_euler(const Vector3 &p_euler, EulerOrder p_order) { Basis zmat(c, -s, 0, s, c, 0, 0, 0, 1); switch (p_order) { - case EULER_ORDER_XYZ: { + case EulerOrder::EULER_ORDER_XYZ: { *this = xmat * (ymat * zmat); } break; - case EULER_ORDER_XZY: { + case EulerOrder::EULER_ORDER_XZY: { *this = xmat * zmat * ymat; } break; - case EULER_ORDER_YXZ: { + case EulerOrder::EULER_ORDER_YXZ: { *this = ymat * xmat * zmat; } break; - case EULER_ORDER_YZX: { + case EulerOrder::EULER_ORDER_YZX: { *this = ymat * zmat * xmat; } break; - case EULER_ORDER_ZXY: { + case EulerOrder::EULER_ORDER_ZXY: { *this = zmat * xmat * ymat; } break; - case EULER_ORDER_ZYX: { + case EulerOrder::EULER_ORDER_ZYX: { *this = zmat * ymat * xmat; } break; default: { - ERR_FAIL_MSG("Invalid order parameter for set_euler(vec3,order)"); + ERR_FAIL_MSG("Invalid Euler order parameter."); } } } @@ -722,7 +733,7 @@ Basis::operator String() const { Quaternion Basis::get_quaternion() const { #ifdef MATH_CHECKS - ERR_FAIL_COND_V_MSG(!is_rotation(), Quaternion(), "Basis must be normalized in order to be casted to a Quaternion. Use get_rotation_quaternion() or call orthonormalized() if the Basis contains linearly independent vectors."); + ERR_FAIL_COND_V_MSG(!is_rotation(), Quaternion(), "Basis " + operator String() + " must be normalized in order to be casted to a Quaternion. Use get_rotation_quaternion() or call orthonormalized() if the Basis contains linearly independent vectors."); #endif /* Allow getting a quaternion from an unnormalized transform */ Basis m = *this; @@ -830,8 +841,8 @@ void Basis::get_axis_angle(Vector3 &r_axis, real_t &r_angle) const { z = (rows[1][0] - rows[0][1]) / s; r_axis = Vector3(x, y, z); - // CLAMP to avoid NaN if the value passed to acos is not in [0,1]. - r_angle = Math::acos(CLAMP((rows[0][0] + rows[1][1] + rows[2][2] - 1) / 2, (real_t)0.0, (real_t)1.0)); + // acos does clamping. + r_angle = Math::acos((rows[0][0] + rows[1][1] + rows[2][2] - 1) / 2); } void Basis::set_quaternion(const Quaternion &p_quaternion) { @@ -849,7 +860,7 @@ void Basis::set_quaternion(const Quaternion &p_quaternion) { void Basis::set_axis_angle(const Vector3 &p_axis, real_t p_angle) { // Rotation matrix from axis and angle, see https://en.wikipedia.org/wiki/Rotation_matrix#Rotation_matrix_from_axis_angle #ifdef MATH_CHECKS - ERR_FAIL_COND_MSG(!p_axis.is_normalized(), "The axis Vector3 must be normalized."); + ERR_FAIL_COND_MSG(!p_axis.is_normalized(), "The axis Vector3 " + p_axis.operator String() + " must be normalized."); #endif Vector3 axis_sq(p_axis.x * p_axis.x, p_axis.y * p_axis.y, p_axis.z * p_axis.z); real_t cosine = Math::cos(p_angle); @@ -907,7 +918,7 @@ void Basis::_set_diagonal(const Vector3 &p_diag) { rows[2][2] = p_diag.z; } -Basis Basis::lerp(const Basis &p_to, const real_t &p_weight) const { +Basis Basis::lerp(const Basis &p_to, real_t p_weight) const { Basis b; b.rows[0] = rows[0].lerp(p_to.rows[0], p_weight); b.rows[1] = rows[1].lerp(p_to.rows[1], p_weight); @@ -916,7 +927,7 @@ Basis Basis::lerp(const Basis &p_to, const real_t &p_weight) const { return b; } -Basis Basis::slerp(const Basis &p_to, const real_t &p_weight) const { +Basis Basis::slerp(const Basis &p_to, real_t p_weight) const { //consider scale Quaternion from(*this); Quaternion to(p_to); @@ -1049,9 +1060,10 @@ Basis Basis::looking_at(const Vector3 &p_target, const Vector3 &p_up, bool p_use v_z = -v_z; } Vector3 v_x = p_up.cross(v_z); -#ifdef MATH_CHECKS - ERR_FAIL_COND_V_MSG(v_x.is_zero_approx(), Basis(), "The target vector and up vector can't be parallel to each other."); -#endif + if (v_x.is_zero_approx()) { + WARN_PRINT("Target and up vectors are colinear. This is not advised as it may cause unwanted rotation around local Z axis."); + v_x = p_up.get_any_perpendicular(); // Vectors are almost parallel. + } v_x.normalize(); Vector3 v_y = v_z.cross(v_x); diff --git a/src/variant/color.cpp b/src/variant/color.cpp index ed5340ff..b24714a0 100644 --- a/src/variant/color.cpp +++ b/src/variant/color.cpp @@ -31,6 +31,7 @@ /**************************************************************************/ #include +#include #include #include #include @@ -133,20 +134,20 @@ String _to_hex(float p_val) { String Color::to_html(bool p_alpha) const { String txt; - txt = txt + _to_hex(r); - txt = txt + _to_hex(g); - txt = txt + _to_hex(b); + txt += _to_hex(r); + txt += _to_hex(g); + txt += _to_hex(b); if (p_alpha) { - txt = txt + _to_hex(a); + txt += _to_hex(a); } return txt; } float Color::get_h() const { - float min = Math::min(r, g); - min = Math::min(min, b); - float max = Math::max(r, g); - max = Math::max(max, b); + float min = MIN(r, g); + min = MIN(min, b); + float max = MAX(r, g); + max = MAX(max, b); float delta = max - min; @@ -172,10 +173,10 @@ float Color::get_h() const { } float Color::get_s() const { - float min = Math::min(r, g); - min = Math::min(min, b); - float max = Math::max(r, g); - max = Math::max(max, b); + float min = MIN(r, g); + min = MIN(min, b); + float max = MAX(r, g); + max = MAX(max, b); float delta = max - min; @@ -183,8 +184,8 @@ float Color::get_s() const { } float Color::get_v() const { - float max = Math::max(r, g); - max = Math::max(max, b); + float max = MAX(r, g); + max = MAX(max, b); return max; } @@ -387,7 +388,6 @@ Color Color::named(const String &p_name) { int idx = find_named_color(p_name); if (idx == -1) { ERR_FAIL_V_MSG(Color(), "Invalid color name: " + p_name + "."); - return Color(); } return named_colors[idx].color; } @@ -402,7 +402,7 @@ Color Color::named(const String &p_name, const Color &p_default) { int Color::find_named_color(const String &p_name) { String name = p_name; - // Normalize name + // Normalize name. name = name.replace(" ", ""); name = name.replace("-", ""); name = name.replace("_", ""); @@ -410,23 +410,24 @@ int Color::find_named_color(const String &p_name) { name = name.replace(".", ""); name = name.to_upper(); - int idx = 0; - while (named_colors[idx].name != nullptr) { - if (name == String(named_colors[idx].name).replace("_", "")) { - return idx; + static HashMap named_colors_hashmap; + if (unlikely(named_colors_hashmap.is_empty())) { + const int named_color_count = get_named_color_count(); + for (int i = 0; i < named_color_count; i++) { + named_colors_hashmap[String(named_colors[i].name).replace("_", "")] = i; } - idx++; + } + + const HashMap::ConstIterator E = named_colors_hashmap.find(name); + if (E) { + return E->value; } return -1; } int Color::get_named_color_count() { - int idx = 0; - while (named_colors[idx].name != nullptr) { - idx++; - } - return idx; + return sizeof(named_colors) / sizeof(NamedColor); } String Color::get_named_color_name(int p_idx) { @@ -469,6 +470,10 @@ Color Color::from_rgbe9995(uint32_t p_rgbe) { return Color(rd, gd, bd, 1.0f); } +Color Color::from_rgba8(int64_t p_r8, int64_t p_g8, int64_t p_b8, int64_t p_a8) { + return Color(p_r8 / 255.0f, p_g8 / 255.0f, p_b8 / 255.0f, p_a8 / 255.0f); +} + Color::operator String() const { return "(" + String::num(r, 4) + ", " + String::num(g, 4) + ", " + String::num(b, 4) + ", " + String::num(a, 4) + ")"; } diff --git a/src/variant/packed_arrays.cpp b/src/variant/packed_arrays.cpp index 6a1788dd..ef5505ea 100644 --- a/src/variant/packed_arrays.cpp +++ b/src/variant/packed_arrays.cpp @@ -238,6 +238,14 @@ void Array::_ref(const Array &p_from) const { internal::gdextension_interface_array_ref((GDExtensionTypePtr *)this, (GDExtensionConstTypePtr *)&p_from); } +const Variant *Array::ptr() const { + return (const Variant *)internal::gdextension_interface_array_operator_index_const((GDExtensionTypePtr *)this, 0); +} + +Variant *Array::ptrw() { + return (Variant *)internal::gdextension_interface_array_operator_index((GDExtensionTypePtr *)this, 0); +} + const Variant &Dictionary::operator[](const Variant &p_key) const { const Variant *var = (const Variant *)internal::gdextension_interface_dictionary_operator_index_const((GDExtensionTypePtr *)this, (GDExtensionVariantPtr)&p_key); return *var; diff --git a/src/variant/plane.cpp b/src/variant/plane.cpp index f03e1d48..915171b5 100644 --- a/src/variant/plane.cpp +++ b/src/variant/plane.cpp @@ -102,13 +102,11 @@ bool Plane::intersects_ray(const Vector3 &p_from, const Vector3 &p_dir, Vector3 Vector3 segment = p_dir; real_t den = normal.dot(segment); - //printf("den is %i\n",den); if (Math::is_zero_approx(den)) { return false; } real_t dist = (normal.dot(p_from) - d) / den; - //printf("dist is %i\n",dist); if (dist > (real_t)CMP_EPSILON) { //this is a ray, before the emitting pos (p_from) doesn't exist @@ -125,13 +123,11 @@ bool Plane::intersects_segment(const Vector3 &p_begin, const Vector3 &p_end, Vec Vector3 segment = p_begin - p_end; real_t den = normal.dot(segment); - //printf("den is %i\n",den); if (Math::is_zero_approx(den)) { return false; } real_t dist = (normal.dot(p_begin) - d) / den; - //printf("dist is %i\n",dist); if (dist < (real_t)-CMP_EPSILON || dist > (1.0f + (real_t)CMP_EPSILON)) { return false; diff --git a/src/variant/projection.cpp b/src/variant/projection.cpp index 9d879b50..a21aae54 100644 --- a/src/variant/projection.cpp +++ b/src/variant/projection.cpp @@ -41,7 +41,7 @@ namespace godot { -float Projection::determinant() const { +real_t Projection::determinant() const { return columns[0][3] * columns[1][2] * columns[2][1] * columns[3][0] - columns[0][2] * columns[1][3] * columns[2][1] * columns[3][0] - columns[0][3] * columns[1][1] * columns[2][2] * columns[3][0] + columns[0][1] * columns[1][3] * columns[2][2] * columns[3][0] + columns[0][2] * columns[1][1] * columns[2][3] * columns[3][0] - columns[0][1] * columns[1][2] * columns[2][3] * columns[3][0] - @@ -173,7 +173,7 @@ Projection Projection::perspective_znear_adjusted(real_t p_new_znear) const { } Plane Projection::get_projection_plane(Planes p_plane) const { - const real_t *matrix = (const real_t *)this->columns; + const real_t *matrix = (const real_t *)columns; switch (p_plane) { case PLANE_NEAR: { @@ -406,20 +406,19 @@ void Projection::set_frustum(real_t p_size, real_t p_aspect, Vector2 p_offset, r } real_t Projection::get_z_far() const { - const real_t *matrix = (const real_t *)this->columns; + const real_t *matrix = (const real_t *)columns; Plane new_plane = Plane(matrix[3] - matrix[2], matrix[7] - matrix[6], matrix[11] - matrix[10], matrix[15] - matrix[14]); - new_plane.normal = -new_plane.normal; new_plane.normalize(); return new_plane.d; } real_t Projection::get_z_near() const { - const real_t *matrix = (const real_t *)this->columns; + const real_t *matrix = (const real_t *)columns; Plane new_plane = Plane(matrix[3] + matrix[2], matrix[7] + matrix[6], matrix[11] + matrix[10], @@ -430,7 +429,7 @@ real_t Projection::get_z_near() const { } Vector2 Projection::get_viewport_half_extents() const { - const real_t *matrix = (const real_t *)this->columns; + const real_t *matrix = (const real_t *)columns; ///////--- Near Plane ---/////// Plane near_plane = Plane(matrix[3] + matrix[2], matrix[7] + matrix[6], @@ -458,7 +457,7 @@ Vector2 Projection::get_viewport_half_extents() const { } Vector2 Projection::get_far_plane_half_extents() const { - const real_t *matrix = (const real_t *)this->columns; + const real_t *matrix = (const real_t *)columns; ///////--- Far Plane ---/////// Plane far_plane = Plane(matrix[3] - matrix[2], matrix[7] - matrix[6], @@ -486,7 +485,7 @@ Vector2 Projection::get_far_plane_half_extents() const { } bool Projection::get_endpoints(const Transform3D &p_transform, Vector3 *p_8points) const { - Array planes = get_projection_planes(Transform3D()); + Vector planes = get_projection_planes(Transform3D()); const Planes intersections[8][3] = { { PLANE_FAR, PLANE_LEFT, PLANE_TOP }, { PLANE_FAR, PLANE_LEFT, PLANE_BOTTOM }, @@ -511,17 +510,17 @@ bool Projection::get_endpoints(const Transform3D &p_transform, Vector3 *p_8point return true; } -Array Projection::get_projection_planes(const Transform3D &p_transform) const { +Vector Projection::get_projection_planes(const Transform3D &p_transform) const { /** Fast Plane Extraction from combined modelview/projection matrices. * References: * https://web.archive.org/web/20011221205252/https://www.markmorley.com/opengl/frustumculling.html * https://web.archive.org/web/20061020020112/https://www2.ravensoft.com/users/ggribb/plane%20extraction.pdf */ - Array planes; + Vector planes; planes.resize(6); - const real_t *matrix = (const real_t *)this->columns; + const real_t *matrix = (const real_t *)columns; Plane new_plane; @@ -534,7 +533,7 @@ Array Projection::get_projection_planes(const Transform3D &p_transform) const { new_plane.normal = -new_plane.normal; new_plane.normalize(); - planes[0] = p_transform.xform(new_plane); + planes.write[0] = p_transform.xform(new_plane); ///////--- Far Plane ---/////// new_plane = Plane(matrix[3] - matrix[2], @@ -545,7 +544,7 @@ Array Projection::get_projection_planes(const Transform3D &p_transform) const { new_plane.normal = -new_plane.normal; new_plane.normalize(); - planes[1] = p_transform.xform(new_plane); + planes.write[1] = p_transform.xform(new_plane); ///////--- Left Plane ---/////// new_plane = Plane(matrix[3] + matrix[0], @@ -556,7 +555,7 @@ Array Projection::get_projection_planes(const Transform3D &p_transform) const { new_plane.normal = -new_plane.normal; new_plane.normalize(); - planes[2] = p_transform.xform(new_plane); + planes.write[2] = p_transform.xform(new_plane); ///////--- Top Plane ---/////// new_plane = Plane(matrix[3] - matrix[1], @@ -567,7 +566,7 @@ Array Projection::get_projection_planes(const Transform3D &p_transform) const { new_plane.normal = -new_plane.normal; new_plane.normalize(); - planes[3] = p_transform.xform(new_plane); + planes.write[3] = p_transform.xform(new_plane); ///////--- Right Plane ---/////// new_plane = Plane(matrix[3] - matrix[0], @@ -578,7 +577,7 @@ Array Projection::get_projection_planes(const Transform3D &p_transform) const { new_plane.normal = -new_plane.normal; new_plane.normalize(); - planes[4] = p_transform.xform(new_plane); + planes.write[4] = p_transform.xform(new_plane); ///////--- Bottom Plane ---/////// new_plane = Plane(matrix[3] + matrix[1], @@ -589,7 +588,7 @@ Array Projection::get_projection_planes(const Transform3D &p_transform) const { new_plane.normal = -new_plane.normal; new_plane.normalize(); - planes[5] = p_transform.xform(new_plane); + planes.write[5] = p_transform.xform(new_plane); return planes; } @@ -601,101 +600,229 @@ Projection Projection::inverse() const { } void Projection::invert() { - int i, j, k; - int pvt_i[4], pvt_j[4]; /* Locations of pivot matrix */ - real_t pvt_val; /* Value of current pivot element */ - real_t hold; /* Temporary storage */ - real_t determinant = 1.0f; - for (k = 0; k < 4; k++) { - /** Locate k'th pivot element **/ - pvt_val = columns[k][k]; /** Initialize for search **/ - pvt_i[k] = k; - pvt_j[k] = k; - for (i = k; i < 4; i++) { - for (j = k; j < 4; j++) { - if (Math::abs(columns[i][j]) > Math::abs(pvt_val)) { - pvt_i[k] = i; - pvt_j[k] = j; - pvt_val = columns[i][j]; - } - } - } - - /** Product of pivots, gives determinant when finished **/ - determinant *= pvt_val; - if (Math::is_zero_approx(determinant)) { - return; /** Matrix is singular (zero determinant). **/ - } - - /** "Interchange" rows (with sign change stuff) **/ - i = pvt_i[k]; - if (i != k) { /** If rows are different **/ - for (j = 0; j < 4; j++) { - hold = -columns[k][j]; - columns[k][j] = columns[i][j]; - columns[i][j] = hold; - } - } - - /** "Interchange" columns **/ - j = pvt_j[k]; - if (j != k) { /** If columns are different **/ - for (i = 0; i < 4; i++) { - hold = -columns[i][k]; - columns[i][k] = columns[i][j]; - columns[i][j] = hold; - } - } - - /** Divide column by minus pivot value **/ - for (i = 0; i < 4; i++) { - if (i != k) { - columns[i][k] /= (-pvt_val); - } - } - - /** Reduce the matrix **/ - for (i = 0; i < 4; i++) { - hold = columns[i][k]; - for (j = 0; j < 4; j++) { - if (i != k && j != k) { - columns[i][j] += hold * columns[k][j]; - } - } - } - - /** Divide row by pivot **/ - for (j = 0; j < 4; j++) { - if (j != k) { - columns[k][j] /= pvt_val; - } - } - - /** Replace pivot by reciprocal (at last we can touch it). **/ - columns[k][k] = 1.0 / pvt_val; + // Adapted from Mesa's `src/util/u_math.c` `util_invert_mat4x4`. + // MIT licensed. Copyright 2008 VMware, Inc. Authored by Jacques Leroy. + Projection temp; + real_t *out = (real_t *)temp.columns; + real_t *m = (real_t *)columns; + + real_t wtmp[4][8]; + real_t m0, m1, m2, m3, s; + real_t *r0, *r1, *r2, *r3; + +#define MAT(m, r, c) (m)[(c) * 4 + (r)] + + r0 = wtmp[0]; + r1 = wtmp[1]; + r2 = wtmp[2]; + r3 = wtmp[3]; + + r0[0] = MAT(m, 0, 0); + r0[1] = MAT(m, 0, 1); + r0[2] = MAT(m, 0, 2); + r0[3] = MAT(m, 0, 3); + r0[4] = 1.0; + r0[5] = 0.0; + r0[6] = 0.0; + r0[7] = 0.0; + + r1[0] = MAT(m, 1, 0); + r1[1] = MAT(m, 1, 1); + r1[2] = MAT(m, 1, 2); + r1[3] = MAT(m, 1, 3); + r1[5] = 1.0; + r1[4] = 0.0; + r1[6] = 0.0; + r1[7] = 0.0; + + r2[0] = MAT(m, 2, 0); + r2[1] = MAT(m, 2, 1); + r2[2] = MAT(m, 2, 2); + r2[3] = MAT(m, 2, 3); + r2[6] = 1.0; + r2[4] = 0.0; + r2[5] = 0.0; + r2[7] = 0.0; + + r3[0] = MAT(m, 3, 0); + r3[1] = MAT(m, 3, 1); + r3[2] = MAT(m, 3, 2); + r3[3] = MAT(m, 3, 3); + + r3[7] = 1.0; + r3[4] = 0.0; + r3[5] = 0.0; + r3[6] = 0.0; + + /* choose pivot - or die */ + if (Math::abs(r3[0]) > Math::abs(r2[0])) { + SWAP(r3, r2); + } + if (Math::abs(r2[0]) > Math::abs(r1[0])) { + SWAP(r2, r1); + } + if (Math::abs(r1[0]) > Math::abs(r0[0])) { + SWAP(r1, r0); + } + ERR_FAIL_COND(0.0 == r0[0]); + + /* eliminate first variable */ + m1 = r1[0] / r0[0]; + m2 = r2[0] / r0[0]; + m3 = r3[0] / r0[0]; + s = r0[1]; + r1[1] -= m1 * s; + r2[1] -= m2 * s; + r3[1] -= m3 * s; + s = r0[2]; + r1[2] -= m1 * s; + r2[2] -= m2 * s; + r3[2] -= m3 * s; + s = r0[3]; + r1[3] -= m1 * s; + r2[3] -= m2 * s; + r3[3] -= m3 * s; + s = r0[4]; + if (s != 0.0) { + r1[4] -= m1 * s; + r2[4] -= m2 * s; + r3[4] -= m3 * s; + } + s = r0[5]; + if (s != 0.0) { + r1[5] -= m1 * s; + r2[5] -= m2 * s; + r3[5] -= m3 * s; + } + s = r0[6]; + if (s != 0.0) { + r1[6] -= m1 * s; + r2[6] -= m2 * s; + r3[6] -= m3 * s; + } + s = r0[7]; + if (s != 0.0) { + r1[7] -= m1 * s; + r2[7] -= m2 * s; + r3[7] -= m3 * s; } - /* That was most of the work, one final pass of row/column interchange */ - /* to finish */ - for (k = 4 - 2; k >= 0; k--) { /* Don't need to work with 1 by 1 corner*/ - i = pvt_j[k]; /* Rows to swap correspond to pivot COLUMN */ - if (i != k) { /* If rows are different */ - for (j = 0; j < 4; j++) { - hold = columns[k][j]; - columns[k][j] = -columns[i][j]; - columns[i][j] = hold; - } - } + /* choose pivot - or die */ + if (Math::abs(r3[1]) > Math::abs(r2[1])) { + SWAP(r3, r2); + } + if (Math::abs(r2[1]) > Math::abs(r1[1])) { + SWAP(r2, r1); + } + ERR_FAIL_COND(0.0 == r1[1]); + + /* eliminate second variable */ + m2 = r2[1] / r1[1]; + m3 = r3[1] / r1[1]; + r2[2] -= m2 * r1[2]; + r3[2] -= m3 * r1[2]; + r2[3] -= m2 * r1[3]; + r3[3] -= m3 * r1[3]; + s = r1[4]; + if (0.0 != s) { + r2[4] -= m2 * s; + r3[4] -= m3 * s; + } + s = r1[5]; + if (0.0 != s) { + r2[5] -= m2 * s; + r3[5] -= m3 * s; + } + s = r1[6]; + if (0.0 != s) { + r2[6] -= m2 * s; + r3[6] -= m3 * s; + } + s = r1[7]; + if (0.0 != s) { + r2[7] -= m2 * s; + r3[7] -= m3 * s; + } - j = pvt_i[k]; /* Columns to swap correspond to pivot ROW */ - if (j != k) { /* If columns are different */ - for (i = 0; i < 4; i++) { - hold = columns[i][k]; - columns[i][k] = -columns[i][j]; - columns[i][j] = hold; - } - } + /* choose pivot - or die */ + if (Math::abs(r3[2]) > Math::abs(r2[2])) { + SWAP(r3, r2); } + ERR_FAIL_COND(0.0 == r2[2]); + + /* eliminate third variable */ + m3 = r3[2] / r2[2]; + r3[3] -= m3 * r2[3]; + r3[4] -= m3 * r2[4]; + r3[5] -= m3 * r2[5]; + r3[6] -= m3 * r2[6]; + r3[7] -= m3 * r2[7]; + + /* last check */ + ERR_FAIL_COND(0.0 == r3[3]); + + s = 1.0 / r3[3]; /* now back substitute row 3 */ + r3[4] *= s; + r3[5] *= s; + r3[6] *= s; + r3[7] *= s; + + m2 = r2[3]; /* now back substitute row 2 */ + s = 1.0 / r2[2]; + r2[4] = s * (r2[4] - r3[4] * m2); + r2[5] = s * (r2[5] - r3[5] * m2); + r2[6] = s * (r2[6] - r3[6] * m2); + r2[7] = s * (r2[7] - r3[7] * m2); + m1 = r1[3]; + r1[4] -= r3[4] * m1; + r1[5] -= r3[5] * m1; + r1[6] -= r3[6] * m1; + r1[7] -= r3[7] * m1; + m0 = r0[3]; + r0[4] -= r3[4] * m0; + r0[5] -= r3[5] * m0; + r0[6] -= r3[6] * m0; + r0[7] -= r3[7] * m0; + + m1 = r1[2]; /* now back substitute row 1 */ + s = 1.0 / r1[1]; + r1[4] = s * (r1[4] - r2[4] * m1); + r1[5] = s * (r1[5] - r2[5] * m1), + r1[6] = s * (r1[6] - r2[6] * m1); + r1[7] = s * (r1[7] - r2[7] * m1); + m0 = r0[2]; + r0[4] -= r2[4] * m0; + r0[5] -= r2[5] * m0; + r0[6] -= r2[6] * m0; + r0[7] -= r2[7] * m0; + + m0 = r0[1]; /* now back substitute row 0 */ + s = 1.0 / r0[0]; + r0[4] = s * (r0[4] - r1[4] * m0); + r0[5] = s * (r0[5] - r1[5] * m0), + r0[6] = s * (r0[6] - r1[6] * m0); + r0[7] = s * (r0[7] - r1[7] * m0); + + MAT(out, 0, 0) = r0[4]; + MAT(out, 0, 1) = r0[5]; + MAT(out, 0, 2) = r0[6]; + MAT(out, 0, 3) = r0[7]; + MAT(out, 1, 0) = r1[4]; + MAT(out, 1, 1) = r1[5]; + MAT(out, 1, 2) = r1[6]; + MAT(out, 1, 3) = r1[7]; + MAT(out, 2, 0) = r2[4]; + MAT(out, 2, 1) = r2[5]; + MAT(out, 2, 2) = r2[6]; + MAT(out, 2, 3) = r2[7]; + MAT(out, 3, 0) = r3[4]; + MAT(out, 3, 1) = r3[5]; + MAT(out, 3, 2) = r3[6]; + MAT(out, 3, 3) = r3[7]; + +#undef MAT + + *this = temp; } void Projection::flip_y() { @@ -724,7 +851,8 @@ Projection Projection::operator*(const Projection &p_matrix) const { return new_matrix; } -void Projection::set_depth_correction(bool p_flip_y) { +void Projection::set_depth_correction(bool p_flip_y, bool p_reverse_z, bool p_remap_z) { + // p_remap_z is used to convert from OpenGL-style clip space (-1 - 1) to Vulkan style (0 - 1). real_t *m = &columns[0][0]; m[0] = 1; @@ -737,11 +865,11 @@ void Projection::set_depth_correction(bool p_flip_y) { m[7] = 0.0; m[8] = 0.0; m[9] = 0.0; - m[10] = 0.5; + m[10] = p_remap_z ? (p_reverse_z ? -0.5 : 0.5) : (p_reverse_z ? -1.0 : 1.0); m[11] = 0.0; m[12] = 0.0; m[13] = 0.0; - m[14] = 0.5; + m[14] = p_remap_z ? 0.5 : 0.0; m[15] = 1.0; } @@ -788,14 +916,10 @@ void Projection::set_light_atlas_rect(const Rect2 &p_rect) { } Projection::operator String() const { - String str; - for (int i = 0; i < 4; i++) { - for (int j = 0; j < 4; j++) { - str = str + String((j > 0) ? ", " : "\n") + rtos(columns[i][j]); - } - } - - return str; + return "[X: " + columns[0].operator String() + + ", Y: " + columns[1].operator String() + + ", Z: " + columns[2].operator String() + + ", W: " + columns[3].operator String() + "]"; } real_t Projection::get_aspect() const { @@ -814,7 +938,7 @@ bool Projection::is_orthogonal() const { } real_t Projection::get_fov() const { - const real_t *matrix = (const real_t *)this->columns; + const real_t *matrix = (const real_t *)columns; Plane right_plane = Plane(matrix[3] - matrix[0], matrix[7] - matrix[4], @@ -836,13 +960,13 @@ real_t Projection::get_fov() const { } } -float Projection::get_lod_multiplier() const { +real_t Projection::get_lod_multiplier() const { if (is_orthogonal()) { return get_viewport_half_extents().x; } else { - float zn = get_z_near(); - float width = get_viewport_half_extents().x * 2.0; - return 1.0 / (zn / width); + const real_t zn = get_z_near(); + const real_t width = get_viewport_half_extents().x * 2.0f; + return 1.0f / (zn / width); } // Usage is lod_size / (lod_distance * multiplier) < threshold @@ -915,6 +1039,13 @@ Projection::Projection(const Vector4 &p_x, const Vector4 &p_y, const Vector4 &p_ columns[3] = p_w; } +Projection::Projection(real_t p_xx, real_t p_xy, real_t p_xz, real_t p_xw, real_t p_yx, real_t p_yy, real_t p_yz, real_t p_yw, real_t p_zx, real_t p_zy, real_t p_zz, real_t p_zw, real_t p_wx, real_t p_wy, real_t p_wz, real_t p_ww) { + columns[0] = Vector4(p_xx, p_xy, p_xz, p_xw); + columns[1] = Vector4(p_yx, p_yy, p_yz, p_yw); + columns[2] = Vector4(p_zx, p_zy, p_zz, p_zw); + columns[3] = Vector4(p_wx, p_wy, p_wz, p_ww); +} + Projection::Projection(const Transform3D &p_transform) { const Transform3D &tr = p_transform; real_t *m = &columns[0][0]; diff --git a/src/variant/quaternion.cpp b/src/variant/quaternion.cpp index ec2c25d4..ced7ab9e 100644 --- a/src/variant/quaternion.cpp +++ b/src/variant/quaternion.cpp @@ -196,11 +196,11 @@ Quaternion Quaternion::spherical_cubic_interpolate(const Quaternion &p_b, const post_q = Basis(post_q).get_rotation_quaternion(); // Flip quaternions to shortest path if necessary. - bool flip1 = Math::sign(from_q.dot(pre_q)); + bool flip1 = std::signbit(from_q.dot(pre_q)); pre_q = flip1 ? -pre_q : pre_q; - bool flip2 = Math::sign(from_q.dot(to_q)); + bool flip2 = std::signbit(from_q.dot(to_q)); to_q = flip2 ? -to_q : to_q; - bool flip3 = flip2 ? to_q.dot(post_q) <= 0 : Math::sign(to_q.dot(post_q)); + bool flip3 = flip2 ? to_q.dot(post_q) <= 0 : std::signbit(to_q.dot(post_q)); post_q = flip3 ? -post_q : post_q; // Calc by Expmap in from_q space. @@ -247,11 +247,11 @@ Quaternion Quaternion::spherical_cubic_interpolate_in_time(const Quaternion &p_b post_q = Basis(post_q).get_rotation_quaternion(); // Flip quaternions to shortest path if necessary. - bool flip1 = Math::sign(from_q.dot(pre_q)); + bool flip1 = std::signbit(from_q.dot(pre_q)); pre_q = flip1 ? -pre_q : pre_q; - bool flip2 = Math::sign(from_q.dot(to_q)); + bool flip2 = std::signbit(from_q.dot(to_q)); to_q = flip2 ? -to_q : to_q; - bool flip3 = flip2 ? to_q.dot(post_q) <= 0 : Math::sign(to_q.dot(post_q)); + bool flip3 = flip2 ? to_q.dot(post_q) <= 0 : std::signbit(to_q.dot(post_q)); post_q = flip3 ? -post_q : post_q; // Calc by Expmap in from_q space. diff --git a/src/variant/rect2.cpp b/src/variant/rect2.cpp index 20e52c21..998cc567 100644 --- a/src/variant/rect2.cpp +++ b/src/variant/rect2.cpp @@ -213,31 +213,31 @@ bool Rect2::intersects_transformed(const Transform2D &p_xform, const Rect2 &p_re real_t mina = maxa; real_t dp = p_xform.columns[0].dot(xf_points2[1]); - maxa = Math::max(dp, maxa); - mina = Math::min(dp, mina); + maxa = MAX(dp, maxa); + mina = MIN(dp, mina); dp = p_xform.columns[0].dot(xf_points2[2]); - maxa = Math::max(dp, maxa); - mina = Math::min(dp, mina); + maxa = MAX(dp, maxa); + mina = MIN(dp, mina); dp = p_xform.columns[0].dot(xf_points2[3]); - maxa = Math::max(dp, maxa); - mina = Math::min(dp, mina); + maxa = MAX(dp, maxa); + mina = MIN(dp, mina); real_t maxb = p_xform.columns[0].dot(xf_points[0]); real_t minb = maxb; dp = p_xform.columns[0].dot(xf_points[1]); - maxb = Math::max(dp, maxb); - minb = Math::min(dp, minb); + maxb = MAX(dp, maxb); + minb = MIN(dp, minb); dp = p_xform.columns[0].dot(xf_points[2]); - maxb = Math::max(dp, maxb); - minb = Math::min(dp, minb); + maxb = MAX(dp, maxb); + minb = MIN(dp, minb); dp = p_xform.columns[0].dot(xf_points[3]); - maxb = Math::max(dp, maxb); - minb = Math::min(dp, minb); + maxb = MAX(dp, maxb); + minb = MIN(dp, minb); if (mina > maxb) { return false; @@ -250,31 +250,31 @@ bool Rect2::intersects_transformed(const Transform2D &p_xform, const Rect2 &p_re mina = maxa; dp = p_xform.columns[1].dot(xf_points2[1]); - maxa = Math::max(dp, maxa); - mina = Math::min(dp, mina); + maxa = MAX(dp, maxa); + mina = MIN(dp, mina); dp = p_xform.columns[1].dot(xf_points2[2]); - maxa = Math::max(dp, maxa); - mina = Math::min(dp, mina); + maxa = MAX(dp, maxa); + mina = MIN(dp, mina); dp = p_xform.columns[1].dot(xf_points2[3]); - maxa = Math::max(dp, maxa); - mina = Math::min(dp, mina); + maxa = MAX(dp, maxa); + mina = MIN(dp, mina); maxb = p_xform.columns[1].dot(xf_points[0]); minb = maxb; dp = p_xform.columns[1].dot(xf_points[1]); - maxb = Math::max(dp, maxb); - minb = Math::min(dp, minb); + maxb = MAX(dp, maxb); + minb = MIN(dp, minb); dp = p_xform.columns[1].dot(xf_points[2]); - maxb = Math::max(dp, maxb); - minb = Math::min(dp, minb); + maxb = MAX(dp, maxb); + minb = MIN(dp, minb); dp = p_xform.columns[1].dot(xf_points[3]); - maxb = Math::max(dp, maxb); - minb = Math::min(dp, minb); + maxb = MAX(dp, maxb); + minb = MIN(dp, minb); if (mina > maxb) { return false; @@ -287,7 +287,7 @@ bool Rect2::intersects_transformed(const Transform2D &p_xform, const Rect2 &p_re } Rect2::operator String() const { - return "[P: " + position.operator String() + ", S: " + size + "]"; + return "[P: " + position.operator String() + ", S: " + size.operator String() + "]"; } Rect2::operator Rect2i() const { diff --git a/src/variant/transform2d.cpp b/src/variant/transform2d.cpp index cd90cd6f..2a14d3ae 100644 --- a/src/variant/transform2d.cpp +++ b/src/variant/transform2d.cpp @@ -50,7 +50,7 @@ Transform2D Transform2D::inverse() const { } void Transform2D::affine_invert() { - real_t det = basis_determinant(); + real_t det = determinant(); #ifdef MATH_CHECKS ERR_FAIL_COND(det == 0); #endif @@ -69,17 +69,17 @@ Transform2D Transform2D::affine_inverse() const { return inv; } -void Transform2D::rotate(const real_t p_angle) { +void Transform2D::rotate(real_t p_angle) { *this = Transform2D(p_angle, Vector2()) * (*this); } real_t Transform2D::get_skew() const { - real_t det = basis_determinant(); + real_t det = determinant(); return Math::acos(columns[0].normalized().dot(SIGN(det) * columns[1].normalized())) - (real_t)Math_PI * 0.5f; } -void Transform2D::set_skew(const real_t p_angle) { - real_t det = basis_determinant(); +void Transform2D::set_skew(real_t p_angle) { + real_t det = determinant(); columns[1] = SIGN(det) * columns[0].rotated(((real_t)Math_PI * 0.5f + p_angle)).normalized() * columns[1].length(); } @@ -87,7 +87,7 @@ real_t Transform2D::get_rotation() const { return Math::atan2(columns[0].y, columns[0].x); } -void Transform2D::set_rotation(const real_t p_rot) { +void Transform2D::set_rotation(real_t p_rot) { Size2 scale = get_scale(); real_t cr = Math::cos(p_rot); real_t sr = Math::sin(p_rot); @@ -98,7 +98,7 @@ void Transform2D::set_rotation(const real_t p_rot) { set_scale(scale); } -Transform2D::Transform2D(const real_t p_rot, const Vector2 &p_pos) { +Transform2D::Transform2D(real_t p_rot, const Vector2 &p_pos) { real_t cr = Math::cos(p_rot); real_t sr = Math::sin(p_rot); columns[0][0] = cr; @@ -108,7 +108,7 @@ Transform2D::Transform2D(const real_t p_rot, const Vector2 &p_pos) { columns[2] = p_pos; } -Transform2D::Transform2D(const real_t p_rot, const Size2 &p_scale, const real_t p_skew, const Vector2 &p_pos) { +Transform2D::Transform2D(real_t p_rot, const Size2 &p_scale, real_t p_skew, const Vector2 &p_pos) { columns[0][0] = Math::cos(p_rot) * p_scale.x; columns[1][1] = Math::cos(p_rot + p_skew) * p_scale.y; columns[1][0] = -Math::sin(p_rot + p_skew) * p_scale.y; @@ -117,7 +117,7 @@ Transform2D::Transform2D(const real_t p_rot, const Size2 &p_scale, const real_t } Size2 Transform2D::get_scale() const { - real_t det_sign = Math::sign(basis_determinant()); + real_t det_sign = SIGN(determinant()); return Size2(columns[0].length(), det_sign * columns[1].length()); } @@ -140,7 +140,7 @@ void Transform2D::scale_basis(const Size2 &p_scale) { columns[1][1] *= p_scale.y; } -void Transform2D::translate_local(const real_t p_tx, const real_t p_ty) { +void Transform2D::translate_local(real_t p_tx, real_t p_ty) { translate_local(Vector2(p_tx, p_ty)); } @@ -155,7 +155,7 @@ void Transform2D::orthonormalize() { Vector2 y = columns[1]; x.normalize(); - y = (y - x * (x.dot(y))); + y = y - x * x.dot(y); y.normalize(); columns[0] = x; @@ -163,9 +163,21 @@ void Transform2D::orthonormalize() { } Transform2D Transform2D::orthonormalized() const { - Transform2D on = *this; - on.orthonormalize(); - return on; + Transform2D ortho = *this; + ortho.orthonormalize(); + return ortho; +} + +bool Transform2D::is_conformal() const { + // Non-flipped case. + if (Math::is_equal_approx(columns[0][0], columns[1][1]) && Math::is_equal_approx(columns[0][1], -columns[1][0])) { + return true; + } + // Flipped case. + if (Math::is_equal_approx(columns[0][0], -columns[1][1]) && Math::is_equal_approx(columns[0][1], columns[1][0])) { + return true; + } + return false; } bool Transform2D::is_equal_approx(const Transform2D &p_transform) const { @@ -225,12 +237,6 @@ Transform2D Transform2D::operator*(const Transform2D &p_transform) const { return t; } -Transform2D Transform2D::basis_scaled(const Size2 &p_scale) const { - Transform2D copy = *this; - copy.scale_basis(p_scale); - return copy; -} - Transform2D Transform2D::scaled(const Size2 &p_scale) const { // Equivalent to left multiplication Transform2D copy = *this; @@ -259,67 +265,52 @@ Transform2D Transform2D::translated_local(const Vector2 &p_offset) const { return Transform2D(columns[0], columns[1], columns[2] + basis_xform(p_offset)); } -Transform2D Transform2D::rotated(const real_t p_angle) const { +Transform2D Transform2D::rotated(real_t p_angle) const { // Equivalent to left multiplication return Transform2D(p_angle, Vector2()) * (*this); } -Transform2D Transform2D::rotated_local(const real_t p_angle) const { +Transform2D Transform2D::rotated_local(real_t p_angle) const { // Equivalent to right multiplication return (*this) * Transform2D(p_angle, Vector2()); // Could be optimized, because origin transform can be skipped. } -real_t Transform2D::basis_determinant() const { +real_t Transform2D::determinant() const { return columns[0].x * columns[1].y - columns[0].y * columns[1].x; } -Transform2D Transform2D::interpolate_with(const Transform2D &p_transform, const real_t p_c) const { - //extract parameters - Vector2 p1 = get_origin(); - Vector2 p2 = p_transform.get_origin(); - - real_t r1 = get_rotation(); - real_t r2 = p_transform.get_rotation(); - - Size2 s1 = get_scale(); - Size2 s2 = p_transform.get_scale(); - - //slerp rotation - Vector2 v1(Math::cos(r1), Math::sin(r1)); - Vector2 v2(Math::cos(r2), Math::sin(r2)); - - real_t dot = v1.dot(v2); - - dot = Math::clamp(dot, (real_t)-1.0, (real_t)1.0); - - Vector2 v; - - if (dot > 0.9995f) { - v = v1.lerp(v2, p_c).normalized(); //linearly interpolate to avoid numerical precision issues - } else { - real_t angle = p_c * Math::acos(dot); - Vector2 v3 = (v2 - v1 * dot).normalized(); - v = v1 * Math::cos(angle) + v3 * Math::sin(angle); - } - - //construct matrix - Transform2D res(v.angle(), p1.lerp(p2, p_c)); - res.scale_basis(s1.lerp(s2, p_c)); - return res; +Transform2D Transform2D::interpolate_with(const Transform2D &p_transform, real_t p_weight) const { + return Transform2D( + Math::lerp_angle(get_rotation(), p_transform.get_rotation(), p_weight), + get_scale().lerp(p_transform.get_scale(), p_weight), + Math::lerp_angle(get_skew(), p_transform.get_skew(), p_weight), + get_origin().lerp(p_transform.get_origin(), p_weight)); } -void Transform2D::operator*=(const real_t p_val) { +void Transform2D::operator*=(real_t p_val) { columns[0] *= p_val; columns[1] *= p_val; columns[2] *= p_val; } -Transform2D Transform2D::operator*(const real_t p_val) const { +Transform2D Transform2D::operator*(real_t p_val) const { Transform2D ret(*this); ret *= p_val; return ret; } +void Transform2D::operator/=(real_t p_val) { + columns[0] /= p_val; + columns[1] /= p_val; + columns[2] /= p_val; +} + +Transform2D Transform2D::operator/(real_t p_val) const { + Transform2D ret(*this); + ret /= p_val; + return ret; +} + Transform2D::operator String() const { return "[X: " + columns[0].operator String() + ", Y: " + columns[1].operator String() + diff --git a/src/variant/transform3d.cpp b/src/variant/transform3d.cpp index fd5de033..ae5b9476 100644 --- a/src/variant/transform3d.cpp +++ b/src/variant/transform3d.cpp @@ -80,20 +80,20 @@ void Transform3D::rotate_basis(const Vector3 &p_axis, real_t p_angle) { basis.rotate(p_axis, p_angle); } -Transform3D Transform3D::looking_at(const Vector3 &p_target, const Vector3 &p_up) const { +Transform3D Transform3D::looking_at(const Vector3 &p_target, const Vector3 &p_up, bool p_use_model_front) const { #ifdef MATH_CHECKS ERR_FAIL_COND_V_MSG(origin.is_equal_approx(p_target), Transform3D(), "The transform's origin and target can't be equal."); #endif Transform3D t = *this; - t.basis = Basis::looking_at(p_target - origin, p_up); + t.basis = Basis::looking_at(p_target - origin, p_up, p_use_model_front); return t; } -void Transform3D::set_look_at(const Vector3 &p_eye, const Vector3 &p_target, const Vector3 &p_up) { +void Transform3D::set_look_at(const Vector3 &p_eye, const Vector3 &p_target, const Vector3 &p_up, bool p_use_model_front) { #ifdef MATH_CHECKS ERR_FAIL_COND_MSG(p_eye.is_equal_approx(p_target), "The eye and target vectors can't be equal."); #endif - basis = Basis::looking_at(p_target - p_eye, p_up); + basis = Basis::looking_at(p_target - p_eye, p_up, p_use_model_front); origin = p_eye; } @@ -200,17 +200,28 @@ Transform3D Transform3D::operator*(const Transform3D &p_transform) const { return t; } -void Transform3D::operator*=(const real_t p_val) { +void Transform3D::operator*=(real_t p_val) { origin *= p_val; basis *= p_val; } -Transform3D Transform3D::operator*(const real_t p_val) const { +Transform3D Transform3D::operator*(real_t p_val) const { Transform3D ret(*this); ret *= p_val; return ret; } +void Transform3D::operator/=(real_t p_val) { + basis /= p_val; + origin /= p_val; +} + +Transform3D Transform3D::operator/(real_t p_val) const { + Transform3D ret(*this); + ret /= p_val; + return ret; +} + Transform3D::operator String() const { return "[X: " + basis.get_column(0).operator String() + ", Y: " + basis.get_column(1).operator String() + @@ -230,9 +241,9 @@ Transform3D::Transform3D(const Vector3 &p_x, const Vector3 &p_y, const Vector3 & basis.set_column(2, p_z); } -Transform3D::Transform3D(real_t xx, real_t xy, real_t xz, real_t yx, real_t yy, real_t yz, real_t zx, real_t zy, real_t zz, real_t ox, real_t oy, real_t oz) { - basis = Basis(xx, xy, xz, yx, yy, yz, zx, zy, zz); - origin = Vector3(ox, oy, oz); +Transform3D::Transform3D(real_t p_xx, real_t p_xy, real_t p_xz, real_t p_yx, real_t p_yy, real_t p_yz, real_t p_zx, real_t p_zy, real_t p_zz, real_t p_ox, real_t p_oy, real_t p_oz) { + basis = Basis(p_xx, p_xy, p_xz, p_yx, p_yy, p_yz, p_zx, p_zy, p_zz); + origin = Vector3(p_ox, p_oy, p_oz); } } // namespace godot diff --git a/src/variant/vector2.cpp b/src/variant/vector2.cpp index 043d13bd..43386524 100644 --- a/src/variant/vector2.cpp +++ b/src/variant/vector2.cpp @@ -41,7 +41,7 @@ real_t Vector2::angle() const { return Math::atan2(y, x); } -Vector2 Vector2::from_angle(const real_t p_angle) { +Vector2 Vector2::from_angle(real_t p_angle) { return Vector2(Math::cos(p_angle), Math::sin(p_angle)); } @@ -113,7 +113,7 @@ Vector2 Vector2::round() const { return Vector2(Math::round(x), Math::round(y)); } -Vector2 Vector2::rotated(const real_t p_by) const { +Vector2 Vector2::rotated(real_t p_by) const { real_t sine = Math::sin(p_by); real_t cosi = Math::cos(p_by); return Vector2( @@ -121,7 +121,7 @@ Vector2 Vector2::rotated(const real_t p_by) const { x * sine + y * cosi); } -Vector2 Vector2::posmod(const real_t p_mod) const { +Vector2 Vector2::posmod(real_t p_mod) const { return Vector2(Math::fposmod(x, p_mod), Math::fposmod(y, p_mod)); } @@ -157,7 +157,7 @@ Vector2 Vector2::snappedf(real_t p_step) const { Math::snapped(y, p_step)); } -Vector2 Vector2::limit_length(const real_t p_len) const { +Vector2 Vector2::limit_length(real_t p_len) const { const real_t l = length(); Vector2 v = *this; if (l > 0 && p_len < l) { @@ -168,7 +168,7 @@ Vector2 Vector2::limit_length(const real_t p_len) const { return v; } -Vector2 Vector2::move_toward(const Vector2 &p_to, const real_t p_delta) const { +Vector2 Vector2::move_toward(const Vector2 &p_to, real_t p_delta) const { Vector2 v = *this; Vector2 vd = p_to - v; real_t len = vd.length(); @@ -178,9 +178,9 @@ Vector2 Vector2::move_toward(const Vector2 &p_to, const real_t p_delta) const { // slide returns the component of the vector along the given plane, specified by its normal vector. Vector2 Vector2::slide(const Vector2 &p_normal) const { #ifdef MATH_CHECKS - ERR_FAIL_COND_V_MSG(!p_normal.is_normalized(), Vector2(), "The normal Vector2 must be normalized."); + ERR_FAIL_COND_V_MSG(!p_normal.is_normalized(), Vector2(), "The normal Vector2 " + p_normal.operator String() + "must be normalized."); #endif - return *this - p_normal * this->dot(p_normal); + return *this - p_normal * dot(p_normal); } Vector2 Vector2::bounce(const Vector2 &p_normal) const { @@ -189,9 +189,9 @@ Vector2 Vector2::bounce(const Vector2 &p_normal) const { Vector2 Vector2::reflect(const Vector2 &p_normal) const { #ifdef MATH_CHECKS - ERR_FAIL_COND_V_MSG(!p_normal.is_normalized(), Vector2(), "The normal Vector2 must be normalized."); + ERR_FAIL_COND_V_MSG(!p_normal.is_normalized(), Vector2(), "The normal Vector2 " + p_normal.operator String() + "must be normalized."); #endif - return 2.0f * p_normal * this->dot(p_normal) - *this; + return 2.0f * p_normal * dot(p_normal) - *this; } bool Vector2::is_equal_approx(const Vector2 &p_v) const { @@ -207,7 +207,7 @@ bool Vector2::is_finite() const { } Vector2::operator String() const { - return "(" + String::num_real(x, false) + ", " + String::num_real(y, false) + ")"; + return "(" + String::num_real(x, true) + ", " + String::num_real(y, true) + ")"; } Vector2::operator Vector2i() const { diff --git a/src/variant/vector2i.cpp b/src/variant/vector2i.cpp index f74db15f..bba36c18 100644 --- a/src/variant/vector2i.cpp +++ b/src/variant/vector2i.cpp @@ -37,18 +37,6 @@ namespace godot { -Vector2i Vector2i::snapped(const Vector2i &p_step) const { - return Vector2i( - Math::snapped(x, p_step.x), - Math::snapped(y, p_step.y)); -} - -Vector2i Vector2i::snappedi(int32_t p_step) const { - return Vector2i( - Math::snapped(x, p_step), - Math::snapped(y, p_step)); -} - Vector2i Vector2i::clamp(const Vector2i &p_min, const Vector2i &p_max) const { return Vector2i( CLAMP(x, p_min.x, p_max.x), @@ -61,20 +49,24 @@ Vector2i Vector2i::clampi(int32_t p_min, int32_t p_max) const { CLAMP(y, p_min, p_max)); } -int64_t Vector2i::length_squared() const { - return x * (int64_t)x + y * (int64_t)y; +Vector2i Vector2i::snapped(const Vector2i &p_step) const { + return Vector2i( + Math::snapped(x, p_step.x), + Math::snapped(y, p_step.y)); } -double Vector2i::length() const { - return Math::sqrt((double)length_squared()); +Vector2i Vector2i::snappedi(int32_t p_step) const { + return Vector2i( + Math::snapped(x, p_step), + Math::snapped(y, p_step)); } -int64_t Vector2i::distance_squared_to(const Vector2i &p_to) const { - return (p_to - *this).length_squared(); +int64_t Vector2i::length_squared() const { + return x * (int64_t)x + y * (int64_t)y; } -double Vector2i::distance_to(const Vector2i &p_to) const { - return (p_to - *this).length(); +double Vector2i::length() const { + return Math::sqrt((double)length_squared()); } Vector2i Vector2i::operator+(const Vector2i &p_v) const { @@ -99,39 +91,39 @@ Vector2i Vector2i::operator*(const Vector2i &p_v1) const { return Vector2i(x * p_v1.x, y * p_v1.y); } -Vector2i Vector2i::operator*(const int32_t &rvalue) const { - return Vector2i(x * rvalue, y * rvalue); +Vector2i Vector2i::operator*(int32_t p_rvalue) const { + return Vector2i(x * p_rvalue, y * p_rvalue); } -void Vector2i::operator*=(const int32_t &rvalue) { - x *= rvalue; - y *= rvalue; +void Vector2i::operator*=(int32_t p_rvalue) { + x *= p_rvalue; + y *= p_rvalue; } Vector2i Vector2i::operator/(const Vector2i &p_v1) const { return Vector2i(x / p_v1.x, y / p_v1.y); } -Vector2i Vector2i::operator/(const int32_t &rvalue) const { - return Vector2i(x / rvalue, y / rvalue); +Vector2i Vector2i::operator/(int32_t p_rvalue) const { + return Vector2i(x / p_rvalue, y / p_rvalue); } -void Vector2i::operator/=(const int32_t &rvalue) { - x /= rvalue; - y /= rvalue; +void Vector2i::operator/=(int32_t p_rvalue) { + x /= p_rvalue; + y /= p_rvalue; } Vector2i Vector2i::operator%(const Vector2i &p_v1) const { return Vector2i(x % p_v1.x, y % p_v1.y); } -Vector2i Vector2i::operator%(const int32_t &rvalue) const { - return Vector2i(x % rvalue, y % rvalue); +Vector2i Vector2i::operator%(int32_t p_rvalue) const { + return Vector2i(x % p_rvalue, y % p_rvalue); } -void Vector2i::operator%=(const int32_t &rvalue) { - x %= rvalue; - y %= rvalue; +void Vector2i::operator%=(int32_t p_rvalue) { + x %= p_rvalue; + y %= p_rvalue; } Vector2i Vector2i::operator-() const { diff --git a/src/variant/vector3.cpp b/src/variant/vector3.cpp index e3be49ca..81eebee2 100644 --- a/src/variant/vector3.cpp +++ b/src/variant/vector3.cpp @@ -39,11 +39,11 @@ namespace godot { -void Vector3::rotate(const Vector3 &p_axis, const real_t p_angle) { +void Vector3::rotate(const Vector3 &p_axis, real_t p_angle) { *this = Basis(p_axis, p_angle).xform(*this); } -Vector3 Vector3::rotated(const Vector3 &p_axis, const real_t p_angle) const { +Vector3 Vector3::rotated(const Vector3 &p_axis, real_t p_angle) const { Vector3 r = *this; r.rotate(p_axis, p_angle); return r; @@ -63,31 +63,31 @@ Vector3 Vector3::clampf(real_t p_min, real_t p_max) const { CLAMP(z, p_min, p_max)); } -void Vector3::snap(const Vector3 p_step) { +void Vector3::snap(const Vector3 &p_step) { x = Math::snapped(x, p_step.x); y = Math::snapped(y, p_step.y); z = Math::snapped(z, p_step.z); } +Vector3 Vector3::snapped(const Vector3 &p_step) const { + Vector3 v = *this; + v.snap(p_step); + return v; +} + void Vector3::snapf(real_t p_step) { x = Math::snapped(x, p_step); y = Math::snapped(y, p_step); z = Math::snapped(z, p_step); } -Vector3 Vector3::snapped(const Vector3 p_step) const { - Vector3 v = *this; - v.snap(p_step); - return v; -} - Vector3 Vector3::snappedf(real_t p_step) const { Vector3 v = *this; v.snapf(p_step); return v; } -Vector3 Vector3::limit_length(const real_t p_len) const { +Vector3 Vector3::limit_length(real_t p_len) const { const real_t l = length(); Vector3 v = *this; if (l > 0 && p_len < l) { @@ -98,7 +98,7 @@ Vector3 Vector3::limit_length(const real_t p_len) const { return v; } -Vector3 Vector3::move_toward(const Vector3 &p_to, const real_t p_delta) const { +Vector3 Vector3::move_toward(const Vector3 &p_to, real_t p_delta) const { Vector3 v = *this; Vector3 vd = p_to - v; real_t len = vd.length(); @@ -124,23 +124,25 @@ Vector2 Vector3::octahedron_encode() const { Vector3 Vector3::octahedron_decode(const Vector2 &p_oct) { Vector2 f(p_oct.x * 2.0f - 1.0f, p_oct.y * 2.0f - 1.0f); Vector3 n(f.x, f.y, 1.0f - Math::abs(f.x) - Math::abs(f.y)); - float t = CLAMP(-n.z, 0.0f, 1.0f); + const real_t t = CLAMP(-n.z, 0.0f, 1.0f); n.x += n.x >= 0 ? -t : t; n.y += n.y >= 0 ? -t : t; return n.normalized(); } -Vector2 Vector3::octahedron_tangent_encode(const float sign) const { - Vector2 res = this->octahedron_encode(); +Vector2 Vector3::octahedron_tangent_encode(float p_sign) const { + const real_t bias = 1.0f / (real_t)32767.0f; + Vector2 res = octahedron_encode(); + res.y = MAX(res.y, bias); res.y = res.y * 0.5f + 0.5f; - res.y = sign >= 0.0f ? res.y : 1 - res.y; + res.y = p_sign >= 0.0f ? res.y : 1 - res.y; return res; } -Vector3 Vector3::octahedron_tangent_decode(const Vector2 &p_oct, float *sign) { +Vector3 Vector3::octahedron_tangent_decode(const Vector2 &p_oct, float *r_sign) { Vector2 oct_compressed = p_oct; oct_compressed.y = oct_compressed.y * 2 - 1; - *sign = oct_compressed.y >= 0.0f ? 1.0f : -1.0f; + *r_sign = oct_compressed.y >= 0.0f ? 1.0f : -1.0f; oct_compressed.y = Math::abs(oct_compressed.y); Vector3 res = Vector3::octahedron_decode(oct_compressed); return res; @@ -167,7 +169,7 @@ bool Vector3::is_finite() const { } Vector3::operator String() const { - return "(" + String::num_real(x, false) + ", " + String::num_real(y, false) + ", " + String::num_real(z, false) + ")"; + return "(" + String::num_real(x, true) + ", " + String::num_real(y, true) + ", " + String::num_real(z, true) + ")"; } Vector3::operator Vector3i() const { diff --git a/src/variant/vector3i.cpp b/src/variant/vector3i.cpp index 7d177665..f73ff3b0 100644 --- a/src/variant/vector3i.cpp +++ b/src/variant/vector3i.cpp @@ -37,20 +37,6 @@ namespace godot { -Vector3i Vector3i::snapped(const Vector3i &p_step) const { - return Vector3i( - Math::snapped(x, p_step.x), - Math::snapped(y, p_step.y), - Math::snapped(z, p_step.z)); -} - -Vector3i Vector3i::snappedi(int32_t p_step) const { - return Vector3i( - Math::snapped(x, p_step), - Math::snapped(y, p_step), - Math::snapped(z, p_step)); -} - Vector3i::Axis Vector3i::min_axis_index() const { return x < y ? (x < z ? Vector3i::AXIS_X : Vector3i::AXIS_Z) : (y < z ? Vector3i::AXIS_Y : Vector3i::AXIS_Z); } @@ -73,6 +59,20 @@ Vector3i Vector3i::clampi(int32_t p_min, int32_t p_max) const { CLAMP(z, p_min, p_max)); } +Vector3i Vector3i::snapped(const Vector3i &p_step) const { + return Vector3i( + Math::snapped(x, p_step.x), + Math::snapped(y, p_step.y), + Math::snapped(z, p_step.z)); +} + +Vector3i Vector3i::snappedi(int32_t p_step) const { + return Vector3i( + Math::snapped(x, p_step), + Math::snapped(y, p_step), + Math::snapped(z, p_step)); +} + Vector3i::operator String() const { return "(" + itos(x) + ", " + itos(y) + ", " + itos(z) + ")"; } diff --git a/src/variant/vector4.cpp b/src/variant/vector4.cpp index 98877b0b..e25198d7 100644 --- a/src/variant/vector4.cpp +++ b/src/variant/vector4.cpp @@ -119,7 +119,7 @@ Vector4 Vector4::abs() const { } Vector4 Vector4::sign() const { - return Vector4(Math::sign(x), Math::sign(y), Math::sign(z), Math::sign(w)); + return Vector4(SIGN(x), SIGN(y), SIGN(z), SIGN(w)); } Vector4 Vector4::floor() const { @@ -134,15 +134,16 @@ Vector4 Vector4::round() const { return Vector4(Math::round(x), Math::round(y), Math::round(z), Math::round(w)); } -Vector4 Vector4::lerp(const Vector4 &p_to, const real_t p_weight) const { - return Vector4( - x + (p_weight * (p_to.x - x)), - y + (p_weight * (p_to.y - y)), - z + (p_weight * (p_to.z - z)), - w + (p_weight * (p_to.w - w))); +Vector4 Vector4::lerp(const Vector4 &p_to, real_t p_weight) const { + Vector4 res = *this; + res.x = Math::lerp(res.x, p_to.x, p_weight); + res.y = Math::lerp(res.y, p_to.y, p_weight); + res.z = Math::lerp(res.z, p_to.z, p_weight); + res.w = Math::lerp(res.w, p_to.w, p_weight); + return res; } -Vector4 Vector4::cubic_interpolate(const Vector4 &p_b, const Vector4 &p_pre_a, const Vector4 &p_post_b, const real_t p_weight) const { +Vector4 Vector4::cubic_interpolate(const Vector4 &p_b, const Vector4 &p_pre_a, const Vector4 &p_post_b, real_t p_weight) const { Vector4 res = *this; res.x = Math::cubic_interpolate(res.x, p_b.x, p_pre_a.x, p_post_b.x, p_weight); res.y = Math::cubic_interpolate(res.y, p_b.y, p_pre_a.y, p_post_b.y, p_weight); @@ -151,7 +152,7 @@ Vector4 Vector4::cubic_interpolate(const Vector4 &p_b, const Vector4 &p_pre_a, c return res; } -Vector4 Vector4::cubic_interpolate_in_time(const Vector4 &p_b, const Vector4 &p_pre_a, const Vector4 &p_post_b, const real_t p_weight, const real_t &p_b_t, const real_t &p_pre_a_t, const real_t &p_post_b_t) const { +Vector4 Vector4::cubic_interpolate_in_time(const Vector4 &p_b, const Vector4 &p_pre_a, const Vector4 &p_post_b, real_t p_weight, real_t p_b_t, real_t p_pre_a_t, real_t p_post_b_t) const { Vector4 res = *this; res.x = Math::cubic_interpolate_in_time(res.x, p_b.x, p_pre_a.x, p_post_b.x, p_weight, p_b_t, p_pre_a_t, p_post_b_t); res.y = Math::cubic_interpolate_in_time(res.y, p_b.y, p_pre_a.y, p_post_b.y, p_weight, p_b_t, p_pre_a_t, p_post_b_t); @@ -160,7 +161,7 @@ Vector4 Vector4::cubic_interpolate_in_time(const Vector4 &p_b, const Vector4 &p_ return res; } -Vector4 Vector4::posmod(const real_t p_mod) const { +Vector4 Vector4::posmod(real_t p_mod) const { return Vector4(Math::fposmod(x, p_mod), Math::fposmod(y, p_mod), Math::fposmod(z, p_mod), Math::fposmod(w, p_mod)); } @@ -215,9 +216,13 @@ Vector4 Vector4::clampf(real_t p_min, real_t p_max) const { } Vector4::operator String() const { - return "(" + String::num_real(x, false) + ", " + String::num_real(y, false) + ", " + String::num_real(z, false) + ", " + String::num_real(w, false) + ")"; + return "(" + String::num_real(x, true) + ", " + String::num_real(y, true) + ", " + String::num_real(z, true) + ", " + String::num_real(w, true) + ")"; } static_assert(sizeof(Vector4) == 4 * sizeof(real_t)); +Vector4::operator Vector4i() const { + return Vector4i(x, y, z, w); +} + } // namespace godot diff --git a/src/variant/vector4i.cpp b/src/variant/vector4i.cpp index f80af0e2..bf4d1ece 100644 --- a/src/variant/vector4i.cpp +++ b/src/variant/vector4i.cpp @@ -37,22 +37,6 @@ namespace godot { -Vector4i Vector4i::snapped(const Vector4i &p_step) const { - return Vector4i( - Math::snapped(x, p_step.x), - Math::snapped(y, p_step.y), - Math::snapped(z, p_step.z), - Math::snapped(w, p_step.w)); -} - -Vector4i Vector4i::snappedi(int32_t p_step) const { - return Vector4i( - Math::snapped(x, p_step), - Math::snapped(y, p_step), - Math::snapped(z, p_step), - Math::snapped(w, p_step)); -} - Vector4i::Axis Vector4i::min_axis_index() const { uint32_t min_index = 0; int32_t min_value = x; @@ -93,6 +77,22 @@ Vector4i Vector4i::clampi(int32_t p_min, int32_t p_max) const { CLAMP(w, p_min, p_max)); } +Vector4i Vector4i::snapped(const Vector4i &p_step) const { + return Vector4i( + Math::snapped(x, p_step.x), + Math::snapped(y, p_step.y), + Math::snapped(z, p_step.z), + Math::snapped(w, p_step.w)); +} + +Vector4i Vector4i::snappedi(int32_t p_step) const { + return Vector4i( + Math::snapped(x, p_step), + Math::snapped(y, p_step), + Math::snapped(z, p_step), + Math::snapped(w, p_step)); +} + Vector4i::operator String() const { return "(" + itos(x) + ", " + itos(y) + ", " + itos(z) + ", " + itos(w) + ")"; } diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 9205aa08..ebbcbb7b 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -5,77 +5,65 @@ Integration Testing The Test target used to validate changes in the GitHub CI. ]=======================================================================] -message( STATUS "Testing Integration targets are enabled.") - -# Generate Doc Data -file( GLOB_RECURSE DOC_XML - LIST_DIRECTORIES NO - CONFIGURE_DEPENDS - "${CMAKE_CURRENT_SOURCE_DIR}/doc_classes/*.xml" ) - -foreach( TARGET_ALIAS template_debug template_release editor ) - set( TARGET_NAME "godot-cpp.test.${TARGET_ALIAS}" ) - - add_library( ${TARGET_NAME} SHARED EXCLUDE_FROM_ALL ) - - target_sources( ${TARGET_NAME} - PRIVATE - src/example.cpp - src/example.h - src/register_types.cpp - src/register_types.h - src/tests.h +message(STATUS "Testing Integration targets are enabled.") + +set(TARGET_NAME "godot-cpp-test") + +add_library(${TARGET_NAME} SHARED EXCLUDE_FROM_ALL) + +target_sources( + ${TARGET_NAME} + PRIVATE src/example.cpp src/example.h src/register_types.cpp src/register_types.h src/tests.h +) + +# conditionally add doc data to compile output +if(GODOTCPP_TARGET MATCHES "editor|template_debug") + file(GLOB_RECURSE DOC_XML LIST_DIRECTORIES NO CONFIGURE_DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/doc_classes/*.xml") + target_doc_sources( ${TARGET_NAME} ${DOC_XML} ) +endif() + +set(OUTPUT_DIR "${CMAKE_CURRENT_SOURCE_DIR}/project/bin/") + +# Link to godot-cpp target +target_link_libraries(${TARGET_NAME} PRIVATE godot-cpp) + +### Get useful properties from godot-cpp target +get_target_property(GODOTCPP_SUFFIX godot-cpp GODOTCPP_SUFFIX) + +# gersemi: off +set_target_properties( + ${TARGET_NAME} + PROPERTIES + CXX_STANDARD 17 + CXX_EXTENSIONS OFF + CXX_VISIBILITY_PRESET ${GODOTCPP_SYMBOL_VISIBILITY} + + POSITION_INDEPENDENT_CODE ON + BUILD_RPATH_USE_ORIGIN ON + + # Try to ensure only static libraries are selected to be linked to. + LINK_SEARCH_START_STATIC ON + LINK_SEARCH_END_STATIC ON + + # NOTE: Wrapping the output variables inside a generator expression + # prevents msvc generator from adding addition Config Directories + LIBRARY_OUTPUT_DIRECTORY "$<1:${OUTPUT_DIR}>" + RUNTIME_OUTPUT_DIRECTORY "$<1:${OUTPUT_DIR}>" + PDB_OUTPUT_DIRECTORY "$<1:${OUTPUT_DIR}>" #MSVC Only, ignored on other platforms + + PREFIX "lib" + OUTPUT_NAME "gdexample${GODOTCPP_SUFFIX}" + # TODO rename the file for both CMake and SCons + + # Some IDE's respect this property to logically group targets + FOLDER "godot-cpp" +) +# gersemi: on + +# CMAKE_SYSTEM_NAME refers to the target system +if(CMAKE_SYSTEM_NAME STREQUAL Darwin) + set_target_properties( + ${TARGET_NAME} + PROPERTIES SUFFIX "" OUTPUT_DIR "${OUTPUT_DIR}/libgdexample.macos.${GODOTCPP_TARGET}.framework" ) - - # conditionally add doc data to compile output - if( TARGET_ALIAS MATCHES "editor|template_debug" ) - target_doc_sources( ${TARGET_NAME} ${DOC_XML} ) - endif() - - set( OUTPUT_DIR "${CMAKE_CURRENT_SOURCE_DIR}/project/bin/" ) - - # Link to godot-cpp target - set( LINK_TARGET "godot-cpp::${TARGET_ALIAS}" ) - target_link_libraries( ${TARGET_NAME} PRIVATE ${LINK_TARGET} ) - - ### Get useful properties from godot-cpp target - get_target_property( GODOTCPP_SUFFIX ${LINK_TARGET} GODOTCPP_SUFFIX ) - get_target_property( OSX_ARCH ${LINK_TARGET} OSX_ARCHITECTURES ) - - set_target_properties( ${TARGET_NAME} - PROPERTIES - CXX_STANDARD 17 - CXX_EXTENSIONS OFF - CXX_VISIBILITY_PRESET ${GODOTCPP_SYMBOL_VISIBILITY} - - POSITION_INDEPENDENT_CODE ON - BUILD_RPATH_USE_ORIGIN ON - - # Try to ensure only static libraries are selected to be linked to. - LINK_SEARCH_START_STATIC ON - LINK_SEARCH_END_STATIC ON - - # NOTE: Wrapping the output variables inside a generator expression - # prevents msvc generator from adding addition Config Directories - LIBRARY_OUTPUT_DIRECTORY "$<1:${OUTPUT_DIR}>" - RUNTIME_OUTPUT_DIRECTORY "$<1:${OUTPUT_DIR}>" - PDB_OUTPUT_DIRECTORY "$<1:${OUTPUT_DIR}>" #MSVC Only, ignored on other platforms - - PREFIX "lib" - OUTPUT_NAME "gdexample${GODOTCPP_SUFFIX}" - - # Some IDE's respect this property to logically group targets - FOLDER "godot-cpp" - ) - - # CMAKE_SYSTEM_NAME refers to the target system - if( CMAKE_SYSTEM_NAME STREQUAL Darwin ) - set_target_properties( ${TARGET_NAME} - PROPERTIES - SUFFIX "" - OUTPUT_DIR "${OUTPUT_DIR}/libgdexample.macos.${TARGET_ALIAS}.framework" - OSX_ARCHITECTURES "${OSX_ARCH}" - ) - endif() - -endforeach() +endif() diff --git a/test/project/example.gd.uid b/test/project/example.gd.uid new file mode 100644 index 00000000..b1c36967 --- /dev/null +++ b/test/project/example.gd.uid @@ -0,0 +1 @@ +uid://1htvqeulgew6 diff --git a/test/project/example.gdextension.uid b/test/project/example.gdextension.uid new file mode 100644 index 00000000..fa1a310e --- /dev/null +++ b/test/project/example.gdextension.uid @@ -0,0 +1 @@ +uid://dhm7q8lygqyol diff --git a/test/project/main.gd.uid b/test/project/main.gd.uid new file mode 100644 index 00000000..1266fc06 --- /dev/null +++ b/test/project/main.gd.uid @@ -0,0 +1 @@ +uid://bujp6xsb8pfqk diff --git a/test/project/main.tscn b/test/project/main.tscn index e786025a..89988fd3 100644 --- a/test/project/main.tscn +++ b/test/project/main.tscn @@ -1,7 +1,7 @@ [gd_scene load_steps=3 format=3 uid="uid://dmx2xuigcpvt4"] -[ext_resource type="Script" path="res://main.gd" id="1_qesh5"] -[ext_resource type="Script" path="res://example.gd" id="2_jju25"] +[ext_resource type="Script" uid="uid://bujp6xsb8pfqk" path="res://main.gd" id="1_qesh5"] +[ext_resource type="Script" uid="uid://1htvqeulgew6" path="res://example.gd" id="2_jju25"] [node name="Node" type="Node"] script = ExtResource("1_qesh5") diff --git a/test/project/project.godot b/test/project/project.godot index df3dd70f..9b711dd6 100644 --- a/test/project/project.godot +++ b/test/project/project.godot @@ -12,7 +12,7 @@ config_version=5 config/name="GDExtension Test Project" run/main_scene="res://main.tscn" -config/features=PackedStringArray("4.3") +config/features=PackedStringArray("4.4") config/icon="res://icon.png" [native_extensions] diff --git a/test/project/test_base.gd.uid b/test/project/test_base.gd.uid new file mode 100644 index 00000000..15057856 --- /dev/null +++ b/test/project/test_base.gd.uid @@ -0,0 +1 @@ +uid://dwbwwljpx3cp diff --git a/test/src/example.h b/test/src/example.h index 6e6ff399..b40fcab1 100644 --- a/test/src/example.h +++ b/test/src/example.h @@ -3,8 +3,7 @@ * This is free and unencumbered software released into the public domain. */ -#ifndef EXAMPLE_CLASS_H -#define EXAMPLE_CLASS_H +#pragma once // We don't need windows.h in this example plugin but many others do, and it can // lead to annoying situations due to the ton of macros it defines. @@ -289,5 +288,3 @@ class ExamplePrzykΕ‚ad : public RefCounted { public: String get_the_word() const; }; - -#endif // EXAMPLE_CLASS_H diff --git a/test/src/register_types.h b/test/src/register_types.h index 5f124da7..d19fd01a 100644 --- a/test/src/register_types.h +++ b/test/src/register_types.h @@ -3,8 +3,7 @@ * This is free and unencumbered software released into the public domain. */ -#ifndef EXAMPLE_REGISTER_TYPES_H -#define EXAMPLE_REGISTER_TYPES_H +#pragma once #include @@ -12,5 +11,3 @@ using namespace godot; void initialize_example_module(ModuleInitializationLevel p_level); void uninitialize_example_module(ModuleInitializationLevel p_level); - -#endif // EXAMPLE_REGISTER_TYPES_H diff --git a/test/src/tests.h b/test/src/tests.h index 55835fc1..a2c39be0 100644 --- a/test/src/tests.h +++ b/test/src/tests.h @@ -3,8 +3,7 @@ * This is free and unencumbered software released into the public domain. */ -#ifndef TESTS_H -#define TESTS_H +#pragma once #include #include @@ -25,5 +24,3 @@ #include #include #include - -#endif // TESTS_H diff --git a/tools/godotcpp.py b/tools/godotcpp.py index 80a24959..ca649773 100644 --- a/tools/godotcpp.py +++ b/tools/godotcpp.py @@ -2,6 +2,7 @@ import platform import sys +from SCons import __version__ as scons_raw_version from SCons.Action import Action from SCons.Builder import Builder from SCons.Errors import UserError @@ -154,6 +155,7 @@ def scons_generate_bindings(target, source, env): _generate_bindings( api, + str(source[0]), env["generate_template_get_node"], "32" if "32" in env["arch"] else "64", env["precision"], @@ -379,6 +381,8 @@ def options(opts, env): def generate(env): + env.scons_version = env._get_major_minor_revision(scons_raw_version) + # Default num_jobs to local cpu count if not user specified. # SCons has a peculiarity where user-specified options won't be overridden # by SetOption, so we can rely on this to know if we should use our default. @@ -436,6 +440,17 @@ def generate(env): else: # Release opt_level = "speed" + # Allow marking includes as external/system to avoid raising warnings. + if env.scons_version < (4, 2): + env["_CPPEXTINCFLAGS"] = "${_concat(EXTINCPREFIX, CPPEXTPATH, EXTINCSUFFIX, __env__, RDirs, TARGET, SOURCE)}" + else: + env["_CPPEXTINCFLAGS"] = ( + "${_concat(EXTINCPREFIX, CPPEXTPATH, EXTINCSUFFIX, __env__, RDirs, TARGET, SOURCE, affect_signature=False)}" + ) + env["CPPEXTPATH"] = [] + env["EXTINCPREFIX"] = "-isystem " + env["EXTINCSUFFIX"] = "" + env["optimize"] = ARGUMENTS.get("optimize", opt_level) env["debug_symbols"] = get_cmdline_bool("debug_symbols", env.dev_build) @@ -466,8 +481,6 @@ def generate(env): # DEBUG_ENABLED enables debugging *features* and debug-only code, which is intended # to give *users* extra debugging information for their game development. env.Append(CPPDEFINES=["DEBUG_ENABLED"]) - # In upstream Godot this is added in typedefs.h when DEBUG_ENABLED is set. - env.Append(CPPDEFINES=["DEBUG_METHODS_ENABLED"]) if env.dev_build: # DEV_ENABLED enables *engine developer* code which should only be compiled for those diff --git a/tools/linux.py b/tools/linux.py index 9e85d880..ae801987 100644 --- a/tools/linux.py +++ b/tools/linux.py @@ -5,6 +5,7 @@ def options(opts): opts.Add(BoolVariable("use_llvm", "Use the LLVM compiler - only effective when targeting Linux", False)) + opts.Add(BoolVariable("use_static_cpp", "Link libgcc and libstdc++ statically for better portability", True)) def exists(env): @@ -37,6 +38,10 @@ def generate(env): env.Append(CCFLAGS=["-march=rv64gc"]) env.Append(LINKFLAGS=["-march=rv64gc"]) + # Link statically for portability + if env["use_static_cpp"]: + env.Append(LINKFLAGS=["-static-libgcc", "-static-libstdc++"]) + env.Append(CPPDEFINES=["LINUX_ENABLED", "UNIX_ENABLED"]) # Refer to https://github.com/godotengine/godot/blob/master/platform/linuxbsd/detect.py diff --git a/tools/macos.py b/tools/macos.py index f88e47ff..541249cb 100644 --- a/tools/macos.py +++ b/tools/macos.py @@ -63,14 +63,6 @@ def generate(env): env.Append(CCFLAGS=["-isysroot", env["macos_sdk_path"]]) env.Append(LINKFLAGS=["-isysroot", env["macos_sdk_path"]]) - env.Append( - LINKFLAGS=[ - "-framework", - "Cocoa", - "-Wl,-undefined,dynamic_lookup", - ] - ) - env.Append(CPPDEFINES=["MACOS_ENABLED", "UNIX_ENABLED"]) # Refer to https://github.com/godotengine/godot/blob/master/platform/macos/detect.py diff --git a/tools/windows.py b/tools/windows.py index f66bce42..93ca89e6 100644 --- a/tools/windows.py +++ b/tools/windows.py @@ -130,6 +130,11 @@ def generate(env): if env["silence_msvc"] and not env.GetOption("clean"): silence_msvc(env) + if not env["use_llvm"]: + env.AppendUnique(CCFLAGS=["/experimental:external", "/external:anglebrackets"]) + env.AppendUnique(CCFLAGS=["/external:W0"]) + env["EXTINCPREFIX"] = "/external:I" + elif (sys.platform == "win32" or sys.platform == "msys") and not env["mingw_prefix"]: env["use_mingw"] = True mingw.generate(env)