Compare commits

..

5 Commits

180 changed files with 8309 additions and 73973 deletions

View File

@@ -1,16 +0,0 @@
root = true
[*]
charset = utf-8
end_of_line = lf
indent_size = 4
indent_style = tab
insert_final_newline = true
trim_trailing_whitespace = true
[{*.py,SConstruct}]
indent_style = space
[*.{yml,yaml}]
indent_size = 2
indent_style = space

8
.gitattributes vendored
View File

@@ -1,2 +1,6 @@
# Normalize EOL for all files that Git considers text files
* text=auto eol=lf
*.c eol=lf
*.cpp eol=lf
*.gd eol=lf
*.tscn eol=lf
*.cfg eol=lf
*.godot eol=lf

View File

@@ -1,71 +0,0 @@
name: Bug report
description: Report a bug in the godot-cpp GDExtension/GDNative integration
body:
- type: markdown
attributes:
value: |
- When reporting bugs, you'll make our life simpler (and the fix will come sooner) if you follow the guidelines in this template.
- Write a descriptive issue title above.
- The golden rule is to **always open *one* issue for *one* bug**. If you notice several bugs and want to report them, make sure to create one new issue for each of them.
- Search [open](https://github.com/godotengine/godot-cpp/issues) and [closed](https://github.com/godotengine/godot-cpp/issues?q=is%3Aissue+is%3Aclosed) issues to ensure it has not already been reported. If you don't find a relevant match or if you're unsure, don't hesitate to **open a new issue**. The bugsquad will handle it from there if it's a duplicate.
- Verify that you are using a [supported Godot version](https://docs.godotengine.org/en/latest/about/release_policy.html).
- type: input
attributes:
label: Godot version
description: >
Specify the Git commit hash if using a development or non-official build.
If you use a custom build, please test if your issue is reproducible in official builds too.
placeholder: 3.3.stable, 4.0.dev (3041becc6)
validations:
required: true
- type: input
attributes:
label: godot-cpp version
description: >
Specify the Git commit hash if using a development build.
placeholder: 3.3.stable, 4.0.dev (3041becc6)
validations:
required: true
- type: input
attributes:
label: System information
description: |
- Specify the OS version, and when relevant hardware information.
- For issues that are likely OS-specific and/or graphics-related, please specify the CPU model and architecture.
- **Bug reports not including the required information may be closed at the maintainers' discretion.** If in doubt, always include all the requested information; it's better to include too much information than not enough information.
placeholder: Windows 10, Intel Core i5-7200U
validations:
required: true
- type: textarea
attributes:
label: Issue description
description: |
Describe your issue briefly. What doesn't work, and how do you expect it to work instead?
You can include images or videos with drag and drop, and format code blocks or logs with <code>```</code> tags.
validations:
required: true
- type: textarea
attributes:
label: Steps to reproduce
description: |
List of steps or sample code that reproduces the issue. Having reproducible issues is a prerequisite for contributors to be able to solve them.
If you include a minimal reproduction project below, you can detail how to use it here.
validations:
required: true
- type: textarea
attributes:
label: Minimal reproduction project
description: |
- A small Godot project which reproduces the issue, with no unnecessary files included. Be sure to not include the `.godot` folder in the archive (but keep `project.godot`).
- Required, unless the reproduction steps are trivial and don't require any project files to be followed. In this case, write "N/A" in the field.
- Drag and drop a ZIP archive to upload it. **Do not select another field until the project is done uploading.**
- **If you've been asked by a maintainer to upload a minimal reproduction project, you *must* do so within 7 days.** Otherwise, your bug report will be closed as it'll be considered too difficult to diagnose.
validations:
required: true

View File

@@ -1,14 +0,0 @@
blank_issues_enabled: false
contact_links:
- name: Godot proposals
url: https://github.com/godotengine/godot-proposals
about: Please submit feature proposals on the Godot proposals repository, not here.
- name: Godot documentation repository
url: https://github.com/godotengine/godot-docs
about: Please report issues with documentation on the Godot documentation repository, not here.
- name: Godot community channels
url: https://godotengine.org/community
about: Please ask for technical support on one of the other community channels, not here.

View File

@@ -1,24 +0,0 @@
name: Restore Godot build cache
description: Restore Godot build cache.
inputs:
cache-name:
description: The cache base name (job name by default).
default: ${{ github.job }}
scons-cache:
description: The SCons cache path.
default: ${{ github.workspace }}/.scons-cache/
runs:
using: composite
steps:
- name: Restore SCons cache directory
uses: actions/cache/restore@v4
with:
path: ${{ inputs.scons-cache }}
key: ${{ inputs.cache-name }}-${{ env.GODOT_BASE_BRANCH }}-${{ github.ref }}-${{ github.sha }}
restore-keys: |
${{ inputs.cache-name }}-${{ env.GODOT_BASE_BRANCH }}-${{ github.ref }}-${{ github.sha }}
${{ inputs.cache-name }}-${{ env.GODOT_BASE_BRANCH }}-${{ github.ref }}
${{ inputs.cache-name }}-${{ env.GODOT_BASE_BRANCH }}-refs/heads/${{ env.GODOT_BASE_BRANCH }}
${{ inputs.cache-name }}-${{ env.GODOT_BASE_BRANCH }}

View File

@@ -1,18 +0,0 @@
name: Save Godot build cache
description: Save Godot build cache.
inputs:
cache-name:
description: The cache base name (job name by default).
default: ${{ github.job }}
scons-cache:
description: The SCons cache path.
default: ${{ github.workspace }}/.scons-cache/
runs:
using: composite
steps:
- name: Save SCons cache directory
uses: actions/cache/save@v4
with:
path: ${{ inputs.scons-cache }}
key: ${{ inputs.cache-name }}-${{ env.GODOT_BASE_BRANCH }}-${{ github.ref }}-${{ github.sha }}

22
.github/actions/godot-cache/action.yml vendored Normal file
View File

@@ -0,0 +1,22 @@
name: Setup Godot build cache
description: Setup Godot build cache.
inputs:
cache-name:
description: The cache base name (job name by default).
default: "${{github.job}}"
scons-cache:
description: The scons cache path.
default: "${{github.workspace}}/.scons-cache/"
runs:
using: "composite"
steps:
# Upload cache on completion and check it out now
- name: Load .scons_cache directory
uses: actions/cache@v3
with:
path: ${{inputs.scons-cache}}
key: ${{inputs.cache-name}}-${{env.GODOT_BASE_BRANCH}}-${{github.ref}}-${{github.sha}}
restore-keys: |
${{inputs.cache-name}}-${{env.GODOT_BASE_BRANCH}}-${{github.ref}}-${{github.sha}}
${{inputs.cache-name}}-${{env.GODOT_BASE_BRANCH}}-${{github.ref}}
${{inputs.cache-name}}-${{env.GODOT_BASE_BRANCH}}

View File

@@ -1,62 +0,0 @@
name: Setup godot-cpp
description: Setup build dependencies for godot-cpp.
inputs:
platform:
required: true
description: Target platform.
em-version:
default: 3.1.62
description: Emscripten version.
windows-compiler:
required: true
description: The compiler toolchain to use on Windows ('mingw' or 'msvc').
type: choice
options:
- mingw
- msvc
default: mingw
mingw-version:
default: 12.2.0
description: MinGW version.
ndk-version:
default: r23c
description: Android NDK version.
scons-version:
default: 4.4.0
description: SCons version.
runs:
using: composite
steps:
- name: Setup Python (for SCons)
uses: actions/setup-python@v5
with:
python-version: 3.x
- name: Setup Android dependencies
if: inputs.platform == 'android'
uses: nttld/setup-ndk@v1
with:
ndk-version: ${{ inputs.ndk-version }}
link-to-sdk: true
- name: Setup Web dependencies
if: inputs.platform == 'web'
uses: mymindstorm/setup-emsdk@v14
with:
version: ${{ inputs.em-version }}
no-cache: true
- name: Setup MinGW for Windows/MinGW build
if: inputs.platform == 'windows' && inputs.windows-compiler == 'mingw'
uses: egor-tensin/setup-mingw@v2
with:
version: ${{ inputs.mingw-version }}
- name: Setup SCons
shell: bash
run: |
python -c "import sys; print(sys.version)"
python -m pip install scons==${{ inputs.scons-version }}
scons --version

View File

@@ -1,18 +1,12 @@
name: Continuous integration
on:
workflow_call:
on: [push, pull_request]
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.
GODOT_TEST_VERSION: master
# Use UTF-8 on Linux.
LANG: en_US.UTF-8
LC_ALL: en_US.UTF-8
concurrency:
group: ci-${{ github.actor }}-${{ github.head_ref || github.run_number }}-${{ github.ref }}
group: ci-${{github.actor}}-${{github.head_ref || github.run_number}}-${{github.ref}}
cancel-in-progress: true
jobs:
@@ -24,20 +18,18 @@ jobs:
matrix:
include:
- name: 🐧 Linux (GCC)
os: ubuntu-22.04
os: ubuntu-20.04
platform: linux
artifact-name: godot-cpp-linux-glibc2.27-x86_64-release
artifact-path: bin/libgodot-cpp.linux.template_release.x86_64.a
run-tests: true
cache-name: linux-x86_64
- name: 🐧 Linux (GCC, Double Precision)
os: ubuntu-22.04
os: ubuntu-20.04
platform: linux
artifact-name: godot-cpp-linux-glibc2.27-x86_64-double-release
artifact-path: bin/libgodot-cpp.linux.template_release.double.x86_64.a
flags: precision=double
run-tests: false
cache-name: linux-x86_64-f64
- name: 🏁 Windows (x86_64, MSVC)
@@ -45,7 +37,6 @@ jobs:
platform: windows
artifact-name: godot-cpp-windows-msvc2019-x86_64-release
artifact-path: bin/libgodot-cpp.windows.template_release.x86_64.lib
run-tests: false
cache-name: windows-x86_64-msvc
- name: 🏁 Windows (x86_64, MinGW)
@@ -54,142 +45,124 @@ jobs:
artifact-name: godot-cpp-linux-mingw-x86_64-release
artifact-path: bin/libgodot-cpp.windows.template_release.x86_64.a
flags: use_mingw=yes
run-tests: false
cache-name: windows-x86_64-mingw
- name: 🍎 macOS (universal)
os: macos-latest
os: macos-11
platform: macos
artifact-name: godot-cpp-macos-universal-release
artifact-path: bin/libgodot-cpp.macos.template_release.universal.a
flags: arch=universal
run-tests: false
cache-name: macos-universal
- name: 🤖 Android (arm64)
os: ubuntu-22.04
os: ubuntu-20.04
platform: android
artifact-name: godot-cpp-android-arm64-release
artifact-path: bin/libgodot-cpp.android.template_release.arm64.a
flags: arch=arm64
run-tests: false
flags: ANDROID_NDK_ROOT=$ANDROID_NDK_LATEST_HOME arch=arm64
cache-name: android-arm64
- name: 🍏 iOS (arm64)
os: macos-latest
os: macos-11
platform: ios
artifact-name: godot-cpp-ios-arm64-release
artifact-path: bin/libgodot-cpp.ios.template_release.arm64.a
flags: arch=arm64
run-tests: false
cache-name: ios-arm64
- name: 🌐 Web (wasm32)
os: ubuntu-22.04
platform: web
artifact-name: godot-cpp-web-wasm32-release
artifact-path: bin/libgodot-cpp.web.template_release.wasm32.a
run-tests: false
cache-name: web-wasm32
env:
SCONS_CACHE: ${{ github.workspace }}/.scons-cache/
EM_VERSION: 3.1.39
steps:
- name: Checkout
uses: actions/checkout@v4
uses: actions/checkout@v3
with:
submodules: recursive
- name: Restore Godot build cache
uses: ./.github/actions/godot-cache-restore
- name: Setup Godot build cache
uses: ./.github/actions/godot-cache
with:
cache-name: ${{ matrix.cache-name }}
continue-on-error: true
- name: Setup godot-cpp
uses: ./.github/actions/setup-godot-cpp
- name: Set up Python (for SCons)
uses: actions/setup-python@v4
with:
platform: ${{ matrix.platform }}
windows-compiler: ${{ contains(matrix.flags, 'use_mingw=yes') && 'mingw' || 'msvc' }}
python-version: '3.x'
- name: Linux dependencies
if: ${{ matrix.platform == 'linux' }}
run: |
sudo apt-get update -qq
sudo apt-get install -qqq build-essential pkg-config
- name: Install scons
run: |
python -m pip install scons==4.0.0
- name: Setup MinGW for Windows/MinGW build
if: ${{ matrix.platform == 'windows' && matrix.flags == 'use_mingw=yes' }}
uses: egor-tensin/setup-mingw@v2
with:
version: 12.2.0
- name: Generate godot-cpp sources only
run: |
scons platform=${{ matrix.platform }} verbose=yes build_library=no ${{ matrix.flags }}
scons platform=${{ matrix.platform }} build_library=no ${{ matrix.flags }}
scons -c
- name: Build godot-cpp (debug)
run: |
scons platform=${{ matrix.platform }} verbose=yes target=template_debug ${{ matrix.flags }}
scons platform=${{ matrix.platform }} target=template_debug ${{ matrix.flags }}
- name: Build test without rebuilding godot-cpp (debug)
run: |
cd test
scons platform=${{ matrix.platform }} verbose=yes target=template_debug ${{ matrix.flags }} build_library=no
scons platform=${{ matrix.platform }} target=template_debug ${{ matrix.flags }} build_library=no
- name: Build test and godot-cpp (release)
run: |
cd test
scons platform=${{ matrix.platform }} verbose=yes target=template_release ${{ matrix.flags }}
- name: Save Godot build cache
uses: ./.github/actions/godot-cache-save
with:
cache-name: ${{ matrix.cache-name }}
continue-on-error: true
- name: Download latest Godot artifacts
uses: dsnopek/action-download-artifact@1322f74e2dac9feed2ee76a32d9ae1ca3b4cf4e9
if: matrix.run-tests && env.GODOT_TEST_VERSION == 'master'
with:
repo: godotengine/godot
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: godot-artifacts
- name: Prepare Godot artifacts for testing
if: matrix.run-tests && env.GODOT_TEST_VERSION == 'master'
run: |
chmod +x ./godot-artifacts/godot.linuxbsd.editor.x86_64.mono
echo "GODOT=$(pwd)/godot-artifacts/godot.linuxbsd.editor.x86_64.mono" >> $GITHUB_ENV
- name: Download requested Godot version for testing
if: matrix.run-tests && env.GODOT_TEST_VERSION != 'master'
run: |
wget "https://github.com/godotengine/godot-builds/releases/download/${GODOT_TEST_VERSION}/Godot_v${GODOT_TEST_VERSION}_linux.x86_64.zip" -O Godot.zip
unzip -a Godot.zip
chmod +x "Godot_v${GODOT_TEST_VERSION}_linux.x86_64"
echo "GODOT=$(pwd)/Godot_v${GODOT_TEST_VERSION}_linux.x86_64" >> $GITHUB_ENV
- name: Run tests
if: matrix.run-tests
run: |
$GODOT --headless --version
cd test
# Need to run the editor so .godot is generated... but it crashes! Ignore that :-)
(cd project && (timeout 30 $GODOT --import --headless >/dev/null 2>&1 || true))
./run-tests.sh
scons platform=${{ matrix.platform }} target=template_release ${{ matrix.flags }}
- name: Upload artifact
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v3
with:
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
linux-cmake:
name: 🐧 Build (Linux, GCC, CMake)
runs-on: ubuntu-20.04
steps:
- name: Checkout
uses: actions/checkout@v4
uses: actions/checkout@v3
with:
submodules: recursive
- name: Install dependencies
run: |
sudo apt-get update -qq
sudo apt-get install -qqq build-essential pkg-config cmake
- name: Build godot-cpp
run: |
cmake -DCMAKE_BUILD_TYPE=Release .
make -j $(nproc) VERBOSE=1
- name: Build test GDExtension library
run: |
cd test && cmake -DCMAKE_BUILD_TYPE=Release -DGODOT_HEADERS_PATH="../godot-headers" -DCPP_BINDINGS_PATH=".." .
make -j $(nproc) VERBOSE=1
linux-cmake-ninja:
name: 🐧 Build (Linux, GCC, CMake Ninja)
runs-on: ubuntu-20.04
steps:
- name: Checkout
uses: actions/checkout@v3
with:
submodules: recursive
@@ -198,25 +171,31 @@ jobs:
sudo apt-get update -qq
sudo apt-get install -qqq build-essential pkg-config cmake ninja-build
- name: Build godot-cpp
run: |
cmake -DCMAKE_BUILD_TYPE=Release -GNinja .
cmake --build . -j $(nproc) --verbose
- 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
cd test && cmake -DCMAKE_BUILD_TYPE=Release -DGODOT_HEADERS_PATH="../godot-headers" -DCPP_BINDINGS_PATH=".." -GNinja .
cmake --build . -j $(nproc) --verbose
windows-msvc-cmake:
name: 🏁 Build (Windows, MSVC, CMake)
runs-on: windows-2019
steps:
- name: Checkout
uses: actions/checkout@v4
uses: actions/checkout@v3
with:
submodules: recursive
- name: Build godot-cpp
run: |
cmake -DCMAKE_BUILD_TYPE=Release -G"Visual Studio 16 2019" .
cmake --build . --verbose
- 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
cd test && cmake -DCMAKE_BUILD_TYPE=Release -DGODOT_HEADERS_PATH="../godot-headers" -DCPP_BINDINGS_PATH=".." -G"Visual Studio 16 2019" .
cmake --build . --verbose

View File

@@ -1,21 +0,0 @@
name: 🔗 GHA
on: [push, pull_request, merge_group]
concurrency:
group: ci-${{ github.actor }}-${{ github.head_ref || github.run_number }}-${{ github.ref }}-runner
cancel-in-progress: true
jobs:
# First stage: Only static checks, fast and prevent expensive builds from running.
static-checks:
if: '!vars.DISABLE_GODOT_CI'
name: 📊 Static Checks
uses: ./.github/workflows/static_checks.yml
# Second stage: Run all the builds and some of the tests.
ci:
name: 🛠️ Continuous Integration
needs: static-checks
uses: ./.github/workflows/ci.yml

View File

@@ -1,38 +1,54 @@
name: 📊 Static Checks
on:
workflow_call:
on: [push, pull_request]
concurrency:
group: ci-${{ github.actor }}-${{ github.head_ref || github.run_number }}-${{ github.ref }}-static
group: ci-${{github.actor}}-${{github.head_ref || github.run_number}}-${{github.ref}}-static
cancel-in-progress: true
jobs:
static-checks:
name: Format (clang-format, ruff format, file format)
runs-on: ubuntu-22.04
name: Format (clang-format, black format, file format)
runs-on: ubuntu-20.04
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 2
uses: actions/checkout@v3
- name: Get changed files
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
# Azure repositories are not reliable, we need to prevent Azure giving us packages.
- name: Make apt sources.list use the default Ubuntu repositories
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
sudo rm -f /etc/apt/sources.list.d/*
sudo cp -f misc/ci/sources.list /etc/apt/sources.list
wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add -
sudo apt-add-repository "deb http://apt.llvm.org/focal/ llvm-toolchain-focal-15 main"
sudo apt-get update
- name: Style checks via pre-commit
uses: pre-commit/action@v3.0.1
with:
extra_args: --verbose --hook-stage manual --files ${{ env.CHANGED_FILES }}
- name: Install dependencies
run: |
sudo apt-get install -qq dos2unix recode clang-format-15 libxml2-utils python3-pip moreutils
sudo update-alternatives --remove-all clang-format || true
sudo update-alternatives --install /usr/bin/clang-format clang-format /usr/bin/clang-format-15 100
sudo pip3 install black==22.3.0 pygments pytest==7.1.2 mypy==0.971
- name: Check generated files consistency
run:
python misc/scripts/check_get_file_list.py
- name: File formatting checks (file_format.sh)
run: |
bash ./misc/scripts/file_format.sh
- name: Header guards formatting checks (header_guards.sh)
run: |
bash ./misc/scripts/header_guards.sh
- name: Python style checks via black (black_format.sh)
run: |
bash ./misc/scripts/black_format.sh
- name: Python scripts static analysis (mypy_check.sh)
run: |
bash ./misc/scripts/mypy_check.sh
- name: Bindings generation checks (ensures get_file_list returns all generated files)
run: |
python ./misc/scripts/check_get_file_list.py
- name: Style checks via clang-format (clang_format.sh)
run: |
bash ./misc/scripts/clang_format.sh

15
.gitignore vendored
View File

@@ -8,7 +8,7 @@
include/gen
src/gen
# Build configuration.
# Build configuarion.
/custom.py
# Misc
@@ -100,7 +100,7 @@ AppPackages/
# Others
sql/
*.[Cc]ache
*.Cache
ClientBin/
[Ss]tyle[Cc]op.*
~$*
@@ -191,14 +191,3 @@ godot.creator.*
# compile commands (https://clang.llvm.org/docs/JSONCompilationDatabase.html)
compile_commands.json
# Python development
.venv
venv
# Clion Configuration
.idea/
cmake-build*/
# CMake related
CMakeUserPresets.json

View File

@@ -1,64 +0,0 @@
default_language_version:
python: python3
exclude: |
(?x)^(
gdextension/extension_api\.json|
gdextension/gdextension_interface\.h
)$
repos:
- repo: https://github.com/pre-commit/mirrors-clang-format
rev: v17.0.6
hooks:
- id: clang-format
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.4.4
hooks:
- id: ruff
args: [--fix]
- id: ruff-format
- repo: https://github.com/pre-commit/mirrors-mypy
rev: v0.971
hooks:
- id: mypy
files: \.py$
types_or: [text]
- repo: https://github.com/codespell-project/codespell
rev: v2.3.0
hooks:
- id: codespell
additional_dependencies: [tomli]
- repo: local
hooks:
- id: copyright-headers
name: copyright-headers
language: python
entry: python misc/scripts/copyright_headers.py
files: \.(c|h)pp$
exclude: ^test/
- id: header-guards
name: header-guards
language: python
entry: python misc/scripts/header_guards.py
files: \.hpp$
exclude: ^test/
- id: file-format
name: file-format
language: python
entry: python misc/scripts/file_format.py
types_or: [text]
- id: check-get-file-list
name: check-get-file-list
language: python
entry: python misc/scripts/check_get_file_list.py
pass_filenames: false
always_run: true
stages: [manual]

View File

@@ -1,62 +1,212 @@
cmake_minimum_required(VERSION 3.17)
# cmake arguments
# CMAKE_BUILD_TYPE: Compilation target (Debug or Release defaults to Debug)
#
# godot-cpp cmake arguments
# GODOT_GDEXTENSION_DIR: Path to the directory containing GDExtension interface header and API JSON file
# GODOT_CPP_SYSTEM_HEADERS Mark the header files as SYSTEM. This may be useful to supress warnings in projects including this one.
# GODOT_CPP_WARNING_AS_ERROR Treat any warnings as errors
# GODOT_CUSTOM_API_FILE: Path to a custom GDExtension API JSON file (takes precedence over `gdextension_dir`)
# FLOAT_PRECISION: Floating-point precision level ("single", "double")
#
# Android cmake arguments
# CMAKE_TOOLCHAIN_FILE: The path to the android cmake toolchain ($ANDROID_NDK/build/cmake/android.toolchain.cmake)
# ANDROID_NDK: The path to the android ndk root folder
# ANDROID_TOOLCHAIN_NAME: The android toolchain (arm-linux-androideabi-4.9 or aarch64-linux-android-4.9 or x86-4.9 or x86_64-4.9)
# ANDROID_PLATFORM: The android platform version (android-23)
# More info here: https://godot.readthedocs.io/en/latest/development/compiling/compiling_for_android.html
#
# Examples
#
# Builds a debug version:
# cmake .
# cmake --build .
#
# Builds a release version with clang
# CC=/usr/bin/clang CXX=/usr/bin/clang++ cmake -DCMAKE_BUILD_TYPE=Release -G "Unix Makefiles" .
# cmake --build .
#
# Builds an android armeabi-v7a debug version:
# cmake -DCMAKE_TOOLCHAIN_FILE=$ANDROID_NDK/build/cmake/android.toolchain.cmake -DANDROID_NDK=$ANDROID_NDK \
# -DANDROID_TOOLCHAIN_NAME=arm-linux-androideabi-4.9 -DANDROID_PLATFORM=android-23 -DCMAKE_BUILD_TYPE=Debug .
# cmake --build .
#
# Protip
# Generate the buildfiles in a sub directory to not clutter the root directory with build files:
# mkdir build && cd build && cmake -G "Unix Makefiles" .. && cmake --build .
#
# Todo
# Test build for Windows, Mac and mingw.
#[=======================================================================[.rst:
project(godot-cpp LANGUAGES CXX)
cmake_minimum_required(VERSION 3.12)
CMake Version requirements
--------------------------
option(GENERATE_TEMPLATE_GET_NODE "Generate a template version of the Node class's get_node." ON)
option(GODOT_CPP_SYSTEM_HEADERS "Expose headers as SYSTEM." ON)
option(GODOT_CPP_WARNING_AS_ERROR "Treat warnings as errors" OFF)
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_<PROJECT-NAME>_INCLUDE which was introduced in version 3.17
# Add path to modules
list( APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake/" )
Scons Compatibility
-------------------
There is an understandable conflict between build systems as they define
similar concepts in different ways. When there isn't a 1:1 relationship,
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.
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
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.
.. highlight:: python
cpp_tool = Tool("godotcpp", toolpath=["tools"])
cpp_tool.options(opts, env)
The CMake equivalent is below.
]=======================================================================]
include( cmake/godotcpp.cmake )
godotcpp_options()
# 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)
compiler_detection()
godotcpp_generate()
# Conditionally enable the godot-cpp.test.<target> integration testing targets
if( GODOTCPP_ENABLE_TESTING )
add_subdirectory( test )
# Check if we are building ourself or being included
if(${PROJECT_NAME} STREQUAL ${CMAKE_PROJECT_NAME})
set(GODOT_CPP_BUILDING_SELF ON)
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
set_property(GLOBAL PROPERTY USE_FOLDERS ON)
# Set some helper variables for readability
set( compiler_is_clang "$<OR:$<CXX_COMPILER_ID:AppleClang>,$<CXX_COMPILER_ID:Clang>>" )
set( compiler_is_gnu "$<CXX_COMPILER_ID:GNU>" )
set( compiler_is_msvc "$<CXX_COMPILER_ID:MSVC>" )
# Default build type is Debug in the SConstruct
if("${CMAKE_BUILD_TYPE}" STREQUAL "")
set(CMAKE_BUILD_TYPE Debug)
endif()
if(NOT DEFINED BITS)
set(BITS 32)
if(CMAKE_SIZEOF_VOID_P EQUAL 8)
set(BITS 64)
endif(CMAKE_SIZEOF_VOID_P EQUAL 8)
endif()
# Input from user for GDExtension interface header and the API JSON file
set(GODOT_GDEXTENSION_DIR "gdextension" CACHE STRING "")
set(GODOT_CUSTOM_API_FILE "" CACHE STRING "")
set(FLOAT_PRECISION "single" CACHE STRING "")
if ("${FLOAT_PRECISION}" STREQUAL "double")
add_definitions(-DREAL_T_IS_DOUBLE)
endif()
set(GODOT_GDEXTENSION_API_FILE "${GODOT_GDEXTENSION_DIR}/extension_api.json")
if (NOT "${GODOT_CUSTOM_API_FILE}" STREQUAL "") # User-defined override.
set(GODOT_GDEXTENSION_API_FILE "${GODOT_CUSTOM_API_FILE}")
endif()
set(GODOT_COMPILE_FLAGS )
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
# using Visual Studio C++
set(GODOT_COMPILE_FLAGS "/EHsc") # /GF /MP
if(CMAKE_BUILD_TYPE MATCHES Debug)
set(GODOT_COMPILE_FLAGS "${GODOT_COMPILE_FLAGS} /MDd") # /Od /RTC1 /Zi
else()
set(GODOT_COMPILE_FLAGS "${GODOT_COMPILE_FLAGS} /MD /O2") # /Oy /GL /Gy
STRING(REGEX REPLACE "/RTC(su|[1su])" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
string(REPLACE "/RTC1" "" CMAKE_CXX_FLAGS_DEBUG ${CMAKE_CXX_FLAGS_DEBUG})
endif(CMAKE_BUILD_TYPE MATCHES Debug)
add_definitions(-DNOMINMAX)
else() # GCC/Clang
set(GODOT_COMPILE_FLAGS "${GODOT_COMPILE_FLAGS} -g")
if(CMAKE_BUILD_TYPE MATCHES Debug)
set(GODOT_COMPILE_FLAGS "${GODOT_COMPILE_FLAGS} -fno-omit-frame-pointer -O0")
else()
set(GODOT_COMPILE_FLAGS "${GODOT_COMPILE_FLAGS} -O3")
endif(CMAKE_BUILD_TYPE MATCHES Debug)
endif()
# Generate source from the bindings file
find_package(Python3 3.4 REQUIRED) # pathlib should be present
if(GENERATE_TEMPLATE_GET_NODE)
set(GENERATE_BINDING_PARAMETERS "True")
else()
set(GENERATE_BINDING_PARAMETERS "False")
endif()
execute_process(COMMAND "${Python3_EXECUTABLE}" "-c" "import binding_generator; binding_generator.print_file_list(\"${GODOT_GDEXTENSION_API_FILE}\", \"${CMAKE_CURRENT_BINARY_DIR}\", headers=True, sources=True)"
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
OUTPUT_VARIABLE GENERATED_FILES_LIST
)
add_custom_command(OUTPUT ${GENERATED_FILES_LIST}
COMMAND "${Python3_EXECUTABLE}" "-c" "import binding_generator; binding_generator.generate_bindings(\"${GODOT_GDEXTENSION_API_FILE}\", \"${GENERATE_BINDING_PARAMETERS}\", \"${BITS}\", \"${FLOAT_PRECISION}\", \"${CMAKE_CURRENT_BINARY_DIR}\")"
VERBATIM
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
MAIN_DEPENDENCY ${GODOT_GDEXTENSION_API_FILE}
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/binding_generator.py
COMMENT "Generating bindings"
)
# Get Sources
file(GLOB_RECURSE SOURCES CONFIGURE_DEPENDS src/*.c**)
file(GLOB_RECURSE HEADERS CONFIGURE_DEPENDS include/*.h**)
# Define our godot-cpp library
add_library(${PROJECT_NAME} STATIC
${SOURCES}
${HEADERS}
${GENERATED_FILES_LIST}
)
add_library(godot::cpp ALIAS ${PROJECT_NAME})
include(GodotCompilerWarnings)
# Treat warnings as errors if we are building ourself
if(GODOT_CPP_BUILDING_SELF)
unset( GODOT_CPP_WARNING_AS_ERROR CACHE )
set_warning_as_error()
endif()
target_compile_features(${PROJECT_NAME}
PRIVATE
cxx_std_17
)
target_compile_definitions(${PROJECT_NAME} PUBLIC
$<$<CONFIG:Debug>:
DEBUG_ENABLED
DEBUG_METHODS_ENABLED
>
$<${compiler_is_msvc}:
TYPED_METHOD_BIND
>
)
target_link_options(${PROJECT_NAME} PRIVATE
$<$<NOT:${compiler_is_msvc}>:
-static-libgcc
-static-libstdc++
-Wl,-R,'$$ORIGIN'
>
)
# Optionally mark headers as SYSTEM
set(GODOT_CPP_SYSTEM_HEADERS_ATTRIBUTE "")
if (GODOT_CPP_SYSTEM_HEADERS)
set(GODOT_CPP_SYSTEM_HEADERS_ATTRIBUTE SYSTEM)
endif ()
target_include_directories(${PROJECT_NAME} ${GODOT_CPP_SYSTEM_HEADERS_ATTRIBUTE} PUBLIC
include
${CMAKE_CURRENT_BINARY_DIR}/gen/include
${GODOT_GDEXTENSION_DIR}
)
# Add the compile flags
set_property(TARGET ${PROJECT_NAME} APPEND_STRING PROPERTY COMPILE_FLAGS ${GODOT_COMPILE_FLAGS})
# Create the correct name (godot.os.build_type.system_bits)
string(TOLOWER "${CMAKE_SYSTEM_NAME}" SYSTEM_NAME)
string(TOLOWER "${CMAKE_BUILD_TYPE}" BUILD_TYPE)
if(ANDROID)
# Added the android abi after system name
set(SYSTEM_NAME ${SYSTEM_NAME}.${ANDROID_ABI})
# Android does not have the bits at the end if you look at the main godot repo build
set(OUTPUT_NAME "godot-cpp.${SYSTEM_NAME}.${BUILD_TYPE}")
else()
set(OUTPUT_NAME "godot-cpp.${SYSTEM_NAME}.${BUILD_TYPE}.${BITS}")
endif()
set_target_properties(${PROJECT_NAME}
PROPERTIES
CXX_EXTENSIONS OFF
POSITION_INDEPENDENT_CODE ON
ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/bin"
LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/bin"
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/bin"
OUTPUT_NAME "${OUTPUT_NAME}"
)

View File

@@ -1,17 +1,9 @@
# godot-cpp
> [!WARNING]
> **Warning**
>
> This repository's `master` branch is only usable with
> [GDExtension](https://godotengine.org/article/introducing-gd-extensions)
> from Godot's `master` branch.
>
> For users of stable branches, switch to the branch matching your target Godot version:
> - [`4.2`](https://github.com/godotengine/godot-cpp/tree/4.2)
> - [`4.1`](https://github.com/godotengine/godot-cpp/tree/4.1)
> - [`4.0`](https://github.com/godotengine/godot-cpp/tree/4.0)
>
> Or check out the Git tag matching your Godot version (e.g. `godot-4.1.1-stable`).
> This repository's `master` branch is only usable with Godot's ([GDExtension](https://godotengine.org/article/introducing-gd-extensions))
> API (Godot 4.0 and later).
>
> For GDNative users (Godot 3.x), switch to the [`3.x`](https://github.com/godotengine/godot-cpp/tree/3.x)
> or the [`3.5`](https://github.com/godotengine/godot-cpp/tree/3.5) branch.
@@ -22,7 +14,7 @@ This repository contains the *C++ bindings* for the [**Godot Engine**](https://
- [**Compatibility**](#compatibility)
- [**Contributing**](#contributing)
- [**Getting started**](#getting-started)
- [**Examples and templates**](#examples-and-templates)
- [**Included example**](#included-example)
## Versioning
@@ -49,20 +41,17 @@ Godot version.**
## Compatibility
> [!WARNING]
>
> The GDExtension API is brand new in Godot 4.0, and is still
**Warning:** The GDExtension API is brand new in Godot 4.0, and is still
considered in **beta** stage, despite Godot 4.0 itself being released.
>
> This applies to both the GDExtension interface header, the API JSON, and this
This applies to both the GDExtension interface header, the API JSON, and this
first-party `godot-cpp` extension.
>
> Some compatibility breakage is to be expected as GDExtension and `godot-cpp`
> get more used, documented, and critical issues get resolved. See the
> [Godot issue tracker](https://github.com/godotengine/godot/issues?q=is%3Aissue+is%3Aopen+label%3Atopic%3Agdextension)
> and the [godot-cpp issue tracker](https://github.com/godotengine/godot-cpp/issues)
> for a list of known issues, and be sure to provide feedback on issues and PRs
> which affect your use of this extension.
Some compatibility breakage is to be expected as GDExtension and `godot-cpp`
get more used, documented, and critical issues get resolved. See the
[issue tracker](https://github.com/godotengine/godot/issues) for a list of known
issues, and be sure to provide feedback on issues and PRs which affect your use
of this extension.
## Contributing
@@ -71,14 +60,12 @@ wish to help out, ensure you have an account on GitHub and create a "fork" of
this repository. See [Pull request workflow](https://docs.godotengine.org/en/stable/community/contributing/pr_workflow.html)
for instructions.
Please install clang-format and the [pre-commit](https://pre-commit.com/) Python framework so formatting is done before your changes are submitted. See the [code style guidelines](https://docs.godotengine.org/en/latest/contributing/development/code_style_guidelines.html#pre-commit-hook) for instructions.
Please install clang-format and copy the files in `misc/hooks` into `.git/hooks`
so formatting is done before your changes are submitted.
## Getting started
You need the same C++ pre-requisites installed that are required for the `godot` repository. Follow the [official build instructions for your target platform](https://docs.godotengine.org/en/latest/contributing/development/compiling/index.html#building-for-target-platforms).
Getting started with GDExtensions is a bit similar to what it was for 3.x but also a bit different.
It's a bit similar to what it was for 3.x but also a bit different.
This new approach is much more akin to how core Godot modules are structured.
Compiling this repository generates a static library to be linked with your shared lib,
@@ -86,22 +73,21 @@ just like before.
To use the shared lib in your Godot project you'll need a `.gdextension`
file, which replaces what was the `.gdnlib` before.
See [example.gdextension](test/project/example.gdextension) used in the test project:
Follow [the example](test/demo/example.gdextension):
```ini
[configuration]
entry_symbol = "example_library_init"
compatibility_minimum = "4.1"
[libraries]
macos.debug = "res://bin/libgdexample.macos.debug.framework"
macos.release = "res://bin/libgdexample.macos.release.framework"
windows.debug.x86_64 = "res://bin/libgdexample.windows.debug.x86_64.dll"
windows.release.x86_64 = "res://bin/libgdexample.windows.release.x86_64.dll"
linux.debug.x86_64 = "res://bin/libgdexample.linux.debug.x86_64.so"
linux.release.x86_64 = "res://bin/libgdexample.linux.release.x86_64.so"
macos.debug = "bin/libgdexample.macos.debug.framework"
macos.release = "bin/libgdexample.macos.release.framework"
windows.debug.x86_64 = "bin/libgdexample.windows.debug.x86_64.dll"
windows.release.x86_64 = "bin/libgdexample.windows.release.x86_64.dll"
linux.debug.x86_64 = "bin/libgdexample.linux.debug.x86_64.so"
linux.release.x86_64 = "bin/libgdexample.linux.release.x86_64.so"
# Repeat for other architectures to support arm64, rv64, etc.
```
@@ -113,8 +99,8 @@ extern "C" {
// Initialization.
GDExtensionBool GDE_EXPORT example_library_init(GDExtensionInterfaceGetProcAddress p_get_proc_address, GDExtensionClassLibraryPtr p_library, GDExtensionInitialization *r_initialization) {
godot::GDExtensionBinding::InitObject init_obj(p_get_proc_address, p_library, r_initialization);
GDExtensionBool GDE_EXPORT example_library_init(const GDExtensionInterface *p_interface, GDExtensionClassLibraryPtr p_library, GDExtensionInitialization *r_initialization) {
godot::GDExtensionBinding::InitObject init_obj(p_interface, p_library, r_initialization);
init_obj.register_initializer(initialize_example_module);
init_obj.register_terminator(uninitialize_example_module);
@@ -133,16 +119,12 @@ void initialize_example_module(ModuleInitializationLevel p_level) {
if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
return;
}
GDREGISTER_CLASS(Example);
ClassDB::register_class<Example>();
}
```
Any node and resource you register will be available in the corresponding `Create...` dialog. Any class will be available to scripting as well.
## Examples and templates
## Included example
See the [godot-cpp-template](https://github.com/godotengine/godot-cpp-template) project for a
generic reusable template.
Or checkout the code for the [Summator example](https://github.com/paddy-exe/GDExtensionSummator)
as shown in the [official documentation](https://docs.godotengine.org/en/latest/tutorials/scripting/gdextension/gdextension_cpp_example.html).
Check the project in the `test` folder for an example on how to use and register different things.

View File

@@ -1,25 +1,80 @@
#!/usr/bin/env python
import os
import platform
import sys
import subprocess
from binding_generator import scons_generate_bindings, scons_emit_files
from SCons.Errors import UserError
EnsureSConsVersion(4, 0)
try:
Import("env")
except Exception:
# Default tools with no platform defaults to gnu toolchain.
# We apply platform specific toolchains via our custom tools.
env = Environment(tools=["default"], PLATFORM="")
def add_sources(sources, dir, extension):
for f in os.listdir(dir):
if f.endswith("." + extension):
sources.append(dir + "/" + f)
env.PrependENVPath("PATH", os.getenv("PATH"))
def normalize_path(val):
return val if os.path.isabs(val) else os.path.join(env.Dir("#").abspath, val)
def validate_api_file(key, val, env):
if not os.path.isfile(normalize_path(val)):
raise UserError("GDExtension API file ('%s') does not exist: %s" % (key, val))
def validate_gdextension_dir(key, val, env):
if not os.path.isdir(normalize_path(val)):
raise UserError("GDExtension directory ('%s') does not exist: %s" % (key, val))
def get_gdextension_dir(env):
return normalize_path(env.get("gdextension_dir", env.Dir("gdextension").abspath))
def get_api_file(env):
return normalize_path(env.get("custom_api_file", os.path.join(get_gdextension_dir(env), "extension_api.json")))
# Try to detect the host platform automatically.
# This is used if no `platform` argument is passed
if sys.platform.startswith("linux"):
default_platform = "linux"
elif sys.platform == "darwin":
default_platform = "macos"
elif sys.platform == "win32" or sys.platform == "msys":
default_platform = "windows"
elif ARGUMENTS.get("platform", ""):
default_platform = ARGUMENTS.get("platform")
else:
raise ValueError("Could not detect platform automatically, please specify with platform=<platform>")
# Default tools with no platform defaults to gnu toolchain.
# We apply platform specific toolchains via our custom tools.
env = Environment(tools=["default"], PLATFORM="")
# 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.
initial_num_jobs = env.GetOption("num_jobs")
altered_num_jobs = initial_num_jobs + 1
env.SetOption("num_jobs", altered_num_jobs)
if env.GetOption("num_jobs") == altered_num_jobs:
cpu_count = os.cpu_count()
if cpu_count is None:
print("Couldn't auto-detect CPU count to configure build parallelism. Specify it with the -j argument.")
else:
safer_cpu_count = cpu_count if cpu_count <= 4 else cpu_count - 1
print(
"Auto-detected %d CPU cores available for build parallelism. Using %d cores by default. You can override it with the -j argument."
% (cpu_count, safer_cpu_count)
)
env.SetOption("num_jobs", safer_cpu_count)
# Custom options and profile flags.
customs = ["custom.py"]
try:
customs += Import("customs")
except Exception:
pass
profile = ARGUMENTS.get("profile", "")
if profile:
if os.path.isfile(profile):
@@ -27,12 +82,113 @@ if profile:
elif os.path.isfile(profile + ".py"):
customs.append(profile + ".py")
opts = Variables(customs, ARGUMENTS)
cpp_tool = Tool("godotcpp", toolpath=["tools"])
cpp_tool.options(opts, env)
opts.Update(env)
platforms = ("linux", "macos", "windows", "android", "ios", "javascript")
opts.Add(
EnumVariable(
"platform",
"Target platform",
default_platform,
allowed_values=platforms,
ignorecase=2,
)
)
# Editor and template_debug are compatible (i.e. you can use the same binary for Godot editor builds and Godot debug templates).
# Godot release templates are only compatible with "template_release" builds.
# For this reason, we default to template_debug builds, unlike Godot which defaults to editor builds.
opts.Add(
EnumVariable("target", "Compilation target", "template_debug", ("editor", "template_release", "template_debug"))
)
opts.Add(
PathVariable(
"gdextension_dir",
"Path to a custom directory containing GDExtension interface header and API JSON file",
None,
validate_gdextension_dir,
)
)
opts.Add(
PathVariable(
"custom_api_file",
"Path to a custom GDExtension API JSON file (takes precedence over `gdextension_dir`)",
None,
validate_api_file,
)
)
opts.Add(
BoolVariable("generate_bindings", "Force GDExtension API bindings generation. Auto-detected by default.", False)
)
opts.Add(BoolVariable("generate_template_get_node", "Generate a template version of the Node class's get_node.", True))
opts.Add(BoolVariable("build_library", "Build the godot-cpp library.", True))
opts.Add(EnumVariable("precision", "Set the floating-point precision level", "single", ("single", "double")))
# Add platform options
tools = {}
for pl in platforms:
tool = Tool(pl, toolpath=["tools"])
if hasattr(tool, "options"):
tool.options(opts)
tools[pl] = tool
# CPU architecture options.
architecture_array = ["", "universal", "x86_32", "x86_64", "arm32", "arm64", "rv64", "ppc32", "ppc64", "wasm32"]
architecture_aliases = {
"x64": "x86_64",
"amd64": "x86_64",
"armv7": "arm32",
"armv8": "arm64",
"arm64v8": "arm64",
"aarch64": "arm64",
"rv": "rv64",
"riscv": "rv64",
"riscv64": "rv64",
"ppcle": "ppc32",
"ppc": "ppc32",
"ppc64le": "ppc64",
}
opts.Add(EnumVariable("arch", "CPU architecture", "", architecture_array, architecture_aliases))
# Targets flags tool (optimizations, debug symbols)
target_tool = Tool("targets", toolpath=["tools"])
target_tool.options(opts)
opts.Update(env)
Help(opts.GenerateHelpText(env))
# Process CPU architecture argument.
if env["arch"] == "":
# No architecture specified. Default to arm64 if building for Android,
# universal if building for macOS or iOS, wasm32 if building for web,
# otherwise default to the host architecture.
if env["platform"] in ["macos", "ios"]:
env["arch"] = "universal"
elif env["platform"] == "android":
env["arch"] = "arm64"
elif env["platform"] == "javascript":
env["arch"] = "wasm32"
else:
host_machine = platform.machine().lower()
if host_machine in architecture_array:
env["arch"] = host_machine
elif host_machine in architecture_aliases.keys():
env["arch"] = architecture_aliases[host_machine]
elif "86" in host_machine:
# Catches x86, i386, i486, i586, i686, etc.
env["arch"] = "x86_32"
else:
print("Unsupported CPU architecture: " + host_machine)
Exit()
tool = Tool(env["platform"], toolpath=["tools"])
if tool is None or not tool.exists(env):
raise ValueError("Required toolchain not found for platform " + env["platform"])
tool.generate(env)
target_tool.generate(env)
# Detect and print a warning listing unknown SCons variables to ease troubleshooting.
unknown = opts.UnknownVariables()
if unknown:
@@ -40,12 +196,66 @@ if unknown:
for item in unknown.items():
print(" " + item[0] + "=" + item[1])
print("Building for architecture " + env["arch"] + " on platform " + env["platform"])
# Require C++17
if env.get("is_msvc", False):
env.Append(CXXFLAGS=["/std:c++17"])
else:
env.Append(CXXFLAGS=["-std=c++17"])
if env["precision"] == "double":
env.Append(CPPDEFINES=["REAL_T_IS_DOUBLE"])
# Generate bindings
env.Append(BUILDERS={"GenerateBindings": Builder(action=scons_generate_bindings, emitter=scons_emit_files)})
bindings = env.GenerateBindings(
env.Dir("."),
[get_api_file(env), os.path.join(get_gdextension_dir(env), "gdextension_interface.h"), "binding_generator.py"],
)
scons_cache_path = os.environ.get("SCONS_CACHE")
if scons_cache_path is not None:
CacheDir(scons_cache_path)
Decider("MD5")
cpp_tool.generate(env)
library = env.GodotCPP()
# Forces bindings regeneration.
if env["generate_bindings"]:
AlwaysBuild(bindings)
NoCache(bindings)
# Includes
env.Append(CPPPATH=[[env.Dir(d) for d in [get_gdextension_dir(env), "include", os.path.join("gen", "include")]]])
# Sources to compile
sources = []
add_sources(sources, "src", "cpp")
add_sources(sources, "src/classes", "cpp")
add_sources(sources, "src/core", "cpp")
add_sources(sources, "src/variant", "cpp")
sources.extend([f for f in bindings if str(f).endswith(".cpp")])
suffix = ".{}.{}".format(env["platform"], env["target"])
if env.dev_build:
suffix += ".dev"
if env["precision"] == "double":
suffix += ".double"
suffix += "." + env["arch"]
if env["ios_simulator"]:
suffix += ".simulator"
# Expose it when included from another project
env["suffix"] = suffix
library = None
env["OBJSUFFIX"] = suffix + env["OBJSUFFIX"]
library_name = "libgodot-cpp{}{}".format(suffix, env["LIBSUFFIX"])
if env["build_library"]:
library = env.StaticLibrary(target=env.File("bin/%s" % library_name), source=sources)
Default(library)
env.Append(LIBPATH=[env.Dir("bin")])
env.Append(LIBS=library_name)
Return("env")

File diff suppressed because it is too large Load Diff

View File

@@ -1,183 +0,0 @@
import json
import sys
def parse_build_profile(profile_filepath, api):
if profile_filepath == "":
return {}
with open(profile_filepath, encoding="utf-8") as profile_file:
profile = json.load(profile_file)
api_dict = {}
parents = {}
children = {}
for engine_class in api["classes"]:
api_dict[engine_class["name"]] = engine_class
parent = engine_class.get("inherits", "")
child = engine_class["name"]
parents[child] = parent
if parent == "":
continue
children[parent] = children.get(parent, [])
children[parent].append(child)
included = []
front = list(profile.get("enabled_classes", []))
if front:
# These must always be included
front.append("WorkerThreadPool")
front.append("ClassDB")
front.append("ClassDBSingleton")
# In src/classes/low_level.cpp
front.append("FileAccess")
front.append("Image")
front.append("XMLParser")
# In include/godot_cpp/templates/thread_work_pool.hpp
front.append("Semaphore")
while front:
cls = front.pop()
if cls in included:
continue
included.append(cls)
parent = parents.get(cls, "")
if parent:
front.append(parent)
excluded = []
front = list(profile.get("disabled_classes", []))
while front:
cls = front.pop()
if cls in excluded:
continue
excluded.append(cls)
front += children.get(cls, [])
if included and excluded:
print(
"WARNING: Cannot specify both 'enabled_classes' and 'disabled_classes' in build profile. 'disabled_classes' will be ignored."
)
return {
"enabled_classes": included,
"disabled_classes": excluded,
}
def generate_trimmed_api(source_api_filepath, profile_filepath):
with open(source_api_filepath, encoding="utf-8") as api_file:
api = json.load(api_file)
if profile_filepath == "":
return api
build_profile = parse_build_profile(profile_filepath, api)
engine_classes = {}
for class_api in api["classes"]:
engine_classes[class_api["name"]] = class_api["is_refcounted"]
for native_struct in api["native_structures"]:
if native_struct["name"] == "ObjectID":
continue
engine_classes[native_struct["name"]] = False
classes = []
for class_api in api["classes"]:
if not is_class_included(class_api["name"], build_profile):
continue
if "methods" in class_api:
methods = []
for method in class_api["methods"]:
if not is_method_included(method, build_profile, engine_classes):
continue
methods.append(method)
class_api["methods"] = methods
classes.append(class_api)
api["classes"] = classes
return api
def is_class_included(class_name, build_profile):
"""
Check if an engine class should be included.
This removes classes according to a build profile of enabled or disabled classes.
"""
included = build_profile.get("enabled_classes", [])
excluded = build_profile.get("disabled_classes", [])
if included:
return class_name in included
if excluded:
return class_name not in excluded
return True
def is_method_included(method, build_profile, engine_classes):
"""
Check if an engine class method should be included.
This removes methods according to a build profile of enabled or disabled classes.
"""
included = build_profile.get("enabled_classes", [])
excluded = build_profile.get("disabled_classes", [])
ref_cls = set()
rtype = get_base_type(method.get("return_value", {}).get("type", ""))
args = [get_base_type(a["type"]) for a in method.get("arguments", [])]
if rtype in engine_classes:
ref_cls.add(rtype)
elif is_enum(rtype) and get_enum_class(rtype) in engine_classes:
ref_cls.add(get_enum_class(rtype))
for arg in args:
if arg in engine_classes:
ref_cls.add(arg)
elif is_enum(arg) and get_enum_class(arg) in engine_classes:
ref_cls.add(get_enum_class(arg))
for acls in ref_cls:
if len(included) > 0 and acls not in included:
return False
elif len(excluded) > 0 and acls in excluded:
return False
return True
def is_enum(type_name):
return type_name.startswith("enum::") or type_name.startswith("bitfield::")
def get_enum_class(enum_name: str):
if "." in enum_name:
if is_bitfield(enum_name):
return enum_name.replace("bitfield::", "").split(".")[0]
else:
return enum_name.replace("enum::", "").split(".")[0]
else:
return "GlobalConstants"
def get_base_type(type_name):
if type_name.startswith("const "):
type_name = type_name[6:]
if type_name.endswith("*"):
type_name = type_name[:-1]
if type_name.startswith("typedarray::"):
type_name = type_name.replace("typedarray::", "")
return type_name
def is_bitfield(type_name):
return type_name.startswith("bitfield::")
if __name__ == "__main__":
if len(sys.argv) < 3 or len(sys.argv) > 4:
print("Usage: %s BUILD_PROFILE INPUT_JSON [OUTPUT_JSON]" % (sys.argv[0]))
sys.exit(1)
profile = sys.argv[1]
infile = sys.argv[2]
outfile = sys.argv[3] if len(sys.argv) > 3 else ""
api = generate_trimmed_api(infile, profile)
if outfile:
with open(outfile, "w", encoding="utf-8") as f:
json.dump(api, f)
else:
json.dump(api, sys.stdout)

View File

@@ -1,169 +0,0 @@
#[=======================================================================[.rst:
GodotCPPModule.cmake
---------------------
This file contains functions and tests which may be needed by consumers.
* Generate Trimmed API
* Generate File List
* Generate Bindings
If you want to use these functions in your project extend the CMAKE_MODULE_PATH
by adding these two lines into your CMakeLists.txt after the inclusion
godot-cpp
.. highlight:: cmake
list(APPEND CMAKE_MODULE_PATH "${godot-cpp_SOURCE_DIR}/cmake")
include( GodotCPPModule )
]=======================================================================]
find_package(Python3 3.4 REQUIRED) # pathlib should be present
#[[ Generate Trimmed API
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 )
execute_process(
COMMAND "${Python3_EXECUTABLE}"
"${godot-cpp_SOURCE_DIR}/build_profile.py"
"${BUILD_PROFILE}"
"${INPUT_JSON}"
"${OUTPUT_JSON}"
WORKING_DIRECTORY ${godot-cpp_SOURCE_DIR}
)
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 )
# 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}',
output_dir='${OUTPUT_DIR}',
headers=True,
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}" )
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} )
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")
endif()
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 )
# This code snippet will be squashed into a single line
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}')")
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"
)
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 )
# 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 )
get_filename_component(OUTPUT_DIR "${OUTPUT_PATH}" DIRECTORY)
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
"${godot-cpp_SOURCE_DIR}/doc_source_generator.py"
"${SOURCES}"
COMMENT "Generating: ${OUTPUT_PATH}"
)
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 )
# set the generated file name
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}" )
# 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}" )
endfunction()

View File

@@ -0,0 +1,94 @@
# Add warnings based on compiler & version
# Set some helper variables for readability
set( compiler_less_than_v8 "$<VERSION_LESS:$<CXX_COMPILER_VERSION>,8>" )
set( compiler_greater_than_or_equal_v9 "$<VERSION_GREATER_EQUAL:$<CXX_COMPILER_VERSION>,9>" )
set( compiler_greater_than_or_equal_v11 "$<VERSION_GREATER_EQUAL:$<CXX_COMPILER_VERSION>,11>" )
set( compiler_less_than_v11 "$<VERSION_LESS:$<CXX_COMPILER_VERSION>,11>" )
set( compiler_greater_than_or_equal_v12 "$<VERSION_GREATER_EQUAL:$<CXX_COMPILER_VERSION>,12>" )
# These compiler options reflect what is in godot/SConstruct.
target_compile_options( ${PROJECT_NAME} PRIVATE
# MSVC only
$<${compiler_is_msvc}:
/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)
>
# Clang and GNU common options
$<$<OR:${compiler_is_clang},${compiler_is_gnu}>:
-Wall
-Wctor-dtor-privacy
-Wextra
-Wno-unused-parameter
-Wnon-virtual-dtor
-Wwrite-strings
>
# Clang only
$<${compiler_is_clang}:
-Wimplicit-fallthrough
-Wno-ordered-compare-function-pointers
>
# GNU only
$<${compiler_is_gnu}:
-Walloc-zero
-Wduplicated-branches
-Wduplicated-cond
-Wno-misleading-indentation
-Wplacement-new=1
-Wshadow-local
-Wstringop-overflow=4
>
$<$<AND:${compiler_is_gnu},${compiler_less_than_v8}>:
# Bogus warning fixed in 8+.
-Wno-strict-overflow
>
$<$<AND:${compiler_is_gnu},${compiler_greater_than_or_equal_v9}>:
-Wattribute-alias=2
>
$<$<AND:${compiler_is_gnu},${compiler_greater_than_or_equal_v11}>:
# Broke on MethodBind templates before GCC 11.
-Wlogical-op
>
$<$<AND:${compiler_is_gnu},${compiler_less_than_v11}>:
# Regression in GCC 9/10, spams so much in our variadic templates that we need to outright disable it.
-Wno-type-limits
>
$<$<AND:${compiler_is_gnu},${compiler_greater_than_or_equal_v12}>:
# False positives in our error macros, see GH-58747.
-Wno-return-type
>
)
# Treat warnings as errors
function( set_warning_as_error )
message( STATUS "[${PROJECT_NAME}] Treating warnings as errors")
if ( CMAKE_VERSION VERSION_GREATER_EQUAL "3.24" )
set_target_properties( ${PROJECT_NAME}
PROPERTIES
COMPILE_WARNING_AS_ERROR ON
)
else()
target_compile_options( ${PROJECT_NAME}
PRIVATE
$<${compiler_is_msvc}:/WX>
$<$<OR:${compiler_is_clang},${compiler_is_gnu}>:-Werror>
)
endif()
endfunction()
if ( GODOT_CPP_WARNING_AS_ERROR )
set_warning_as_error()
endif()

View File

@@ -1,40 +0,0 @@
#[=======================================================================[.rst:
Android
-------
This file contains functions for options and configuration for targeting the
Android platform
Configuration of the Android toolchain is done using toolchain files,
CMakePresets, or variables on the command line.
The `Android SDK`_ provides toolchain files to help with configuration.
CMake has its own `built-in support`_ for cross compiling to the
Android platforms.
.. warning::
Android does not support or test the CMake built-in workflow, recommend
using their toolchain file.
.. _Android SDK:https://developer.android.com/ndk/guides/cmake
.. _built-in support:https://cmake.org/cmake/help/latest/manual/cmake-toolchains.7.html#cross-compiling-for-android
There is further information and examples in the doc/cmake.rst file.
]=======================================================================]
function( android_options )
# Android Options
endfunction()
function( android_generate )
target_compile_definitions(${TARGET_NAME}
PUBLIC
ANDROID_ENABLED
UNIX_ENABLED
)
common_compiler_flags()
endfunction()

View File

@@ -1,177 +0,0 @@
#[=======================================================================[.rst:
Common Compiler Flags
---------------------
This file contains host platform toolchain and target platform agnostic
configuration. It includes flags like optimization levels, warnings, and
features. For target platform specific flags look to each of the
``cmake/<platform>.cmake`` files.
]=======================================================================]
#[[ Compiler Configuration, not to be confused with build targets ]]
set( DEBUG_SYMBOLS "$<OR:$<CONFIG:Debug>,$<CONFIG:RelWithDebInfo>>" )
#[[ Compiler Identification ]]
set( IS_CLANG "$<CXX_COMPILER_ID:Clang>" )
set( IS_APPLECLANG "$<CXX_COMPILER_ID:AppleClang>" )
set( IS_GNU "$<CXX_COMPILER_ID:GNU>" )
set( IS_MSVC "$<CXX_COMPILER_ID:MSVC>" )
set( NOT_MSVC "$<NOT:$<CXX_COMPILER_ID:MSVC>>" )
set( GNU_LT_V8 "$<VERSION_LESS:$<CXX_COMPILER_VERSION>,8>" )
set( GNU_GE_V9 "$<VERSION_GREATER_EQUAL:$<CXX_COMPILER_VERSION>,9>" )
set( GNU_GT_V11 "$<VERSION_GREATER_EQUAL:$<CXX_COMPILER_VERSION>,11>" )
set( GNU_LT_V11 "$<VERSION_LESS:$<CXX_COMPILER_VERSION>,11>" )
set( GNU_GE_V12 "$<VERSION_GREATER_EQUAL:$<CXX_COMPILER_VERSION>,12>" )
#[[ 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
The generator expression $<CXX_COMPILER_FRONTEND_VARIANT> wasn't introduced
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
)
# These compiler options reflect what is in godot/SConstruct.
target_compile_options( ${TARGET_NAME}
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>
>
# Enabling Debug Symbols
$<${DEBUG_SYMBOLS}:
# Adding dwarf-4 explicitly makes stacktraces work with clang builds,
# otherwise addr2line doesn't understand them.
$<${NOT_MSVC}:
-gdwarf-4
$<IF:${IS_DEV_BUILD},-g3,-g2>
>
>
$<${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
$<$<CXX_COMPILER_ID:MSVC>:/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
$<$<OR:${IS_CLANG},${IS_GNU}>:
-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>
>
)
target_compile_definitions(${TARGET_NAME}
PUBLIC
GDEXTENSION
# features
$<${DEBUG_FEATURES}:DEBUG_ENABLED DEBUG_METHODS_ENABLED>
$<${IS_DEV_BUILD}:DEV_ENABLED>
$<${HOT_RELOAD}:HOT_RELOAD_ENABLED>
$<$<STREQUAL:${GODOTCPP_PRECISION},double>:REAL_T_IS_DOUBLE>
$<${IS_MSVC}:$<${DISABLE_EXCEPTIONS}:_HAS_EXCEPTIONS=0>>
$<${THREADS_ENABLED}:THREADS_ENABLED>
)
target_link_options( ${TARGET_NAME}
PUBLIC
$<${IS_MSVC}:
/WX # treat link warnings as errors.
/MANIFEST:NO # We dont need a manifest
>
$<${DEBUG_SYMBOLS}:$<${IS_MSVC}:/DEBUG:FULL>>
$<$<NOT:${DEBUG_SYMBOLS}>:
$<${IS_GNU}:-s>
$<${IS_CLANG}:-s>
$<${IS_APPLECLANG}:-Wl,-S -Wl,-x -Wl,-dead_strip>
>
)
endfunction()

View File

@@ -1,40 +0,0 @@
#[=======================================================================[.rst:
emsdkHack
---------
The Emscripten platform doesn't support the use of shared libraries as known by cmake.
* https://github.com/emscripten-core/emscripten/issues/15276
* https://github.com/emscripten-core/emscripten/issues/17804
This workaround only works due to the way the cmake scripts are loaded.
Prior to the use of ``project( ... )`` directive we need to set
``CMAKE_PROJECT_INCLUDE=cmake/emscripten.cmake``.
This file will be loaded after the toolchain overriding the settings that
prevent shared library building.
CMAKE_PROJECT_INCLUDE was Added in version 3.15.
``CMAKE_PROJECT_<projectName>_INCLUDE`` was Added in version 3.17:
More information on cmake's `code injection`_
.. _code injection:https://cmake.org/cmake/help/latest/command/project.html#code-injection
Overwrite Shared Library Properties to allow shared libs to be generated.
]=======================================================================]
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
# 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" )
# the above prevents the need for logic like:
#if( ${CMAKE_SYSTEM_NAME} STREQUAL Emscripten )
# set( SYSTEM_ARCH wasm32 )
#endif ()
endif ()

View File

@@ -1,373 +0,0 @@
#[=======================================================================[.rst:
godotcpp.cmake
--------------
As godot-cpp is a C++ project, there are no C files, and detection of a C
compiler is unnecessary. When CMake performs the configure process, if a
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 ()
#[=======================================================================[.rst:
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)
# Detect number of processors
include(ProcessorCount)
ProcessorCount(PROC_MAX)
message( "Auto-detected ${PROC_MAX} CPU cores available for build parallelism." )
# List of known platforms
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 )
# 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 )
return()
endif()
endif()
# Direct match early out.
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")
# Catches x86, i386, i486, i586, i686, etc.
set(${OUTVAR} "x86_32" PARENT_SCOPE )
else()
# Default value is whatever the processor is.
set(${OUTVAR} ${CMAKE_SYSTEM_PROCESSOR} PARENT_SCOPE )
endif ()
endfunction()
# Function to define all the 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
# 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 )")
#TODO generate_bindings
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_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_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 )
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 )
#[[ debug_symbols
Debug symbols are enabled by using the Debug or RelWithDebInfo build configurations.
Single Config Generator is set at configure time
cmake ../ -DCMAKE_BUILD_TYPE=Debug
Multi-Config Generator is set at build time
cmake --build . --config Debug
]]
# 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 )
# Enable Testing
option( GODOTCPP_ENABLE_TESTING "Enable the godot-cpp.test.<target> integration testing targets" OFF )
#[[ Target Platform Options ]]
android_options()
ios_options()
linux_options()
macos_options()
web_options()
windows_options()
endfunction()
# Function to configure and generate the targets
function( godotcpp_generate )
#[[ Multi-Threaded MSVC Compilation
When using the MSVC compiler the build command -j <n> only specifies
parallel jobs or targets, and not multi-threaded compilation To speed up
compile times on msvc, the /MP <n> flag can be set. But we need to set it
at configure time.
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.")
# 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 <n> or --parallel <n> 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"
This effects the compiler flag_ -fvisibility=[default|internal|hidden|protected]
The corresponding target option CXX_VISIBILITY_PRESET accepts the compiler values.
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 ()
# Setup variable to optionally mark headers as SYSTEM
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" )
endif()
# Bits (32|64)
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}")
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}'")
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" )
endif()
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}" )
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" )
### Platform is derived from the toolchain target
# See GeneratorExpressions PLATFORM_ID and CMAKE_SYSTEM_NAME
string( CONCAT SYSTEM_NAME
"$<$<PLATFORM_ID:Android>:android.${ANDROID_ABI}>"
"$<$<PLATFORM_ID:iOS>:ios>"
"$<$<PLATFORM_ID:Linux>:linux>"
"$<$<PLATFORM_ID:Darwin>:macos>"
"$<$<PLATFORM_ID:Emscripten>:web>"
"$<$<PLATFORM_ID:Windows>:windows>"
"$<$<PLATFORM_ID:Msys>:windows>"
)
# Process CPU architecture argument.
godot_arch_name( ARCH_NAME )
# Transform options into generator expressions
set( HOT_RELOAD-UNSET "$<STREQUAL:${GODOTCPP_USE_HOT_RELOAD},>")
set( DISABLE_EXCEPTIONS "$<BOOL:${GODOTCPP_DISABLE_EXCEPTIONS}>")
set( THREADS_ENABLED "$<BOOL:${GODOTCPP_THREADS}>" )
# 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 <type> 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 "$<BOOL:${GODOTCPP_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 "$<NOT:$<STREQUAL:${TARGET_ALIAS},template_release>>" )
set( HOT_RELOAD "$<IF:${HOT_RELOAD-UNSET},${DEBUG_FEATURES},$<BOOL:${GODOTCPP_USE_HOT_RELOAD}>>" )
# Suffix
string( CONCAT GODOTCPP_SUFFIX
"$<1:.${SYSTEM_NAME}>"
"$<1:.${TARGET_ALIAS}>"
"$<${IS_DEV_BUILD}:.dev>"
"$<$<STREQUAL:${GODOTCPP_PRECISION},double>:.double>"
"$<1:.${ARCH_NAME}>"
# TODO IOS_SIMULATOR
"$<$<NOT:${THREADS_ENABLED}>:.nothreads>"
)
# the godot-cpp.* library targets
add_library( ${TARGET_NAME} STATIC EXCLUDE_FROM_ALL )
add_library( godot-cpp::${TARGET_ALIAS} ALIAS ${TARGET_NAME} )
file( GLOB_RECURSE GODOTCPP_SOURCES LIST_DIRECTORIES NO CONFIGURE_DEPENDS src/*.cpp )
target_sources( ${TARGET_NAME}
PRIVATE
${GODOTCPP_SOURCES}
${GENERATED_FILES_LIST}
)
target_include_directories( ${TARGET_NAME} ${GODOTCPP_SYSTEM_HEADERS_ATTRIBUTE} PUBLIC
include
${CMAKE_CURRENT_BINARY_DIR}/gen/include
${GODOTCPP_GDEXTENSION_DIR}
)
set_target_properties( ${TARGET_NAME}
PROPERTIES
CXX_STANDARD 17
CXX_EXTENSIONS OFF
CXX_VISIBILITY_PRESET ${GODOTCPP_SYMBOL_VISIBILITY}
COMPILE_WARNING_AS_ERROR ${GODOTCPP_WARNING_AS_ERROR}
POSITION_INDEPENDENT_CODE ON
BUILD_RPATH_USE_ORIGIN ON
PREFIX "lib"
OUTPUT_NAME "${PROJECT_NAME}${GODOTCPP_SUFFIX}"
ARCHIVE_OUTPUT_DIRECTORY "$<1:${CMAKE_BINARY_DIR}/bin>"
# 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}"
# Some IDE's respect this property to logically group targets
FOLDER "godot-cpp"
)
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 ()
# 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 )
endfunction()

View File

@@ -1,21 +0,0 @@
#[=======================================================================[.rst:
Ios
---
This file contains functions for options and configuration for targeting the
Ios platform
]=======================================================================]
function(ios_options)
# iOS options
endfunction()
function(ios_generate)
target_compile_definitions(${TARGET_NAME}
PUBLIC
IOS_ENABLED
UNIX_ENABLED
)
common_compiler_flags()
endfunction()

View File

@@ -1,21 +0,0 @@
#[=======================================================================[.rst:
Linux
-----
This file contains functions for options and configuration for targeting the
Linux platform
]=======================================================================]
function( linux_options )
# Linux Options
endfunction()
function( linux_generate )
target_compile_definitions( ${TARGET_NAME}
PUBLIC
LINUX_ENABLED
UNIX_ENABLED
)
common_compiler_flags()
endfunction()

View File

@@ -1,46 +0,0 @@
#[=======================================================================[.rst:
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
]=======================================================================]
# 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 )
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}
)
common_compiler_flags()
endfunction()

View File

@@ -1,42 +0,0 @@
#[=======================================================================[.rst:
Web
---
This file contains functions for options and configuration for targeting the
Web platform
]=======================================================================]
# Emscripten requires this hack for use of the SHARED option
set( CMAKE_PROJECT_godot-cpp_INCLUDE cmake/emsdkHack.cmake )
function( web_options )
# web options
endfunction()
function( web_generate )
target_compile_definitions(${TARGET_NAME}
PUBLIC
WEB_ENABLED
UNIX_ENABLED
)
target_compile_options( ${TARGET_NAME}
PUBLIC
-sSIDE_MODULE
-sSUPPORT_LONGJMP=wasm
-fno-exceptions
$<${THREADS_ENABLED}:-sUSE_PTHREADS=1>
)
target_link_options( ${TARGET_NAME}
INTERFACE
-sWASM_BIGINT
-sSUPPORT_LONGJMP=wasm
-fvisibility=hidden
-shared
)
common_compiler_flags()
endfunction()

View File

@@ -1,103 +0,0 @@
#[=======================================================================[.rst:
Windows
-------
This file contains functions for options and configuration for targeting the
Windows platform
Because this file is 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
MSVC Runtime Selection
----------------------
There are two main ways to set the msvc runtime library;
Using ``target_compile_options()`` to add the flags
or using the ``CMAKE_MSVC_RUNTIME_LIBRARY`` property_ abstraction, introduced
in CMake version 3.15 with the policy CMP0091_ to remove the flags from
``CMAKE_<LANG>_FLAGS_<CONFIG>``.
Default: ``CMAKE_MSVC_RUNTIME_LIBRARY="MultiThreaded$<$<CONFIG:Debug>:Debug>DLL"``
This initializes each target's ``MSVC_RUNTIME_LIBRARY`` property at the time of
target creation.
it is stated in the msvc_ documentation that: "All modules passed to a given
invocation of the linker must have been compiled with the same runtime library
compiler option (/MD, /MT, /LD)."
This creates a conundrum for us, the ``CMAKE_MSVC_RUNTIME_LIBRARY`` needs to be
correct at the time the target is created, but we have no control over the
consumers CMake scripts, and the per-target ``MSVC_RUNTIME_LIBRARY`` property
is not transient.
It has been raised that not using ``CMAKE_MSVC_RUNTIME_LIBRARY`` can also cause
issues_ when a dependency( independent to godot-cpp ) that doesn't set any
runtime flags, which relies purely on the ``CMAKE_MSVC_RUNTIME_LIBRARY``
variable will very likely not have the correct msvc runtime flags set.
So we'll set ``CMAKE_MSVC_RUNTIME_LIBRARY`` as CACHE STRING so that it will be
available for consumer target definitions, but also be able to be overridden if
needed.
Additionally we message consumers notifying them and pointing to this
documentation.
.. _CMP0091:https://cmake.org/cmake/help/latest/policy/CMP0091.html
.. _property:https://cmake.org/cmake/help/latest/variable/CMAKE_MSVC_RUNTIME_LIBRARY.html
.. https://discourse.cmake.org/t/mt-staticrelease-doesnt-match-value-md-dynamicrelease/5428/4
.. _msvc: https://learn.microsoft.com/en-us/cpp/build/reference/md-mt-ld-use-run-time-library
.. _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")
set( CMAKE_MSVC_RUNTIME_LIBRARY
"MultiThreaded$<IF:$<BOOL:${GODOTCPP_DEBUG_CRT}>,DebugDLL,$<$<NOT:$<BOOL:${GODOTCPP_USE_STATIC_CPP}>>:DLL>>"
CACHE STRING "Select the MSVC runtime library for use by compilers targeting the MSVC ABI.")
endfunction()
#[===========================[ Target Generation ]===========================]
function( windows_generate )
set( STATIC_CPP "$<BOOL:${GODOTCPP_USE_STATIC_CPP}>")
set_target_properties( ${TARGET_NAME}
PROPERTIES
PDB_OUTPUT_DIRECTORY "$<1:${CMAKE_SOURCE_DIR}/bin>"
)
target_compile_definitions( ${TARGET_NAME}
PUBLIC
WINDOWS_ENABLED
$<${IS_MSVC}:
TYPED_METHOD_BIND
NOMINMAX
>
)
target_link_options( ${TARGET_NAME}
PUBLIC
$<${NOT_MSVC}:
-Wl,--no-undefined
$<${STATIC_CPP}:
-static
-static-libgcc
-static-libstdc++
>
>
$<${IS_CLANG}:-lstdc++>
)
common_compiler_flags()
endfunction()

View File

@@ -1,377 +0,0 @@
CMake
=====
.. warning::
The CMake scripts do not have feature parity with the SCons ones at this
stage and are still a work in progress. There are a number of people who
have been working on alternative CMake solutions that are frequently
referenced in the discord chats: Ivan's cmake-rewrite_ branch and
Vorlac's godot-roguelite_ Project
.. _cmake-rewrite: https://github.com/IvanInventor/godot-cpp/tree/cmake-rewrite
.. _godot-roguelite: https://github.com/vorlac/godot-roguelite
Introduction
------------
Compiling godot-cpp independently of an extension project is mainly for
godot-cpp developers, package maintainers, and CI/CD. Look to the
godot-cpp-template_ for a practical example on how to consume the godot-cpp
library as part of a Godot extension.
Configuration examples are listed at the bottom of the page.
.. _godot-cpp-template: https://github.com/godotengine/godot-cpp-template
SCons Deviations
----------------
Not everything from SCons can be perfectly representable in CMake, here are
the notable differences.
- debug_symbols
No longer has an explicit option, and is enabled via Debug-like CMake
build configurations; Debug, RelWithDebInfo.
- dev_build
Does not define NDEBUG when disabled, NDEBUG is set via Release-like
CMake build configurations; Release, MinSizeRel.
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.<target>``
are also 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:
.. 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
Basic walkthrough
-----------------
.. topic:: Clone the git repository
.. code-block::
git clone https://github.com/godotengine/godot-cpp.git
Cloning into 'godot-cpp'...
...
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"
To list the available options CMake use the ``-L[AH]`` option. ``A`` is for
advanced, and ``H`` is for help strings.
.. code-block::
cmake .. -LH
Options are specified on the command line when configuring
.. code-block::
cmake .. -DGODOTCPP_USE_HOT_RELOAD:BOOL=ON \
-DGODOTCPP_PRECISION:STRING=double \
-DCMAKE_BUILD_TYPE:STRING=Debug
Review setting-build-variables_ and build-configurations_ for more information.
.. _setting-build-variables: https://cmake.org/cmake/help/latest/guide/user-interaction/index.html#setting-build-variables
.. _build-configurations: https://cmake.org/cmake/help/latest/manual/cmake-buildsystem.7.html#build-configurations
A non-exhaustive list of options:
.. code-block::
// Path to a custom GDExtension API JSON file (takes precedence over `GODOTCPP_GDEXTENSION_DIR`) ( /path/to/custom_api_file )
`GODOTCPP_CUSTOM_API_FILE:FILEPATH=`
// Force disabling exception handling code (ON|OFF)
GODOTCPP_DISABLE_EXCEPTIONS:BOOL=ON
// 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:: 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.
.. code-block::
cmake --build . -t template_debug --config Debug
Examples
--------
Windows and MSVC - Release
~~~~~~~~~~~~~~~~~~~~~~~~~~
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.
.. _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
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
needs to be specified at Configure time.
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
MSys2/clang64, "Ninja Multi-Config" - dev_build, Debug Symbols
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Assumes the ming-w64-clang-x86_64-toolchain is installed
This time we are choosing the 'Ninja Multi-Config' generator, so the build
type is specified at build time.
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
Emscripten for web platform
~~~~~~~~~~~~~~~~~~~~~~~~~~~
I've only tested this on windows so far.
I cloned and installed the latest Emscripten tools to ``c:\emsdk``
At the time of writing that was v3.1.69
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
.. 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
Android Cross Compile from Windows
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
There are two separate paths you can choose when configuring for android.
Use the ``CMAKE_ANDROID_*`` variables specified on the commandline or in your
own toolchain file as listed in the cmake-toolchains_ documentation
.. _cmake-toolchains: https://cmake.org/cmake/help/latest/manual/cmake-toolchains.7.html#cross-compiling-for-android-with-the-ndk
Or use the toolchain and scripts provided by the Android SDK and make changes
using the ``ANDROID_*`` variables listed there. Where ``<version>`` is whatever
ndk version you have installed (tested with `23.2.8568313`) and ``<platform>``
is for android sdk platform, (tested with ``android-29``)
.. warning::
The Android SDK website explicitly states that they do not support using
the CMake built-in method, and recommends you stick with their toolchain
files.
.. topic:: Using your own toolchain file as described in the CMake documentation
.. 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
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 .. \
-DCMAKE_SYSTEM_NAME=Android \
-DCMAKE_SYSTEM_VERSION=<platform> \
-DCMAKE_ANDROID_ARCH_ABI=<arch> \
-DCMAKE_ANDROID_NDK=/path/to/android-ndk
cmake --build . -t template_release
.. topic:: Using the toolchain file from the Android SDK
Defaults to minimum supported version( android-16 in my case) and armv7-a.
.. code-block::
# Assuming our current directory is the godot-cpp source root
mkdir build-android
cd build-android
cmake .. --toolchain $ANDROID_HOME/ndk/<version>/build/cmake/android.toolchain.cmake
cmake --build . -t template_release
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/<version>/build/cmake/android.toolchain.cmake \
-DANDROID_PLATFORM:STRING=android-29 \
-DANDROID_ABI:STRING=armeabi-v7a
cmake --build . -t template_release
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 ``<arch>[sub][-vendor][-OS][-env]``
* `osdev.org <https://wiki.osdev.org/Target_Triplet>`_
* `stack overflow <https://stackoverflow.com/questions/13819857/does-a-list-of-all-known-target-triplets-in-use-exist>`_
* `LLVM <https://llvm.org/doxygen/classllvm_1_1Triple.html>`_
* `clang target triple <https://clang.llvm.org/docs/CrossCompilation.html#target-triple>`_
* `vcpkg <https://learn.microsoft.com/en-us/vcpkg/concepts/triplets>`_
* `wasm32-unknown-emscripten <https://blog.therocode.net/2020/10/a-guide-to-rust-sdl2-emscripten>`_
Linux Host
~~~~~~~~~~
:Target: x86_64-linux
Macos Host
~~~~~~~~~~
:System: Mac Mini
:OS Name: Sequoia 15.0.1
:Processor: Apple M2
Windows Host
~~~~~~~~~~~~
:OS Name: Microsoft Windows 11 Home, 10.0.22631 N/A Build 22631
:Processor: AMD Ryzen 7 6800HS Creator Edition
`Microsoft Visual Studio 17 2022 <https://visualstudio.microsoft.com/vs/>`_
:Target: x86_64-w64
`LLVM <https://llvm.org/>`_
:Target: x86_64-pc-windows-msvc
`AndroidSDK <https://developer.android.com/studio/#command-tools>`_
armv7-none-linux-androideabi16
`Emscripten <https://emscripten.org/>`_
:Compiler: Emscripten
:Target: wasm32-unknown-emscripten
`MinGW-w64 <https://www.mingw-w64.org/>`_ based toolchains
`MSYS2 <https://www.msys2.org/>`_
Necessary reading about MSYS2 `environments <https://www.msys2.org/docs/environments/>`_
ucrt64
:Compiler: gcc version 14.2.0 (Rev1, Built by MSYS2 project)
:Target: x86_64-w64-mingw32
clang64
:Compiler: clang version 18.1.8
:Target: x86_64-w64-windows-gnu
`LLVM-MinGW <https://github.com/mstorsjo/llvm-mingw/releases>`_
`MinGW-W64-builds <https://github.com/niXman/mingw-builds-binaries/releases>`_
:Compiler: gcc
:Target: x86_64-w64-mingw32-ucrt
`Jetbrains-CLion <https://www.jetbrains.com/clion/>`_
:Target: x86_64-w64-mingw32-msvcrt

View File

@@ -1,55 +0,0 @@
#!/usr/bin/env python
import glob
import os
import zlib
def generate_doc_source(dst, source):
g = open(dst, "w", encoding="utf-8")
buf = ""
docbegin = ""
docend = ""
for src in source:
src_path = str(src)
if not src_path.endswith(".xml"):
continue
with open(src_path, "r", encoding="utf-8") as f:
content = f.read()
buf += content
buf = (docbegin + buf + docend).encode("utf-8")
decomp_size = len(buf)
# Use maximum zlib compression level to further reduce file size
# (at the cost of initial build times).
buf = zlib.compress(buf, zlib.Z_BEST_COMPRESSION)
g.write("/* THIS FILE IS GENERATED DO NOT EDIT */\n")
g.write("\n")
g.write("#include <godot_cpp/godot.hpp>\n")
g.write("\n")
g.write('static const char *_doc_data_hash = "' + str(hash(buf)) + '";\n')
g.write("static const int _doc_data_uncompressed_size = " + str(decomp_size) + ";\n")
g.write("static const int _doc_data_compressed_size = " + str(len(buf)) + ";\n")
g.write("static const unsigned char _doc_data_compressed[] = {\n")
for i in range(len(buf)):
g.write("\t" + str(buf[i]) + ",\n")
g.write("};\n")
g.write("\n")
g.write(
"static godot::internal::DocDataRegistration _doc_data_registration(_doc_data_hash, _doc_data_uncompressed_size, _doc_data_compressed_size, _doc_data_compressed);\n"
)
g.write("\n")
g.close()
def scons_generate_doc_source(target, source, env):
generate_doc_source(str(target[0]), source)
def generate_doc_source_from_directory(target, directory):
generate_doc_source(target, glob.glob(os.path.join(directory, "*.xml")))

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,62 +0,0 @@
/**************************************************************************/
/* editor_plugin_registration.hpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* 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 GODOT_EDITOR_PLUGIN_REGISTRATION_HPP
#define GODOT_EDITOR_PLUGIN_REGISTRATION_HPP
#include <godot_cpp/templates/vector.hpp>
namespace godot {
class EditorPlugin;
class StringName;
class EditorPlugins {
private:
static Vector<StringName> plugin_classes;
public:
static void add_plugin_class(const StringName &p_class_name);
static void remove_plugin_class(const StringName &p_class_name);
static void deinitialize(GDExtensionInitializationLevel p_level);
template <typename T>
static void add_by_type() {
add_plugin_class(T::get_class_static());
}
template <typename T>
static void remove_by_type() {
remove_plugin_class(T::get_class_static());
}
};
} // namespace godot
#endif // GODOT_EDITOR_PLUGIN_REGISTRATION_HPP

View File

@@ -45,7 +45,7 @@ namespace godot {
class RefCounted;
template <typename T>
template <class T>
class Ref {
T *reference = nullptr;
@@ -63,7 +63,7 @@ class Ref {
}
void ref_pointer(T *p_ref) {
ERR_FAIL_NULL(p_ref);
ERR_FAIL_COND(!p_ref);
if (p_ref->init_ref()) {
reference = p_ref;
@@ -88,15 +88,26 @@ public:
return reference != p_r.reference;
}
_FORCE_INLINE_ T *operator*() const {
_FORCE_INLINE_ T *operator->() {
return reference;
}
_FORCE_INLINE_ T *operator->() const {
_FORCE_INLINE_ T *operator*() {
return reference;
}
_FORCE_INLINE_ T *ptr() const {
_FORCE_INLINE_ const T *operator->() const {
return reference;
}
_FORCE_INLINE_ const T *ptr() const {
return reference;
}
_FORCE_INLINE_ T *ptr() {
return reference;
}
_FORCE_INLINE_ const T *operator*() const {
return reference;
}
@@ -108,7 +119,7 @@ public:
ref(p_from);
}
template <typename T_Other>
template <class T_Other>
void operator=(const Ref<T_Other> &p_from) {
RefCounted *refb = const_cast<RefCounted *>(static_cast<const RefCounted *>(p_from.ptr()));
if (!refb) {
@@ -144,7 +155,7 @@ public:
}
}
template <typename T_Other>
template <class T_Other>
void reference_ptr(T_Other *p_ptr) {
if (reference == p_ptr) {
return;
@@ -161,7 +172,7 @@ public:
ref(p_from);
}
template <typename T_Other>
template <class T_Other>
Ref(const Ref<T_Other> &p_from) {
RefCounted *refb = const_cast<RefCounted *>(static_cast<const RefCounted *>(p_from.ptr()));
if (!refb) {
@@ -219,21 +230,21 @@ public:
// Used exclusively in the bindings to recreate the Ref Godot encapsulates in return values,
// without adding to the refcount.
inline static Ref<T> _gde_internal_constructor(Object *obj) {
inline static Ref<T> ___internal_constructor(Object *obj) {
Ref<T> r;
r.reference = (T *)obj;
return r;
}
};
template <typename T>
template <class T>
struct PtrToArg<Ref<T>> {
_FORCE_INLINE_ static Ref<T> convert(const void *p_ptr) {
GDExtensionRefPtr ref = (GDExtensionRefPtr)p_ptr;
if (unlikely(!p_ptr)) {
return Ref<T>();
}
return Ref<T>(reinterpret_cast<T *>(godot::internal::get_object_instance_binding(godot::internal::gdextension_interface_ref_get_object(ref))));
ERR_FAIL_NULL_V(ref, Ref<T>());
T *obj = reinterpret_cast<T *>(godot::internal::gde_interface->object_get_instance_binding(godot::internal::gde_interface->ref_get_object(ref), godot::internal::token, &T::___binding_callbacks));
return Ref<T>(obj);
}
typedef Ref<T> EncodeT;
@@ -245,38 +256,34 @@ struct PtrToArg<Ref<T>> {
// This code assumes that p_ptr points to an unset Ref<T> variable on the Godot side
// so we only set it if we have an object to set.
if (p_val.is_valid()) {
godot::internal::gdextension_interface_ref_set_object(ref, p_val->_owner);
godot::internal::gde_interface->ref_set_object(ref, p_val->_owner);
}
}
};
template <typename T>
template <class T>
struct PtrToArg<const Ref<T> &> {
typedef Ref<T> EncodeT;
_FORCE_INLINE_ static Ref<T> convert(const void *p_ptr) {
GDExtensionRefPtr ref = const_cast<GDExtensionRefPtr>(p_ptr);
if (unlikely(!p_ptr)) {
return Ref<T>();
}
return Ref<T>(reinterpret_cast<T *>(godot::internal::get_object_instance_binding(godot::internal::gdextension_interface_ref_get_object(ref))));
return Ref<T>(reinterpret_cast<T *>(godot::internal::gde_interface->object_get_instance_binding(*reinterpret_cast<GDExtensionObjectPtr *>(const_cast<void *>(p_ptr)), godot::internal::token, &T::___binding_callbacks)));
}
};
template <typename T>
template <class T>
struct GetTypeInfo<Ref<T>, typename EnableIf<TypeInherits<RefCounted, T>::value>::type> {
static constexpr GDExtensionVariantType VARIANT_TYPE = GDEXTENSION_VARIANT_TYPE_OBJECT;
static constexpr GDExtensionClassMethodArgumentMetadata METADATA = GDEXTENSION_METHOD_ARGUMENT_METADATA_NONE;
static const GDExtensionVariantType VARIANT_TYPE = GDEXTENSION_VARIANT_TYPE_OBJECT;
static const GDExtensionClassMethodArgumentMetadata METADATA = GDEXTENSION_METHOD_ARGUMENT_METADATA_NONE;
static inline PropertyInfo get_class_info() {
return make_property_info(Variant::Type::OBJECT, "", PROPERTY_HINT_RESOURCE_TYPE, T::get_class_static());
}
};
template <typename T>
template <class T>
struct GetTypeInfo<const Ref<T> &, typename EnableIf<TypeInherits<RefCounted, T>::value>::type> {
static constexpr GDExtensionVariantType VARIANT_TYPE = GDEXTENSION_VARIANT_TYPE_OBJECT;
static constexpr GDExtensionClassMethodArgumentMetadata METADATA = GDEXTENSION_METHOD_ARGUMENT_METADATA_NONE;
static const GDExtensionVariantType VARIANT_TYPE = GDEXTENSION_VARIANT_TYPE_OBJECT;
static const GDExtensionClassMethodArgumentMetadata METADATA = GDEXTENSION_METHOD_ARGUMENT_METADATA_NONE;
static inline PropertyInfo get_class_info() {
return make_property_info(Variant::Type::OBJECT, "", PROPERTY_HINT_RESOURCE_TYPE, T::get_class_static());

View File

@@ -36,56 +36,23 @@
#include <godot_cpp/core/property_info.hpp>
#include <godot_cpp/templates/list.hpp>
#include <godot_cpp/templates/vector.hpp>
#include <godot_cpp/godot.hpp>
#if defined(MACOS_ENABLED) && defined(HOT_RELOAD_ENABLED)
#include <mutex>
#define _GODOT_CPP_AVOID_THREAD_LOCAL
#define _GODOT_CPP_THREAD_LOCAL
#else
#define _GODOT_CPP_THREAD_LOCAL thread_local
#endif
namespace godot {
class ClassDB;
typedef void GodotObject;
template <typename T, std::enable_if_t<std::is_base_of<::godot::Wrapped, T>::value, bool> = true>
_ALWAYS_INLINE_ void _pre_initialize();
// Base for all engine classes, to contain the pointer to the engine instance.
class Wrapped {
friend class GDExtensionBinding;
friend class ClassDB;
friend void postinitialize_handler(Wrapped *);
template <typename T, std::enable_if_t<std::is_base_of<::godot::Wrapped, T>::value, bool>>
friend _ALWAYS_INLINE_ void _pre_initialize();
#ifdef _GODOT_CPP_AVOID_THREAD_LOCAL
static std::recursive_mutex _constructing_mutex;
#endif
_GODOT_CPP_THREAD_LOCAL static const StringName *_constructing_extension_class_name;
_GODOT_CPP_THREAD_LOCAL static const GDExtensionInstanceBindingCallbacks *_constructing_class_binding_callbacks;
#ifdef HOT_RELOAD_ENABLED
_GODOT_CPP_THREAD_LOCAL static GDExtensionObjectPtr _constructing_recreate_owner;
#endif
template <typename T>
_ALWAYS_INLINE_ static void _set_construct_info() {
_constructing_extension_class_name = T::_get_extension_class_name();
_constructing_class_binding_callbacks = &T::_gde_binding_callbacks;
}
protected:
virtual bool _is_extension_class() const { return false; }
static const StringName *_get_extension_class_name(); // This is needed to retrieve the class name before the godot object has its _extension and _extension_instance members assigned.
virtual const StringName *_get_extension_class_name() const; // This is needed to retrieve the class name before the godot object has its _extension and _extension_instance members assigned.
virtual const GDExtensionInstanceBindingCallbacks *_get_bindings_callbacks() const = 0;
void _notification(int p_what) {}
bool _set(const StringName &p_name, const Variant &p_property) { return false; }
@@ -93,22 +60,20 @@ protected:
void _get_property_list(List<PropertyInfo> *p_list) const {}
bool _property_can_revert(const StringName &p_name) const { return false; }
bool _property_get_revert(const StringName &p_name, Variant &r_property) const { return false; }
void _validate_property(PropertyInfo &p_property) const {}
String _to_string() const { return "[" + String(get_class_static()) + ":" + itos(get_instance_id()) + "]"; }
static void notification_bind(GDExtensionClassInstancePtr p_instance, int32_t p_what, GDExtensionBool p_reversed) {}
static void notification_bind(GDExtensionClassInstancePtr p_instance, int32_t p_what) {}
static GDExtensionBool set_bind(GDExtensionClassInstancePtr p_instance, GDExtensionConstStringNamePtr p_name, GDExtensionConstVariantPtr p_value) { return false; }
static GDExtensionBool get_bind(GDExtensionClassInstancePtr p_instance, GDExtensionConstStringNamePtr p_name, GDExtensionVariantPtr r_ret) { return false; }
static const GDExtensionPropertyInfo *get_property_list_bind(GDExtensionClassInstancePtr p_instance, uint32_t *r_count) { return nullptr; }
static void free_property_list_bind(GDExtensionClassInstancePtr p_instance, const GDExtensionPropertyInfo *p_list, uint32_t p_count) {}
static void free_property_list_bind(GDExtensionClassInstancePtr p_instance, const GDExtensionPropertyInfo *p_list) {}
static GDExtensionBool property_can_revert_bind(GDExtensionClassInstancePtr p_instance, GDExtensionConstStringNamePtr p_name) { return false; }
static GDExtensionBool property_get_revert_bind(GDExtensionClassInstancePtr p_instance, GDExtensionConstStringNamePtr p_name, GDExtensionVariantPtr r_ret) { return false; }
static GDExtensionBool validate_property_bind(GDExtensionClassInstancePtr p_instance, GDExtensionPropertyInfo *p_property) { return false; }
static void to_string_bind(GDExtensionClassInstancePtr p_instance, GDExtensionBool *r_is_valid, GDExtensionStringPtr r_out) {}
// The only reason this has to be held here, is when we return results of `_get_property_list` to Godot, we pass
// pointers to strings in this list. They have to remain valid to pass the bridge, until the list is freed by Godot...
::godot::List<::godot::PropertyInfo> plist_owned;
GDExtensionPropertyInfo *plist = nullptr;
uint32_t plist_size = 0;
void _postinitialize();
@@ -117,8 +82,8 @@ protected:
virtual ~Wrapped() {}
public:
static const StringName &get_class_static() {
static const StringName string_name = StringName("Wrapped");
static StringName &get_class_static() {
static StringName string_name = StringName("Wrapped");
return string_name;
}
@@ -130,76 +95,23 @@ public:
GodotObject *_owner = nullptr;
};
template <typename T, std::enable_if_t<std::is_base_of<::godot::Wrapped, T>::value, bool>>
_ALWAYS_INLINE_ void _pre_initialize() {
#ifdef _GODOT_CPP_AVOID_THREAD_LOCAL
Wrapped::_constructing_mutex.lock();
#endif
Wrapped::_set_construct_info<T>();
}
_FORCE_INLINE_ void snarray_add_str(Vector<StringName> &arr) {
}
_FORCE_INLINE_ void snarray_add_str(Vector<StringName> &arr, const StringName &p_str) {
arr.push_back(p_str);
}
template <typename... P>
_FORCE_INLINE_ void snarray_add_str(Vector<StringName> &arr, const StringName &p_str, P... p_args) {
arr.push_back(p_str);
snarray_add_str(arr, p_args...);
}
template <typename... P>
_FORCE_INLINE_ Vector<StringName> snarray(P... p_args) {
Vector<StringName> arr;
snarray_add_str(arr, p_args...);
return arr;
}
namespace internal {
GDExtensionPropertyInfo *create_c_property_list(const ::godot::List<::godot::PropertyInfo> &plist_cpp, uint32_t *r_size);
void free_c_property_list(GDExtensionPropertyInfo *plist);
typedef void (*EngineClassRegistrationCallback)();
void add_engine_class_registration_callback(EngineClassRegistrationCallback p_callback);
void register_engine_class(const StringName &p_name, const GDExtensionInstanceBindingCallbacks *p_callbacks);
void register_engine_classes();
template <typename T>
struct EngineClassRegistration {
EngineClassRegistration() {
add_engine_class_registration_callback(&EngineClassRegistration<T>::callback);
}
static void callback() {
register_engine_class(T::get_class_static(), &T::_gde_binding_callbacks);
}
};
} // namespace internal
} // namespace godot
// Use this on top of your own classes.
// Note: the trail of `***` is to keep sane diffs in PRs, because clang-format otherwise moves every `\` which makes
// every line of the macro different
#define GDCLASS(m_class, m_inherits) /***********************************************************************************************************************************************/ \
#define GDCLASS(m_class, m_inherits) \
private: \
void operator=(const m_class & /*p_rval*/) {} \
void operator=(const m_class &p_rval) {} \
friend class ::godot::ClassDB; \
friend class ::godot::Wrapped; \
\
protected: \
virtual bool _is_extension_class() const override { return true; } \
\
static const ::godot::StringName *_get_extension_class_name() { \
const ::godot::StringName &string_name = get_class_static(); \
virtual const ::godot::StringName *_get_extension_class_name() const override { \
static ::godot::StringName string_name = get_class_static(); \
return &string_name; \
} \
\
virtual const GDExtensionInstanceBindingCallbacks *_get_bindings_callbacks() const override { \
return &___binding_callbacks; \
} \
\
static void (*_get_bind_methods())() { \
return &m_class::_bind_methods; \
} \
@@ -220,31 +132,24 @@ protected:
return (void(::godot::Wrapped::*)(::godot::List<::godot::PropertyInfo> * p_list) const) & m_class::_get_property_list; \
} \
\
static bool (::godot::Wrapped::*_get_property_can_revert())(const ::godot::StringName &p_name) const { \
return (bool(::godot::Wrapped::*)(const ::godot::StringName &p_name) const) & m_class::_property_can_revert; \
static bool (::godot::Wrapped::*_get_property_can_revert())(const ::godot::StringName &p_name) { \
return (bool(::godot::Wrapped::*)(const ::godot::StringName &p_name)) & m_class::_property_can_revert; \
} \
\
static bool (::godot::Wrapped::*_get_property_get_revert())(const ::godot::StringName &p_name, ::godot::Variant &) const { \
return (bool(::godot::Wrapped::*)(const ::godot::StringName &p_name, ::godot::Variant &) const) & m_class::_property_get_revert; \
static bool (::godot::Wrapped::*_get_property_get_revert())(const ::godot::StringName &p_name, ::godot::Variant &) { \
return (bool(::godot::Wrapped::*)(const ::godot::StringName &p_name, ::godot::Variant &)) & m_class::_property_get_revert; \
} \
\
static void (::godot::Wrapped::*_get_validate_property())(::godot::PropertyInfo & p_property) const { \
return (void(::godot::Wrapped::*)(::godot::PropertyInfo & p_property) const) & m_class::_validate_property; \
static ::godot::String (::godot::Wrapped::*_get_to_string())() { \
return (::godot::String(::godot::Wrapped::*)()) & m_class::_to_string; \
} \
\
static ::godot::String (::godot::Wrapped::*_get_to_string())() const { \
return (::godot::String(::godot::Wrapped::*)() const) & m_class::_to_string; \
} \
\
template <typename T, typename B> \
template <class T, class B> \
static void register_virtuals() { \
m_inherits::register_virtuals<T, B>(); \
} \
\
public: \
typedef m_class self_type; \
typedef m_inherits parent_type; \
\
static void initialize_class() { \
static bool initialized = false; \
if (initialized) { \
@@ -258,78 +163,86 @@ public:
initialized = true; \
} \
\
static const ::godot::StringName &get_class_static() { \
static const ::godot::StringName string_name = ::godot::StringName(U## #m_class); \
static ::godot::StringName &get_class_static() { \
static ::godot::StringName string_name = ::godot::StringName(#m_class); \
return string_name; \
} \
\
static const ::godot::StringName &get_parent_class_static() { \
static ::godot::StringName &get_parent_class_static() { \
return m_inherits::get_class_static(); \
} \
\
static void notification_bind(GDExtensionClassInstancePtr p_instance, int32_t p_what, GDExtensionBool p_reversed) { \
static GDExtensionObjectPtr create(void *data) { \
m_class *new_object = memnew(m_class); \
return new_object->_owner; \
} \
\
static void notification_bind(GDExtensionClassInstancePtr p_instance, int32_t p_what) { \
if (p_instance && m_class::_get_notification()) { \
if (!p_reversed) { \
m_inherits::notification_bind(p_instance, p_what, p_reversed); \
} \
if (m_class::_get_notification() != m_inherits::_get_notification()) { \
m_class *cls = reinterpret_cast<m_class *>(p_instance); \
cls->_notification(p_what); \
} \
if (p_reversed) { \
m_inherits::notification_bind(p_instance, p_what, p_reversed); \
return cls->_notification(p_what); \
} \
m_inherits::notification_bind(p_instance, p_what); \
} \
} \
\
static GDExtensionBool set_bind(GDExtensionClassInstancePtr p_instance, GDExtensionConstStringNamePtr p_name, GDExtensionConstVariantPtr p_value) { \
if (p_instance) { \
if (m_inherits::set_bind(p_instance, p_name, p_value)) { \
return true; \
} \
if (p_instance && m_class::_get_set()) { \
if (m_class::_get_set() != m_inherits::_get_set()) { \
m_class *cls = reinterpret_cast<m_class *>(p_instance); \
return cls->_set(*reinterpret_cast<const ::godot::StringName *>(p_name), *reinterpret_cast<const ::godot::Variant *>(p_value)); \
} \
return m_inherits::set_bind(p_instance, p_name, p_value); \
} \
return false; \
} \
\
static GDExtensionBool get_bind(GDExtensionClassInstancePtr p_instance, GDExtensionConstStringNamePtr p_name, GDExtensionVariantPtr r_ret) { \
if (p_instance) { \
if (m_inherits::get_bind(p_instance, p_name, r_ret)) { \
return true; \
} \
if (p_instance && m_class::_get_get()) { \
if (m_class::_get_get() != m_inherits::_get_get()) { \
m_class *cls = reinterpret_cast<m_class *>(p_instance); \
return cls->_get(*reinterpret_cast<const ::godot::StringName *>(p_name), *reinterpret_cast<::godot::Variant *>(r_ret)); \
} \
return m_inherits::get_bind(p_instance, p_name, r_ret); \
} \
return false; \
} \
\
static inline bool has_get_property_list() { \
return m_class::_get_get_property_list() && m_class::_get_get_property_list() != m_inherits::_get_get_property_list(); \
} \
\
static const GDExtensionPropertyInfo *get_property_list_bind(GDExtensionClassInstancePtr p_instance, uint32_t *r_count) { \
if (!p_instance) { \
if (r_count) \
*r_count = 0; \
return nullptr; \
if (p_instance && m_class::_get_get_property_list()) { \
if (m_class::_get_get_property_list() != m_inherits::_get_get_property_list()) { \
m_class *cls = reinterpret_cast<m_class *>(p_instance); \
ERR_FAIL_COND_V_MSG(!cls->plist_owned.is_empty() || cls->plist != nullptr || cls->plist_size != 0, nullptr, "Internal error, property list was not freed by engine!"); \
cls->_get_property_list(&cls->plist_owned); \
cls->plist = reinterpret_cast<GDExtensionPropertyInfo *>(memalloc(sizeof(GDExtensionPropertyInfo) * cls->plist_owned.size())); \
cls->plist_size = 0; \
for (const ::godot::PropertyInfo &E : cls->plist_owned) { \
cls->plist[cls->plist_size].type = static_cast<GDExtensionVariantType>(E.type); \
cls->plist[cls->plist_size].name = E.name._native_ptr(); \
cls->plist[cls->plist_size].hint = E.hint; \
cls->plist[cls->plist_size].hint_string = E.hint_string._native_ptr(); \
cls->plist[cls->plist_size].class_name = E.class_name._native_ptr(); \
cls->plist[cls->plist_size].usage = E.usage; \
cls->plist_size++; \
} \
if (r_count) \
*r_count = cls->plist_size; \
return cls->plist; \
} \
return m_inherits::get_property_list_bind(p_instance, r_count); \
} \
m_class *cls = reinterpret_cast<m_class *>(p_instance); \
::godot::List<::godot::PropertyInfo> &plist_cpp = cls->plist_owned; \
ERR_FAIL_COND_V_MSG(!plist_cpp.is_empty(), nullptr, "Internal error, property list was not freed by engine!"); \
cls->_get_property_list(&plist_cpp); \
return ::godot::internal::create_c_property_list(plist_cpp, r_count); \
return nullptr; \
} \
\
static void free_property_list_bind(GDExtensionClassInstancePtr p_instance, const GDExtensionPropertyInfo *p_list, uint32_t /*p_count*/) { \
static void free_property_list_bind(GDExtensionClassInstancePtr p_instance, const GDExtensionPropertyInfo *p_list) { \
if (p_instance) { \
m_class *cls = reinterpret_cast<m_class *>(p_instance); \
ERR_FAIL_COND_MSG(cls->plist == nullptr, "Internal error, property list double free!"); \
memfree(cls->plist); \
cls->plist = nullptr; \
cls->plist_size = 0; \
cls->plist_owned.clear(); \
::godot::internal::free_c_property_list(const_cast<GDExtensionPropertyInfo *>(p_list)); \
} \
} \
\
@@ -355,21 +268,6 @@ public:
return false; \
} \
\
static GDExtensionBool validate_property_bind(GDExtensionClassInstancePtr p_instance, GDExtensionPropertyInfo *p_property) { \
bool ret = false; \
if (p_instance && m_class::_get_validate_property()) { \
ret = m_inherits::validate_property_bind(p_instance, p_property); \
if (m_class::_get_validate_property() != m_inherits::_get_validate_property()) { \
m_class *cls = reinterpret_cast<m_class *>(p_instance); \
::godot::PropertyInfo info(p_property); \
cls->_validate_property(info); \
info._update(p_property); \
return true; \
} \
} \
return ret; \
} \
\
static void to_string_bind(GDExtensionClassInstancePtr p_instance, GDExtensionBool *r_is_valid, GDExtensionStringPtr r_out) { \
if (p_instance && m_class::_get_to_string()) { \
if (m_class::_get_to_string() != m_inherits::_get_to_string()) { \
@@ -382,7 +280,7 @@ public:
} \
} \
\
static void free(void * /*data*/, GDExtensionClassInstancePtr ptr) { \
static void free(void *data, GDExtensionClassInstancePtr ptr) { \
if (ptr) { \
m_class *cls = reinterpret_cast<m_class *>(ptr); \
cls->~m_class(); \
@@ -390,126 +288,97 @@ public:
} \
} \
\
static void *_gde_binding_create_callback(void * /*p_token*/, void * /*p_instance*/) { \
static void *___binding_create_callback(void *p_token, void *p_instance) { \
return nullptr; \
} \
\
static void _gde_binding_free_callback(void * /*p_token*/, void * /*p_instance*/, void * /*p_binding*/) { \
static void ___binding_free_callback(void *p_token, void *p_instance, void *p_binding) { \
} \
\
static GDExtensionBool _gde_binding_reference_callback(void * /*p_token*/, void * /*p_instance*/, GDExtensionBool /*p_reference*/) { \
static GDExtensionBool ___binding_reference_callback(void *p_token, void *p_instance, GDExtensionBool p_reference) { \
return true; \
} \
\
static constexpr GDExtensionInstanceBindingCallbacks _gde_binding_callbacks = { \
_gde_binding_create_callback, \
_gde_binding_free_callback, \
_gde_binding_reference_callback, \
}; \
\
private:
static constexpr GDExtensionInstanceBindingCallbacks ___binding_callbacks = { \
___binding_create_callback, \
___binding_free_callback, \
___binding_reference_callback, \
};
// Don't use this for your classes, use GDCLASS() instead.
#define GDEXTENSION_CLASS_ALIAS(m_class, m_alias_for, m_inherits) /******************************************************************************************************************/ \
private: \
inline static ::godot::internal::EngineClassRegistration<m_class> _gde_engine_class_registration_helper; \
void operator=(const m_class &p_rval) {} \
friend class ::godot::ClassDB; \
friend class ::godot::Wrapped; \
\
protected: \
m_class(const char *p_godot_class) : m_inherits(p_godot_class) {} \
m_class(GodotObject *p_godot_object) : m_inherits(p_godot_object) {} \
\
static void _bind_methods() {} \
\
static void (*_get_bind_methods())() { \
return nullptr; \
} \
\
static void (Wrapped::*_get_notification())(int) { \
return nullptr; \
} \
\
static bool (Wrapped::*_get_set())(const ::godot::StringName &p_name, const Variant &p_property) { \
return nullptr; \
} \
\
static bool (Wrapped::*_get_get())(const ::godot::StringName &p_name, Variant &r_ret) const { \
return nullptr; \
} \
\
static inline bool has_get_property_list() { \
return false; \
} \
\
static void (Wrapped::*_get_get_property_list())(List<PropertyInfo> * p_list) const { \
return nullptr; \
} \
\
static bool (Wrapped::*_get_property_can_revert())(const ::godot::StringName &p_name) const { \
return nullptr; \
} \
\
static bool (Wrapped::*_get_property_get_revert())(const ::godot::StringName &p_name, Variant &) const { \
return nullptr; \
} \
\
static void (Wrapped::*_get_validate_property())(::godot::PropertyInfo & p_property) const { \
return nullptr; \
} \
\
static String (Wrapped::*_get_to_string())() const { \
return nullptr; \
} \
\
public: \
typedef m_class self_type; \
typedef m_inherits parent_type; \
\
static void initialize_class() {} \
\
static const ::godot::StringName &get_class_static() { \
static const ::godot::StringName string_name = ::godot::StringName(#m_alias_for); \
return string_name; \
} \
\
static const ::godot::StringName &get_parent_class_static() { \
return m_inherits::get_class_static(); \
} \
\
static void free(void *data, GDExtensionClassInstancePtr ptr) { \
} \
\
static void *_gde_binding_create_callback(void *p_token, void *p_instance) { \
/* Do not call memnew here, we don't want the post-initializer to be called */ \
return new ("", "") m_class((GodotObject *)p_instance); \
} \
static void _gde_binding_free_callback(void *p_token, void *p_instance, void *p_binding) { \
/* Explicitly call the deconstructor to ensure proper lifecycle for non-trivial members */ \
reinterpret_cast<m_class *>(p_binding)->~m_class(); \
Memory::free_static(reinterpret_cast<m_class *>(p_binding)); \
} \
static GDExtensionBool _gde_binding_reference_callback(void *p_token, void *p_instance, GDExtensionBool p_reference) { \
return true; \
} \
static constexpr GDExtensionInstanceBindingCallbacks _gde_binding_callbacks = { \
_gde_binding_create_callback, \
_gde_binding_free_callback, \
_gde_binding_reference_callback, \
}; \
m_class() : m_class(#m_alias_for) {} \
\
private:
// Don't use this for your classes, use GDCLASS() instead.
#define GDEXTENSION_CLASS(m_class, m_inherits) GDEXTENSION_CLASS_ALIAS(m_class, m_class, m_inherits)
#define GDVIRTUAL_CALL(m_name, ...) _gdvirtual_##m_name##_call(__VA_ARGS__)
#define GDVIRTUAL_CALL_PTR(m_obj, m_name, ...) m_obj->_gdvirtual_##m_name##_call(__VA_ARGS__)
#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()
#define GDEXTENSION_CLASS(m_class, m_inherits) \
private: \
void operator=(const m_class &p_rval) {} \
\
protected: \
virtual const GDExtensionInstanceBindingCallbacks *_get_bindings_callbacks() const override { \
return &___binding_callbacks; \
} \
\
m_class(const char *p_godot_class) : m_inherits(p_godot_class) {} \
m_class(GodotObject *p_godot_object) : m_inherits(p_godot_object) {} \
\
static void (*_get_bind_methods())() { \
return nullptr; \
} \
\
static void (Wrapped::*_get_notification())(int) { \
return nullptr; \
} \
\
static bool (Wrapped::*_get_set())(const ::godot::StringName &p_name, const Variant &p_property) { \
return nullptr; \
} \
\
static bool (Wrapped::*_get_get())(const ::godot::StringName &p_name, Variant &r_ret) const { \
return nullptr; \
} \
\
static void (Wrapped::*_get_get_property_list())(List<PropertyInfo> * p_list) const { \
return nullptr; \
} \
\
static bool (Wrapped::*_get_property_can_revert())(const ::godot::StringName &p_name) { \
return nullptr; \
} \
\
static bool (Wrapped::*_get_property_get_revert())(const ::godot::StringName &p_name, Variant &) { \
return nullptr; \
} \
\
static String (Wrapped::*_get_to_string())() { \
return nullptr; \
} \
\
public: \
static void initialize_class() {} \
\
static ::godot::StringName &get_class_static() { \
static ::godot::StringName string_name = ::godot::StringName(#m_class); \
return string_name; \
} \
\
static ::godot::StringName &get_parent_class_static() { \
return m_inherits::get_class_static(); \
} \
\
static void *___binding_create_callback(void *p_token, void *p_instance) { \
/* Do not call memnew here, we don't want the postinitializer to be called */ \
return new ("") m_class((GodotObject *)p_instance); \
} \
static void ___binding_free_callback(void *p_token, void *p_instance, void *p_binding) { \
/* Explicitly call the deconstructor to ensure proper lifecycle for non-trivial members */ \
reinterpret_cast<m_class *>(p_binding)->~m_class(); \
Memory::free_static(reinterpret_cast<m_class *>(p_binding)); \
} \
static GDExtensionBool ___binding_reference_callback(void *p_token, void *p_instance, GDExtensionBool p_reference) { \
return true; \
} \
static constexpr GDExtensionInstanceBindingCallbacks ___binding_callbacks = { \
___binding_create_callback, \
___binding_free_callback, \
___binding_reference_callback, \
}; \
m_class() : m_class(#m_class) {}
#endif // GODOT_WRAPPED_HPP

View File

@@ -83,7 +83,7 @@ namespace godot {
}; \
}
template <typename T>
template <class T>
struct VariantCaster {
static _FORCE_INLINE_ T cast(const Variant &p_variant) {
using TStripped = std::remove_pointer_t<T>;
@@ -95,7 +95,7 @@ struct VariantCaster {
}
};
template <typename T>
template <class T>
struct VariantCaster<T &> {
static _FORCE_INLINE_ T cast(const Variant &p_variant) {
using TStripped = std::remove_pointer_t<T>;
@@ -107,7 +107,7 @@ struct VariantCaster<T &> {
}
};
template <typename T>
template <class T>
struct VariantCaster<const T &> {
static _FORCE_INLINE_ T cast(const Variant &p_variant) {
using TStripped = std::remove_pointer_t<T>;
@@ -144,11 +144,11 @@ struct VariantObjectClassChecker<const Ref<T> &> {
}
};
template <typename T>
template <class T>
struct VariantCasterAndValidate {
static _FORCE_INLINE_ T cast(const Variant **p_args, uint32_t p_arg_idx, GDExtensionCallError &r_error) {
GDExtensionVariantType argtype = GDExtensionVariantType(GetTypeInfo<T>::VARIANT_TYPE);
if (!internal::gdextension_interface_variant_can_convert_strict(static_cast<GDExtensionVariantType>(p_args[p_arg_idx]->get_type()), argtype) ||
if (!internal::gde_interface->variant_can_convert_strict(static_cast<GDExtensionVariantType>(p_args[p_arg_idx]->get_type()), argtype) ||
!VariantObjectClassChecker<T>::check(p_args[p_arg_idx])) {
r_error.error = GDEXTENSION_CALL_ERROR_INVALID_ARGUMENT;
r_error.argument = p_arg_idx;
@@ -159,11 +159,11 @@ struct VariantCasterAndValidate {
}
};
template <typename T>
template <class T>
struct VariantCasterAndValidate<T &> {
static _FORCE_INLINE_ T cast(const Variant **p_args, uint32_t p_arg_idx, GDExtensionCallError &r_error) {
GDExtensionVariantType argtype = GDExtensionVariantType(GetTypeInfo<T>::VARIANT_TYPE);
if (!internal::gdextension_interface_variant_can_convert_strict(static_cast<GDExtensionVariantType>(p_args[p_arg_idx]->get_type()), argtype) ||
if (!internal::gde_interface->variant_can_convert_strict(static_cast<GDExtensionVariantType>(p_args[p_arg_idx]->get_type()), argtype) ||
!VariantObjectClassChecker<T>::check(p_args[p_arg_idx])) {
r_error.error = GDEXTENSION_CALL_ERROR_INVALID_ARGUMENT;
r_error.argument = p_arg_idx;
@@ -174,11 +174,11 @@ struct VariantCasterAndValidate<T &> {
}
};
template <typename T>
template <class T>
struct VariantCasterAndValidate<const T &> {
static _FORCE_INLINE_ T cast(const Variant **p_args, uint32_t p_arg_idx, GDExtensionCallError &r_error) {
GDExtensionVariantType argtype = GDExtensionVariantType(GetTypeInfo<T>::VARIANT_TYPE);
if (!internal::gdextension_interface_variant_can_convert_strict(static_cast<GDExtensionVariantType>(p_args[p_arg_idx]->get_type()), argtype) ||
if (!internal::gde_interface->variant_can_convert_strict(static_cast<GDExtensionVariantType>(p_args[p_arg_idx]->get_type()), argtype) ||
!VariantObjectClassChecker<T>::check(p_args[p_arg_idx])) {
r_error.error = GDEXTENSION_CALL_ERROR_INVALID_ARGUMENT;
r_error.argument = p_arg_idx;
@@ -189,47 +189,47 @@ struct VariantCasterAndValidate<const T &> {
}
};
template <typename T, typename... P, size_t... Is>
template <class T, class... P, size_t... Is>
void call_with_ptr_args_helper(T *p_instance, void (T::*p_method)(P...), const GDExtensionConstTypePtr *p_args, IndexSequence<Is...>) {
(p_instance->*p_method)(PtrToArg<P>::convert(p_args[Is])...);
}
template <typename T, typename... P, size_t... Is>
template <class T, class... P, size_t... Is>
void call_with_ptr_argsc_helper(T *p_instance, void (T::*p_method)(P...) const, const GDExtensionConstTypePtr *p_args, IndexSequence<Is...>) {
(p_instance->*p_method)(PtrToArg<P>::convert(p_args[Is])...);
}
template <typename T, typename R, typename... P, size_t... Is>
template <class T, class R, class... P, size_t... Is>
void call_with_ptr_args_ret_helper(T *p_instance, R (T::*p_method)(P...), const GDExtensionConstTypePtr *p_args, void *r_ret, IndexSequence<Is...>) {
PtrToArg<R>::encode((p_instance->*p_method)(PtrToArg<P>::convert(p_args[Is])...), r_ret);
}
template <typename T, typename R, typename... P, size_t... Is>
template <class T, class R, class... P, size_t... Is>
void call_with_ptr_args_retc_helper(T *p_instance, R (T::*p_method)(P...) const, const GDExtensionConstTypePtr *p_args, void *r_ret, IndexSequence<Is...>) {
PtrToArg<R>::encode((p_instance->*p_method)(PtrToArg<P>::convert(p_args[Is])...), r_ret);
}
template <typename T, typename... P>
template <class T, class... P>
void call_with_ptr_args(T *p_instance, void (T::*p_method)(P...), const GDExtensionConstTypePtr *p_args, void * /*ret*/) {
call_with_ptr_args_helper<T, P...>(p_instance, p_method, p_args, BuildIndexSequence<sizeof...(P)>{});
}
template <typename T, typename... P>
template <class T, class... P>
void call_with_ptr_args(T *p_instance, void (T::*p_method)(P...) const, const GDExtensionConstTypePtr *p_args, void * /*ret*/) {
call_with_ptr_argsc_helper<T, P...>(p_instance, p_method, p_args, BuildIndexSequence<sizeof...(P)>{});
}
template <typename T, typename R, typename... P>
template <class T, class R, class... P>
void call_with_ptr_args(T *p_instance, R (T::*p_method)(P...), const GDExtensionConstTypePtr *p_args, void *r_ret) {
call_with_ptr_args_ret_helper<T, R, P...>(p_instance, p_method, p_args, r_ret, BuildIndexSequence<sizeof...(P)>{});
}
template <typename T, typename R, typename... P>
template <class T, class R, class... P>
void call_with_ptr_args(T *p_instance, R (T::*p_method)(P...) const, const GDExtensionConstTypePtr *p_args, void *r_ret) {
call_with_ptr_args_retc_helper<T, R, P...>(p_instance, p_method, p_args, r_ret, BuildIndexSequence<sizeof...(P)>{});
}
template <typename T, typename... P, size_t... Is>
template <class T, class... P, size_t... Is>
void call_with_variant_args_helper(T *p_instance, void (T::*p_method)(P...), const Variant **p_args, GDExtensionCallError &r_error, IndexSequence<Is...>) {
r_error.error = GDEXTENSION_CALL_OK;
@@ -241,7 +241,7 @@ void call_with_variant_args_helper(T *p_instance, void (T::*p_method)(P...), con
(void)(p_args); // Avoid warning.
}
template <typename T, typename... P, size_t... Is>
template <class T, class... P, size_t... Is>
void call_with_variant_argsc_helper(T *p_instance, void (T::*p_method)(P...) const, const Variant **p_args, GDExtensionCallError &r_error, IndexSequence<Is...>) {
r_error.error = GDEXTENSION_CALL_OK;
@@ -253,7 +253,7 @@ void call_with_variant_argsc_helper(T *p_instance, void (T::*p_method)(P...) con
(void)(p_args); // Avoid warning.
}
template <typename T, typename R, typename... P, size_t... Is>
template <class T, class R, class... P, size_t... Is>
void call_with_variant_args_ret_helper(T *p_instance, R (T::*p_method)(P...), const Variant **p_args, Variant &r_ret, GDExtensionCallError &r_error, IndexSequence<Is...>) {
r_error.error = GDEXTENSION_CALL_OK;
@@ -264,7 +264,7 @@ void call_with_variant_args_ret_helper(T *p_instance, R (T::*p_method)(P...), co
#endif
}
template <typename T, typename R, typename... P, size_t... Is>
template <class T, class R, class... P, size_t... Is>
void call_with_variant_args_retc_helper(T *p_instance, R (T::*p_method)(P...) const, const Variant **p_args, Variant &r_ret, GDExtensionCallError &r_error, IndexSequence<Is...>) {
r_error.error = GDEXTENSION_CALL_OK;
@@ -276,66 +276,12 @@ void call_with_variant_args_retc_helper(T *p_instance, R (T::*p_method)(P...) co
(void)p_args;
}
template <typename T, typename... P>
void call_with_variant_args(T *p_instance, void (T::*p_method)(P...), const Variant **p_args, int p_argcount, GDExtensionCallError &r_error) {
#ifdef DEBUG_ENABLED
if ((size_t)p_argcount > sizeof...(P)) {
r_error.error = GDEXTENSION_CALL_ERROR_TOO_MANY_ARGUMENTS;
r_error.expected = (int32_t)sizeof...(P);
return;
}
if ((size_t)p_argcount < sizeof...(P)) {
r_error.error = GDEXTENSION_CALL_ERROR_TOO_FEW_ARGUMENTS;
r_error.expected = (int32_t)sizeof...(P);
return;
}
#endif
call_with_variant_args_helper<T, P...>(p_instance, p_method, p_args, r_error, BuildIndexSequence<sizeof...(P)>{});
}
template <typename T, typename R, typename... P>
void call_with_variant_args_ret(T *p_instance, R (T::*p_method)(P...), const Variant **p_args, int p_argcount, Variant &r_ret, GDExtensionCallError &r_error) {
#ifdef DEBUG_ENABLED
if ((size_t)p_argcount > sizeof...(P)) {
r_error.error = GDEXTENSION_CALL_ERROR_TOO_MANY_ARGUMENTS;
r_error.expected = (int32_t)sizeof...(P);
return;
}
if ((size_t)p_argcount < sizeof...(P)) {
r_error.error = GDEXTENSION_CALL_ERROR_TOO_FEW_ARGUMENTS;
r_error.expected = (int32_t)sizeof...(P);
return;
}
#endif
call_with_variant_args_ret_helper<T, R, P...>(p_instance, p_method, p_args, r_ret, r_error, BuildIndexSequence<sizeof...(P)>{});
}
template <typename T, typename R, typename... P>
void call_with_variant_args_retc(T *p_instance, R (T::*p_method)(P...) const, const Variant **p_args, int p_argcount, Variant &r_ret, GDExtensionCallError &r_error) {
#ifdef DEBUG_ENABLED
if ((size_t)p_argcount > sizeof...(P)) {
r_error.error = GDEXTENSION_CALL_ERROR_TOO_MANY_ARGUMENTS;
r_error.expected = (int32_t)sizeof...(P);
return;
}
if ((size_t)p_argcount < sizeof...(P)) {
r_error.error = GDEXTENSION_CALL_ERROR_TOO_FEW_ARGUMENTS;
r_error.expected = (int32_t)sizeof...(P);
return;
}
#endif
call_with_variant_args_retc_helper<T, R, P...>(p_instance, p_method, p_args, r_ret, r_error, BuildIndexSequence<sizeof...(P)>{});
}
template <typename T, typename... P>
template <class T, class... P>
void call_with_variant_args_dv(T *p_instance, void (T::*p_method)(P...), const GDExtensionConstVariantPtr *p_args, int p_argcount, GDExtensionCallError &r_error, const std::vector<Variant> &default_values) {
#ifdef DEBUG_ENABLED
if ((size_t)p_argcount > sizeof...(P)) {
r_error.error = GDEXTENSION_CALL_ERROR_TOO_MANY_ARGUMENTS;
r_error.expected = (int32_t)sizeof...(P);
r_error.argument = (int32_t)sizeof...(P);
return;
}
#endif
@@ -346,7 +292,7 @@ void call_with_variant_args_dv(T *p_instance, void (T::*p_method)(P...), const G
#ifdef DEBUG_ENABLED
if (missing > dvs) {
r_error.error = GDEXTENSION_CALL_ERROR_TOO_FEW_ARGUMENTS;
r_error.expected = (int32_t)sizeof...(P);
r_error.argument = (int32_t)sizeof...(P);
return;
}
#endif
@@ -365,12 +311,12 @@ void call_with_variant_args_dv(T *p_instance, void (T::*p_method)(P...), const G
call_with_variant_args_helper(p_instance, p_method, argsp.data(), r_error, BuildIndexSequence<sizeof...(P)>{});
}
template <typename T, typename... P>
template <class T, class... P>
void call_with_variant_argsc_dv(T *p_instance, void (T::*p_method)(P...) const, const GDExtensionConstVariantPtr *p_args, int p_argcount, GDExtensionCallError &r_error, const std::vector<Variant> &default_values) {
#ifdef DEBUG_ENABLED
if ((size_t)p_argcount > sizeof...(P)) {
r_error.error = GDEXTENSION_CALL_ERROR_TOO_MANY_ARGUMENTS;
r_error.expected = (int32_t)sizeof...(P);
r_error.argument = (int32_t)sizeof...(P);
return;
}
#endif
@@ -381,7 +327,7 @@ void call_with_variant_argsc_dv(T *p_instance, void (T::*p_method)(P...) const,
#ifdef DEBUG_ENABLED
if (missing > dvs) {
r_error.error = GDEXTENSION_CALL_ERROR_TOO_FEW_ARGUMENTS;
r_error.expected = (int32_t)sizeof...(P);
r_error.argument = (int32_t)sizeof...(P);
return;
}
#endif
@@ -400,12 +346,12 @@ void call_with_variant_argsc_dv(T *p_instance, void (T::*p_method)(P...) const,
call_with_variant_argsc_helper(p_instance, p_method, argsp.data(), r_error, BuildIndexSequence<sizeof...(P)>{});
}
template <typename T, typename R, typename... P>
template <class T, class R, class... P>
void call_with_variant_args_ret_dv(T *p_instance, R (T::*p_method)(P...), const GDExtensionConstVariantPtr *p_args, int p_argcount, Variant &r_ret, GDExtensionCallError &r_error, const std::vector<Variant> &default_values) {
#ifdef DEBUG_ENABLED
if ((size_t)p_argcount > sizeof...(P)) {
r_error.error = GDEXTENSION_CALL_ERROR_TOO_MANY_ARGUMENTS;
r_error.expected = (int32_t)sizeof...(P);
r_error.argument = (int32_t)sizeof...(P);
return;
}
#endif
@@ -416,7 +362,7 @@ void call_with_variant_args_ret_dv(T *p_instance, R (T::*p_method)(P...), const
#ifdef DEBUG_ENABLED
if (missing > dvs) {
r_error.error = GDEXTENSION_CALL_ERROR_TOO_FEW_ARGUMENTS;
r_error.expected = (int32_t)sizeof...(P);
r_error.argument = (int32_t)sizeof...(P);
return;
}
#endif
@@ -435,12 +381,12 @@ void call_with_variant_args_ret_dv(T *p_instance, R (T::*p_method)(P...), const
call_with_variant_args_ret_helper(p_instance, p_method, argsp.data(), r_ret, r_error, BuildIndexSequence<sizeof...(P)>{});
}
template <typename T, typename R, typename... P>
template <class T, class R, class... P>
void call_with_variant_args_retc_dv(T *p_instance, R (T::*p_method)(P...) const, const GDExtensionConstVariantPtr *p_args, int p_argcount, Variant &r_ret, GDExtensionCallError &r_error, const std::vector<Variant> &default_values) {
#ifdef DEBUG_ENABLED
if ((size_t)p_argcount > sizeof...(P)) {
r_error.error = GDEXTENSION_CALL_ERROR_TOO_MANY_ARGUMENTS;
r_error.expected = (int32_t)sizeof...(P);
r_error.argument = (int32_t)sizeof...(P);
return;
}
#endif
@@ -451,7 +397,7 @@ void call_with_variant_args_retc_dv(T *p_instance, R (T::*p_method)(P...) const,
#ifdef DEBUG_ENABLED
if (missing > dvs) {
r_error.error = GDEXTENSION_CALL_ERROR_TOO_FEW_ARGUMENTS;
r_error.expected = (int32_t)sizeof...(P);
r_error.argument = (int32_t)sizeof...(P);
return;
}
#endif
@@ -477,7 +423,7 @@ void call_with_variant_args_retc_dv(T *p_instance, R (T::*p_method)(P...) const,
#pragma GCC diagnostic ignored "-Wunused-but-set-parameter"
#endif
template <typename Q>
template <class Q>
void call_get_argument_type_helper(int p_arg, int &index, GDExtensionVariantType &type) {
if (p_arg == index) {
type = GDExtensionVariantType(GetTypeInfo<Q>::VARIANT_TYPE);
@@ -485,7 +431,7 @@ void call_get_argument_type_helper(int p_arg, int &index, GDExtensionVariantType
index++;
}
template <typename... P>
template <class... P>
GDExtensionVariantType call_get_argument_type(int p_arg) {
GDExtensionVariantType type = GDEXTENSION_VARIANT_TYPE_NIL;
int index = 0;
@@ -497,7 +443,7 @@ GDExtensionVariantType call_get_argument_type(int p_arg) {
return type;
}
template <typename Q>
template <class Q>
void call_get_argument_type_info_helper(int p_arg, int &index, PropertyInfo &info) {
if (p_arg == index) {
info = GetTypeInfo<Q>::get_class_info();
@@ -505,7 +451,7 @@ void call_get_argument_type_info_helper(int p_arg, int &index, PropertyInfo &inf
index++;
}
template <typename... P>
template <class... P>
void call_get_argument_type_info(int p_arg, PropertyInfo &info) {
int index = 0;
// I think rocket science is simpler than modern C++.
@@ -515,7 +461,7 @@ void call_get_argument_type_info(int p_arg, PropertyInfo &info) {
(void)index; // Suppress GCC warning.
}
template <typename Q>
template <class Q>
void call_get_argument_metadata_helper(int p_arg, int &index, GDExtensionClassMethodArgumentMetadata &md) {
if (p_arg == index) {
md = GetTypeInfo<Q>::METADATA;
@@ -523,7 +469,7 @@ void call_get_argument_metadata_helper(int p_arg, int &index, GDExtensionClassMe
index++;
}
template <typename... P>
template <class... P>
GDExtensionClassMethodArgumentMetadata call_get_argument_metadata(int p_arg) {
GDExtensionClassMethodArgumentMetadata md = GDEXTENSION_METHOD_ARGUMENT_METADATA_NONE;
@@ -536,7 +482,7 @@ GDExtensionClassMethodArgumentMetadata call_get_argument_metadata(int p_arg) {
return md;
}
template <typename... P, size_t... Is>
template <class... P, size_t... Is>
void call_with_variant_args_static(void (*p_method)(P...), const Variant **p_args, GDExtensionCallError &r_error, IndexSequence<Is...>) {
r_error.error = GDEXTENSION_CALL_OK;
@@ -547,12 +493,12 @@ void call_with_variant_args_static(void (*p_method)(P...), const Variant **p_arg
#endif
}
template <typename... P>
template <class... P>
void call_with_variant_args_static_dv(void (*p_method)(P...), const GDExtensionConstVariantPtr *p_args, int p_argcount, GDExtensionCallError &r_error, const std::vector<Variant> &default_values) {
#ifdef DEBUG_ENABLED
if ((size_t)p_argcount > sizeof...(P)) {
r_error.error = GDEXTENSION_CALL_ERROR_TOO_MANY_ARGUMENTS;
r_error.expected = sizeof...(P);
r_error.argument = sizeof...(P);
return;
}
#endif
@@ -563,7 +509,7 @@ void call_with_variant_args_static_dv(void (*p_method)(P...), const GDExtensionC
#ifdef DEBUG_ENABLED
if (missing > dvs) {
r_error.error = GDEXTENSION_CALL_ERROR_TOO_FEW_ARGUMENTS;
r_error.expected = sizeof...(P);
r_error.argument = sizeof...(P);
return;
}
#endif
@@ -582,53 +528,17 @@ void call_with_variant_args_static_dv(void (*p_method)(P...), const GDExtensionC
call_with_variant_args_static(p_method, argsp.data(), r_error, BuildIndexSequence<sizeof...(P)>{});
}
template <typename... P, size_t... Is>
template <class... P, size_t... Is>
void call_with_ptr_args_static_method_helper(void (*p_method)(P...), const GDExtensionConstTypePtr *p_args, IndexSequence<Is...>) {
p_method(PtrToArg<P>::convert(p_args[Is])...);
}
template <typename... P>
template <class... P>
void call_with_ptr_args_static_method(void (*p_method)(P...), const GDExtensionConstTypePtr *p_args) {
call_with_ptr_args_static_method_helper<P...>(p_method, p_args, BuildIndexSequence<sizeof...(P)>{});
}
template <typename R, typename... P>
void call_with_variant_args_static_ret(R (*p_method)(P...), const Variant **p_args, int p_argcount, Variant &r_ret, GDExtensionCallError &r_error) {
#ifdef DEBUG_ENABLED
if ((size_t)p_argcount > sizeof...(P)) {
r_error.error = GDEXTENSION_CALL_ERROR_TOO_MANY_ARGUMENTS;
r_error.expected = (int32_t)sizeof...(P);
return;
}
if ((size_t)p_argcount < sizeof...(P)) {
r_error.error = GDEXTENSION_CALL_ERROR_TOO_FEW_ARGUMENTS;
r_error.expected = (int32_t)sizeof...(P);
return;
}
#endif
call_with_variant_args_static_ret<R, P...>(p_method, p_args, r_ret, r_error, BuildIndexSequence<sizeof...(P)>{});
}
template <typename... P>
void call_with_variant_args_static_ret(void (*p_method)(P...), const Variant **p_args, int p_argcount, Variant &r_ret, GDExtensionCallError &r_error) {
#ifdef DEBUG_ENABLED
if ((size_t)p_argcount > sizeof...(P)) {
r_error.error = GDEXTENSION_CALL_ERROR_TOO_MANY_ARGUMENTS;
r_error.expected = (int32_t)sizeof...(P);
return;
}
if ((size_t)p_argcount < sizeof...(P)) {
r_error.error = GDEXTENSION_CALL_ERROR_TOO_FEW_ARGUMENTS;
r_error.expected = (int32_t)sizeof...(P);
return;
}
#endif
call_with_variant_args_static<P...>(p_method, p_args, r_error, BuildIndexSequence<sizeof...(P)>{});
}
template <typename R, typename... P, size_t... Is>
template <class R, class... P, size_t... Is>
void call_with_variant_args_static_ret(R (*p_method)(P...), const Variant **p_args, Variant &r_ret, GDExtensionCallError &r_error, IndexSequence<Is...>) {
r_error.error = GDEXTENSION_CALL_OK;
@@ -639,12 +549,12 @@ void call_with_variant_args_static_ret(R (*p_method)(P...), const Variant **p_ar
#endif
}
template <typename R, typename... P>
template <class R, class... P>
void call_with_variant_args_static_ret_dv(R (*p_method)(P...), const GDExtensionConstVariantPtr *p_args, int p_argcount, Variant &r_ret, GDExtensionCallError &r_error, const std::vector<Variant> &default_values) {
#ifdef DEBUG_ENABLED
if ((size_t)p_argcount > sizeof...(P)) {
r_error.error = GDEXTENSION_CALL_ERROR_TOO_MANY_ARGUMENTS;
r_error.expected = sizeof...(P);
r_error.argument = sizeof...(P);
return;
}
#endif
@@ -655,7 +565,7 @@ void call_with_variant_args_static_ret_dv(R (*p_method)(P...), const GDExtension
#ifdef DEBUG_ENABLED
if (missing > dvs) {
r_error.error = GDEXTENSION_CALL_ERROR_TOO_FEW_ARGUMENTS;
r_error.expected = sizeof...(P);
r_error.argument = sizeof...(P);
return;
}
#endif
@@ -674,12 +584,12 @@ void call_with_variant_args_static_ret_dv(R (*p_method)(P...), const GDExtension
call_with_variant_args_static_ret(p_method, argsp.data(), r_ret, r_error, BuildIndexSequence<sizeof...(P)>{});
}
template <typename R, typename... P, size_t... Is>
template <class R, class... P, size_t... Is>
void call_with_ptr_args_static_method_ret_helper(R (*p_method)(P...), const GDExtensionConstTypePtr *p_args, void *r_ret, IndexSequence<Is...>) {
PtrToArg<R>::encode(p_method(PtrToArg<P>::convert(p_args[Is])...), r_ret);
}
template <typename R, typename... P>
template <class R, class... P>
void call_with_ptr_args_static_method_ret(R (*p_method)(P...), const GDExtensionConstTypePtr *p_args, void *r_ret) {
call_with_ptr_args_static_method_ret_helper<R, P...>(p_method, p_args, r_ret, BuildIndexSequence<sizeof...(P)>{});
}

View File

@@ -32,7 +32,6 @@
#define GODOT_BUILTIN_PTRCALL_HPP
#include <gdextension_interface.h>
#include <godot_cpp/core/object.hpp>
#include <array>
@@ -40,24 +39,13 @@ namespace godot {
namespace internal {
template <typename O, typename... Args>
O *_call_builtin_method_ptr_ret_obj(const GDExtensionPtrBuiltInMethod method, GDExtensionTypePtr base, const Args &...args) {
GodotObject *ret = nullptr;
std::array<GDExtensionConstTypePtr, sizeof...(Args)> call_args = { { (GDExtensionConstTypePtr)args... } };
method(base, call_args.data(), &ret, sizeof...(Args));
if (ret == nullptr) {
return nullptr;
}
return reinterpret_cast<O *>(internal::get_object_instance_binding(ret));
}
template <typename... Args>
template <class... Args>
void _call_builtin_constructor(const GDExtensionPtrConstructor constructor, GDExtensionTypePtr base, Args... args) {
std::array<GDExtensionConstTypePtr, sizeof...(Args)> call_args = { { (GDExtensionConstTypePtr)args... } };
constructor(base, call_args.data());
}
template <typename T, typename... Args>
template <class T, class... Args>
T _call_builtin_method_ptr_ret(const GDExtensionPtrBuiltInMethod method, GDExtensionTypePtr base, Args... args) {
T ret;
std::array<GDExtensionConstTypePtr, sizeof...(Args)> call_args = { { (GDExtensionConstTypePtr)args... } };
@@ -65,20 +53,20 @@ T _call_builtin_method_ptr_ret(const GDExtensionPtrBuiltInMethod method, GDExten
return ret;
}
template <typename... Args>
template <class... Args>
void _call_builtin_method_ptr_no_ret(const GDExtensionPtrBuiltInMethod method, GDExtensionTypePtr base, Args... args) {
std::array<GDExtensionConstTypePtr, sizeof...(Args)> call_args = { { (GDExtensionConstTypePtr)args... } };
method(base, call_args.data(), nullptr, sizeof...(Args));
}
template <typename T>
template <class T>
T _call_builtin_operator_ptr(const GDExtensionPtrOperatorEvaluator op, GDExtensionConstTypePtr left, GDExtensionConstTypePtr right) {
T ret;
op(left, right, &ret);
return ret;
}
template <typename T>
template <class T>
T _call_builtin_ptr_getter(const GDExtensionPtrGetter getter, GDExtensionConstTypePtr base) {
T ret;
getter(base, &ret);

View File

@@ -37,16 +37,8 @@
#include <godot_cpp/core/error_macros.hpp>
#include <godot_cpp/core/method_bind.hpp>
#include <godot_cpp/core/object.hpp>
#include <godot_cpp/core/print_string.hpp>
#include <godot_cpp/classes/class_db_singleton.hpp>
// Makes callable_mp readily available in all classes connecting signals.
// Needs to come after method_bind and object have been included.
#include <godot_cpp/variant/callable_method_pointer.hpp>
#include <list>
#include <mutex>
#include <set>
#include <string>
#include <unordered_map>
@@ -87,18 +79,22 @@ class ClassDB {
friend class godot::GDExtensionBinding;
public:
struct ClassInfo {
struct VirtualMethod {
GDExtensionClassCallVirtual func;
uint32_t hash;
};
struct PropertySetGet {
int index;
StringName setter;
StringName getter;
MethodBind *_setptr;
MethodBind *_getptr;
Variant::Type type;
};
struct ClassInfo {
StringName name;
StringName parent_name;
GDExtensionInitializationLevel level = GDEXTENSION_INITIALIZATION_SCENE;
std::unordered_map<StringName, MethodBind *> method_map;
std::set<StringName> signal_names;
std::unordered_map<StringName, VirtualMethod> virtual_methods;
std::unordered_map<StringName, GDExtensionClassCallVirtual> virtual_methods;
std::set<StringName> property_names;
std::set<StringName> constant_names;
// Pointer to the parent custom class, if any. Will be null if the parent class is a Godot class.
@@ -108,88 +104,27 @@ public:
private:
// This may only contain custom classes, not Godot classes
static std::unordered_map<StringName, ClassInfo> classes;
static std::unordered_map<StringName, const GDExtensionInstanceBindingCallbacks *> instance_binding_callbacks;
// Used to remember the custom class registration order.
static std::vector<StringName> class_register_order;
static std::unordered_map<StringName, Object *> engine_singletons;
static std::mutex engine_singletons_mutex;
static MethodBind *bind_methodfi(uint32_t p_flags, MethodBind *p_bind, const MethodDefinition &method_name, const void **p_defs, int p_defcount);
static void initialize_class(const ClassInfo &cl);
static void bind_method_godot(const StringName &p_class_name, MethodBind *p_method);
template <typename T, bool is_abstract>
static void _register_class(bool p_virtual = false, bool p_exposed = true, bool p_runtime = false);
template <typename T>
static GDExtensionObjectPtr _create_instance_func(void *data, GDExtensionBool p_notify_postinitialize) {
if constexpr (!std::is_abstract_v<T>) {
Wrapped::_set_construct_info<T>();
T *new_object = new ("", "") T;
if (p_notify_postinitialize) {
new_object->_postinitialize();
}
return new_object->_owner;
} else {
return nullptr;
}
}
template <typename T>
static GDExtensionClassInstancePtr _recreate_instance_func(void *data, GDExtensionObjectPtr obj) {
if constexpr (!std::is_abstract_v<T>) {
#ifdef HOT_RELOAD_ENABLED
#ifdef _GODOT_CPP_AVOID_THREAD_LOCAL
std::lock_guard<std::recursive_mutex> lk(Wrapped::_constructing_mutex);
#endif
Wrapped::_constructing_recreate_owner = obj;
T *new_instance = (T *)memalloc(sizeof(T));
memnew_placement(new_instance, T);
return new_instance;
#else
return nullptr;
#endif
} else {
return nullptr;
}
}
template <class T, bool is_abstract>
static void _register_class(bool p_virtual = false);
public:
template <typename T>
template <class T>
static void register_class(bool p_virtual = false);
template <typename T>
template <class T>
static void register_abstract_class();
template <typename T>
static void register_internal_class();
template <typename T>
static void register_runtime_class();
_FORCE_INLINE_ static void _register_engine_class(const StringName &p_name, const GDExtensionInstanceBindingCallbacks *p_callbacks) {
instance_binding_callbacks[p_name] = p_callbacks;
}
static void _register_engine_singleton(const StringName &p_class_name, Object *p_singleton) {
std::lock_guard<std::mutex> lock(engine_singletons_mutex);
std::unordered_map<StringName, Object *>::const_iterator i = engine_singletons.find(p_class_name);
if (i != engine_singletons.end()) {
ERR_FAIL_COND((*i).second != p_singleton);
return;
}
engine_singletons[p_class_name] = p_singleton;
}
static void _unregister_engine_singleton(const StringName &p_class_name) {
std::lock_guard<std::mutex> lock(engine_singletons_mutex);
engine_singletons.erase(p_class_name);
}
template <typename N, typename M, typename... VarArgs>
template <class N, class M, typename... VarArgs>
static MethodBind *bind_method(N p_method_name, M p_method, VarArgs... p_args);
template <typename N, typename M, typename... VarArgs>
template <class N, class M, typename... VarArgs>
static MethodBind *bind_static_method(StringName p_class, N p_method_name, M p_method, VarArgs... p_args);
template <typename M>
template <class M>
static MethodBind *bind_vararg_method(uint32_t p_flags, StringName p_name, M p_method, const MethodInfo &p_info = MethodInfo(), const std::vector<Variant> &p_default_args = std::vector<Variant>{}, bool p_return_nil_is_variant = true);
static void add_property_group(const StringName &p_class, const String &p_name, const String &p_prefix);
@@ -197,46 +132,35 @@ public:
static void add_property(const StringName &p_class, const PropertyInfo &p_pinfo, const StringName &p_setter, const StringName &p_getter, int p_index = -1);
static void add_signal(const StringName &p_class, const MethodInfo &p_signal);
static void bind_integer_constant(const StringName &p_class_name, const StringName &p_enum_name, const StringName &p_constant_name, GDExtensionInt p_constant_value, bool p_is_bitfield = false);
// Binds an implementation of a virtual method defined in Godot.
static void bind_virtual_method(const StringName &p_class, const StringName &p_method, GDExtensionClassCallVirtual p_call, uint32_t p_hash);
// Add a new virtual method that can be implemented by scripts.
static void add_virtual_method(const StringName &p_class, const MethodInfo &p_method, const Vector<StringName> &p_arg_names = Vector<StringName>());
static void bind_virtual_method(const StringName &p_class, const StringName &p_method, GDExtensionClassCallVirtual p_call);
static MethodBind *get_method(const StringName &p_class, const StringName &p_method);
static GDExtensionClassCallVirtual get_virtual_func(void *p_userdata, GDExtensionConstStringNamePtr p_name, uint32_t p_hash);
static const GDExtensionInstanceBindingCallbacks *get_instance_binding_callbacks(const StringName &p_class);
static GDExtensionClassCallVirtual get_virtual_func(void *p_userdata, GDExtensionConstStringNamePtr p_name);
static void initialize(GDExtensionInitializationLevel p_level);
static void deinitialize(GDExtensionInitializationLevel p_level);
CLASSDB_SINGLETON_FORWARD_METHODS;
};
#define BIND_CONSTANT(m_constant) \
::godot::ClassDB::bind_integer_constant(get_class_static(), "", #m_constant, m_constant);
godot::ClassDB::bind_integer_constant(get_class_static(), "", #m_constant, m_constant);
#define BIND_ENUM_CONSTANT(m_constant) \
::godot::ClassDB::bind_integer_constant(get_class_static(), ::godot::_gde_constant_get_enum_name(m_constant, #m_constant), #m_constant, m_constant);
godot::ClassDB::bind_integer_constant(get_class_static(), godot::__constant_get_enum_name(m_constant, #m_constant), #m_constant, m_constant);
#define BIND_BITFIELD_FLAG(m_constant) \
::godot::ClassDB::bind_integer_constant(get_class_static(), ::godot::_gde_constant_get_bitfield_name(m_constant, #m_constant), #m_constant, m_constant, true);
godot::ClassDB::bind_integer_constant(get_class_static(), godot::__constant_get_bitfield_name(m_constant, #m_constant), #m_constant, m_constant, true);
#define BIND_VIRTUAL_METHOD(m_class, m_method, m_hash) \
{ \
auto _call##m_method = [](GDExtensionObjectPtr p_instance, const GDExtensionConstTypePtr *p_args, GDExtensionTypePtr p_ret) -> void { \
call_with_ptr_args(reinterpret_cast<m_class *>(p_instance), &m_class::m_method, p_args, p_ret); \
}; \
::godot::ClassDB::bind_virtual_method(m_class::get_class_static(), #m_method, _call##m_method, m_hash); \
#define BIND_VIRTUAL_METHOD(m_class, m_method) \
{ \
auto ___call##m_method = [](GDExtensionObjectPtr p_instance, const GDExtensionConstTypePtr *p_args, GDExtensionTypePtr p_ret) -> void { \
call_with_ptr_args(reinterpret_cast<m_class *>(p_instance), &m_class::m_method, p_args, p_ret); \
}; \
godot::ClassDB::bind_virtual_method(m_class::get_class_static(), #m_method, ___call##m_method); \
}
template <typename T, bool is_abstract>
void ClassDB::_register_class(bool p_virtual, bool p_exposed, bool p_runtime) {
static_assert(TypesAreSame<typename T::self_type, T>::value, "Class not declared properly, please use GDCLASS.");
static_assert(!FunctionsAreSame<T::self_type::_bind_methods, T::parent_type::_bind_methods>::value, "Class must declare 'static void _bind_methods'.");
static_assert(!std::is_abstract_v<T> || is_abstract, "Class is abstract, please use GDREGISTER_ABSTRACT_CLASS.");
instance_binding_callbacks[T::get_class_static()] = &T::_gde_binding_callbacks;
template <class T, bool is_abstract>
void ClassDB::_register_class(bool p_virtual) {
// Register this class within our plugin
ClassInfo cl;
cl.name = T::get_class_static();
@@ -248,36 +172,29 @@ void ClassDB::_register_class(bool p_virtual, bool p_exposed, bool p_runtime) {
cl.parent_ptr = &parent_it->second;
}
classes[cl.name] = cl;
class_register_order.push_back(cl.name);
// Register this class with Godot
GDExtensionClassCreationInfo4 class_info = {
GDExtensionClassCreationInfo class_info = {
p_virtual, // GDExtensionBool is_virtual;
is_abstract, // GDExtensionBool is_abstract;
p_exposed, // GDExtensionBool is_exposed;
p_runtime, // GDExtensionBool is_runtime;
nullptr, // GDExtensionConstStringPtr icon_path;
T::set_bind, // GDExtensionClassSet set_func;
T::get_bind, // GDExtensionClassGet get_func;
T::has_get_property_list() ? T::get_property_list_bind : nullptr, // GDExtensionClassGetPropertyList get_property_list_func;
T::free_property_list_bind, // GDExtensionClassFreePropertyList2 free_property_list_func;
T::get_property_list_bind, // GDExtensionClassGetPropertyList get_property_list_func;
T::free_property_list_bind, // GDExtensionClassFreePropertyList free_property_list_func;
T::property_can_revert_bind, // GDExtensionClassPropertyCanRevert property_can_revert_func;
T::property_get_revert_bind, // GDExtensionClassPropertyGetRevert property_get_revert_func;
T::validate_property_bind, // GDExtensionClassValidateProperty validate_property_func;
T::notification_bind, // GDExtensionClassNotification2 notification_func;
T::notification_bind, // GDExtensionClassNotification notification_func;
T::to_string_bind, // GDExtensionClassToString to_string_func;
nullptr, // GDExtensionClassReference reference_func;
nullptr, // GDExtensionClassUnreference unreference_func;
&_create_instance_func<T>, // GDExtensionClassCreateInstance create_instance_func; /* this one is mandatory */
T::create, // GDExtensionClassCreateInstance create_instance_func; /* this one is mandatory */
T::free, // GDExtensionClassFreeInstance free_instance_func; /* this one is mandatory */
&_recreate_instance_func<T>, // GDExtensionClassRecreateInstance recreate_instance_func;
&ClassDB::get_virtual_func, // GDExtensionClassGetVirtual get_virtual_func;
nullptr, // GDExtensionClassGetVirtualCallData get_virtual_call_data_func;
nullptr, // GDExtensionClassCallVirtualWithData call_virtual_func;
nullptr, // GDExtensionClassGetRID get_rid;
(void *)&T::get_class_static(), // void *class_userdata;
};
internal::gdextension_interface_classdb_register_extension_class4(internal::library, cl.name._native_ptr(), cl.parent_name._native_ptr(), &class_info);
internal::gde_interface->classdb_register_extension_class(internal::library, cl.name._native_ptr(), cl.parent_name._native_ptr(), &class_info);
// call bind_methods etc. to register all members of the class
T::initialize_class();
@@ -286,27 +203,17 @@ void ClassDB::_register_class(bool p_virtual, bool p_exposed, bool p_runtime) {
initialize_class(classes[cl.name]);
}
template <typename T>
template <class T>
void ClassDB::register_class(bool p_virtual) {
ClassDB::_register_class<T, false>(p_virtual);
}
template <typename T>
template <class T>
void ClassDB::register_abstract_class() {
ClassDB::_register_class<T, true>();
}
template <typename T>
void ClassDB::register_internal_class() {
ClassDB::_register_class<T, false>(false, false);
}
template <typename T>
void ClassDB::register_runtime_class() {
ClassDB::_register_class<T, false>(false, true, true);
}
template <typename N, typename M, typename... VarArgs>
template <class N, class M, typename... VarArgs>
MethodBind *ClassDB::bind_method(N p_method_name, M p_method, VarArgs... p_args) {
Variant args[sizeof...(p_args) + 1] = { p_args..., Variant() }; // +1 makes sure zero sized arrays are also supported.
const Variant *argptrs[sizeof...(p_args) + 1];
@@ -317,7 +224,7 @@ MethodBind *ClassDB::bind_method(N p_method_name, M p_method, VarArgs... p_args)
return bind_methodfi(METHOD_FLAGS_DEFAULT, bind, p_method_name, sizeof...(p_args) == 0 ? nullptr : (const void **)argptrs, sizeof...(p_args));
}
template <typename N, typename M, typename... VarArgs>
template <class N, class M, typename... VarArgs>
MethodBind *ClassDB::bind_static_method(StringName p_class, N p_method_name, M p_method, VarArgs... p_args) {
Variant args[sizeof...(p_args) + 1] = { p_args..., Variant() }; // +1 makes sure zero sized arrays are also supported.
const Variant *argptrs[sizeof...(p_args) + 1];
@@ -329,10 +236,10 @@ MethodBind *ClassDB::bind_static_method(StringName p_class, N p_method_name, M p
return bind_methodfi(0, bind, p_method_name, sizeof...(p_args) == 0 ? nullptr : (const void **)argptrs, sizeof...(p_args));
}
template <typename M>
template <class M>
MethodBind *ClassDB::bind_vararg_method(uint32_t p_flags, StringName p_name, M p_method, const MethodInfo &p_info, const std::vector<Variant> &p_default_args, bool p_return_nil_is_variant) {
MethodBind *bind = create_vararg_method_bind(p_method, p_info, p_return_nil_is_variant);
ERR_FAIL_NULL_V(bind, nullptr);
ERR_FAIL_COND_V(!bind, nullptr);
bind->set_name(p_name);
bind->set_default_arguments(p_default_args);
@@ -361,14 +268,10 @@ MethodBind *ClassDB::bind_vararg_method(uint32_t p_flags, StringName p_name, M p
return bind;
}
#define GDREGISTER_CLASS(m_class) ::godot::ClassDB::register_class<m_class>();
#define GDREGISTER_VIRTUAL_CLASS(m_class) ::godot::ClassDB::register_class<m_class>(true);
#define GDREGISTER_ABSTRACT_CLASS(m_class) ::godot::ClassDB::register_abstract_class<m_class>();
#define GDREGISTER_INTERNAL_CLASS(m_class) ::godot::ClassDB::register_internal_class<m_class>();
#define GDREGISTER_RUNTIME_CLASS(m_class) ::godot::ClassDB::register_runtime_class<m_class>();
#define GDREGISTER_CLASS(m_class) ClassDB::register_class<m_class>();
#define GDREGISTER_VIRTUAL_CLASS(m_class) ClassDB::register_class<m_class>(true);
#define GDREGISTER_ABSTRACT_CLASS(m_class) ClassDB::register_abstract_class<m_class>();
} // namespace godot
CLASSDB_SINGLETON_VARIANT_CAST;
#endif // GODOT_CLASS_DB_HPP

View File

@@ -35,8 +35,6 @@
#include <cstdint>
#include <cstring>
namespace godot {
#if !defined(GDE_EXPORT)
#if defined(_WIN32)
#define GDE_EXPORT __declspec(dllexport)
@@ -74,6 +72,10 @@ namespace godot {
#endif
#endif
#ifndef _NO_DISCARD_
#define _NO_DISCARD_ [[nodiscard]]
#endif
// Windows badly defines a lot of stuff we'll never use. Undefine it.
#ifdef _WIN32
#undef min // override standard definition
@@ -106,7 +108,7 @@ typedef float real_t;
// Generic swap template.
#ifndef SWAP
#define SWAP(m_x, m_y) __swap_tmpl((m_x), (m_y))
template <typename T>
template <class T>
inline void __swap_tmpl(T &x, T &y) {
T aux = x;
x = y;
@@ -125,10 +127,4 @@ struct BuildIndexSequence : BuildIndexSequence<N - 1, N - 1, Is...> {};
template <size_t... Is>
struct BuildIndexSequence<0, Is...> : IndexSequence<Is...> {};
} //namespace godot
// To maintain compatibility an alias is defined outside the namespace.
// Consider it deprecated.
using real_t = godot::real_t;
#endif // GODOT_DEFS_HPP

View File

@@ -43,32 +43,32 @@ namespace godot {
namespace internal {
template <typename O, typename... Args>
template <class O, class... Args>
O *_call_native_mb_ret_obj(const GDExtensionMethodBindPtr mb, void *instance, const Args &...args) {
GodotObject *ret = nullptr;
std::array<GDExtensionConstTypePtr, sizeof...(Args)> mb_args = { { (GDExtensionConstTypePtr)args... } };
internal::gdextension_interface_object_method_bind_ptrcall(mb, instance, mb_args.data(), &ret);
internal::gde_interface->object_method_bind_ptrcall(mb, instance, mb_args.data(), &ret);
if (ret == nullptr) {
return nullptr;
}
return reinterpret_cast<O *>(internal::get_object_instance_binding(ret));
return reinterpret_cast<O *>(internal::gde_interface->object_get_instance_binding(ret, internal::token, &O::___binding_callbacks));
}
template <typename R, typename... Args>
template <class R, class... Args>
R _call_native_mb_ret(const GDExtensionMethodBindPtr mb, void *instance, const Args &...args) {
R ret;
std::array<GDExtensionConstTypePtr, sizeof...(Args)> mb_args = { { (GDExtensionConstTypePtr)args... } };
internal::gdextension_interface_object_method_bind_ptrcall(mb, instance, mb_args.data(), &ret);
internal::gde_interface->object_method_bind_ptrcall(mb, instance, mb_args.data(), &ret);
return ret;
}
template <typename... Args>
template <class... Args>
void _call_native_mb_no_ret(const GDExtensionMethodBindPtr mb, void *instance, const Args &...args) {
std::array<GDExtensionConstTypePtr, sizeof...(Args)> mb_args = { { (GDExtensionConstTypePtr)args... } };
internal::gdextension_interface_object_method_bind_ptrcall(mb, instance, mb_args.data(), nullptr);
internal::gde_interface->object_method_bind_ptrcall(mb, instance, mb_args.data(), nullptr);
}
template <typename R, typename... Args>
template <class R, class... Args>
R _call_utility_ret(GDExtensionPtrUtilityFunction func, const Args &...args) {
R ret;
std::array<GDExtensionConstTypePtr, sizeof...(Args)> mb_args = { { (GDExtensionConstTypePtr)args... } };
@@ -76,15 +76,15 @@ R _call_utility_ret(GDExtensionPtrUtilityFunction func, const Args &...args) {
return ret;
}
template <typename... Args>
Object *_call_utility_ret_obj(const GDExtensionPtrUtilityFunction func, const Args &...args) {
template <class... Args>
Object *_call_utility_ret_obj(const GDExtensionPtrUtilityFunction func, void *instance, const Args &...args) {
GodotObject *ret = nullptr;
std::array<GDExtensionConstTypePtr, sizeof...(Args)> mb_args = { { (GDExtensionConstTypePtr)args... } };
func(&ret, mb_args.data(), mb_args.size());
return (Object *)internal::get_object_instance_binding(ret);
return (Object *)internal::gde_interface->object_get_instance_binding(ret, internal::token, &Object::___binding_callbacks);
}
template <typename... Args>
template <class... Args>
void _call_utility_no_ret(const GDExtensionPtrUtilityFunction func, const Args &...args) {
std::array<GDExtensionConstTypePtr, sizeof...(Args)> mb_args = { { (GDExtensionConstTypePtr)args... } };
func(nullptr, mb_args.data(), mb_args.size());

View File

@@ -84,7 +84,7 @@ constexpr auto CLAMP(const T m_a, const T2 m_min, const T3 m_max) {
// Generic swap template.
#ifndef SWAP
#define SWAP(m_x, m_y) __swap_tmpl((m_x), (m_y))
template <typename T>
template <class T>
inline void __swap_tmpl(T &x, T &y) {
T aux = x;
x = y;
@@ -138,7 +138,7 @@ static inline int get_shift_from_power_of_2(unsigned int p_bits) {
return -1;
}
template <typename T>
template <class T>
static _FORCE_INLINE_ T nearest_power_of_2_templated(T x) {
--x;
@@ -613,14 +613,6 @@ inline bool is_inf(double p_val) {
return std::isinf(p_val);
}
inline bool is_finite(float p_val) {
return std::isfinite(p_val);
}
inline bool is_finite(double p_val) {
return std::isfinite(p_val);
}
inline bool is_equal_approx(float a, float b) {
// Check for exact equality first, required to handle "infinity" values.
if (a == b) {

View File

@@ -40,21 +40,24 @@
#include <type_traits>
// p_dummy argument is added to avoid conflicts with the engine functions when both engine and GDExtension are built as a static library on iOS.
void *operator new(size_t p_size, const char *p_dummy, const char *p_description); ///< operator new that takes a description and uses MemoryStaticPool
void *operator new(size_t p_size, const char *p_dummy, void *(*p_allocfunc)(size_t p_size)); ///< operator new that takes a description and uses MemoryStaticPool
void *operator new(size_t p_size, const char *p_dummy, void *p_pointer, size_t check, const char *p_description); ///< operator new that takes a description and uses a pointer to the preallocated memory
#ifndef PAD_ALIGN
#define PAD_ALIGN 16 //must always be greater than this at much
#endif
_ALWAYS_INLINE_ void *operator new(size_t p_size, const char *p_dummy, void *p_pointer, size_t check, const char *p_description) {
void *operator new(size_t p_size, const char *p_description); ///< operator new that takes a description and uses MemoryStaticPool
void *operator new(size_t p_size, void *(*p_allocfunc)(size_t p_size)); ///< operator new that takes a description and uses MemoryStaticPool
void *operator new(size_t p_size, void *p_pointer, size_t check, const char *p_description); ///< operator new that takes a description and uses a pointer to the preallocated memory
_ALWAYS_INLINE_ void *operator new(size_t p_size, void *p_pointer, size_t check, const char *p_description) {
return p_pointer;
}
#ifdef _MSC_VER
// When compiling with VC++ 2017, the above declarations of placement new generate many irrelevant warnings (C4291).
// The purpose of the following definitions is to muffle these warnings, not to provide a usable implementation of placement delete.
void operator delete(void *p_mem, const char *p_dummy, const char *p_description);
void operator delete(void *p_mem, const char *p_dummy, void *(*p_allocfunc)(size_t p_size));
void operator delete(void *p_mem, const char *p_dummy, void *p_pointer, size_t check, const char *p_description);
void operator delete(void *p_mem, const char *p_description);
void operator delete(void *p_mem, void *(*p_allocfunc)(size_t p_size));
void operator delete(void *p_mem, void *p_pointer, size_t check, const char *p_description);
#endif
namespace godot {
@@ -65,29 +68,14 @@ class Memory {
Memory();
public:
// Alignment: ↓ max_align_t ↓ uint64_t ↓ max_align_t
// ┌─────────────────┬──┬────────────────┬──┬───────────...
// │ uint64_t │░░│ uint64_t │░░│ T[]
// │ alloc size │░░│ element count │░░│ data
// └─────────────────┴──┴────────────────┴──┴───────────...
// Offset: ↑ SIZE_OFFSET ↑ ELEMENT_OFFSET ↑ DATA_OFFSET
// Note: "alloc size" is used and set by the engine and is never accessed or changed for the extension.
static constexpr size_t SIZE_OFFSET = 0;
static constexpr size_t ELEMENT_OFFSET = ((SIZE_OFFSET + sizeof(uint64_t)) % alignof(uint64_t) == 0) ? (SIZE_OFFSET + sizeof(uint64_t)) : ((SIZE_OFFSET + sizeof(uint64_t)) + alignof(uint64_t) - ((SIZE_OFFSET + sizeof(uint64_t)) % alignof(uint64_t)));
static constexpr size_t DATA_OFFSET = ((ELEMENT_OFFSET + sizeof(uint64_t)) % alignof(max_align_t) == 0) ? (ELEMENT_OFFSET + sizeof(uint64_t)) : ((ELEMENT_OFFSET + sizeof(uint64_t)) + alignof(max_align_t) - ((ELEMENT_OFFSET + sizeof(uint64_t)) % alignof(max_align_t)));
static void *alloc_static(size_t p_bytes, bool p_pad_align = false);
static void *realloc_static(void *p_memory, size_t p_bytes, bool p_pad_align = false);
static void free_static(void *p_ptr, bool p_pad_align = false);
};
template <typename T, std::enable_if_t<!std::is_base_of<::godot::Wrapped, T>::value, bool> = true>
_ALWAYS_INLINE_ void _pre_initialize() {}
_ALWAYS_INLINE_ void postinitialize_handler(void *) {}
template <typename T>
template <class T>
_ALWAYS_INLINE_ T *_post_initialize(T *p_obj) {
postinitialize_handler(p_obj);
return p_obj;
@@ -97,34 +85,34 @@ _ALWAYS_INLINE_ T *_post_initialize(T *p_obj) {
#define memrealloc(m_mem, m_size) ::godot::Memory::realloc_static(m_mem, m_size)
#define memfree(m_mem) ::godot::Memory::free_static(m_mem)
#define memnew(m_class) (::godot::_pre_initialize<std::remove_pointer_t<decltype(new ("", "") m_class)>>(), ::godot::_post_initialize(new ("", "") m_class))
#define memnew(m_class) ::godot::_post_initialize(new ("") m_class)
#define memnew_allocator(m_class, m_allocator) (::godot::_pre_initialize<std::remove_pointer_t<decltype(new ("", "") m_class)>>(), ::godot::_post_initialize(new ("", m_allocator::alloc) m_class))
#define memnew_placement(m_placement, m_class) (::godot::_pre_initialize<std::remove_pointer_t<decltype(new ("", "") m_class)>>(), ::godot::_post_initialize(new ("", m_placement, sizeof(m_class), "") m_class))
#define memnew_allocator(m_class, m_allocator) ::godot::_post_initialize(new (m_allocator::alloc) m_class)
#define memnew_placement(m_placement, m_class) ::godot::_post_initialize(new (m_placement, sizeof(m_class), "") m_class)
// Generic comparator used in Map, List, etc.
template <typename T>
template <class T>
struct Comparator {
_ALWAYS_INLINE_ bool operator()(const T &p_a, const T &p_b) const { return (p_a < p_b); }
};
template <typename T>
template <class T>
void memdelete(T *p_class, typename std::enable_if<!std::is_base_of_v<godot::Wrapped, T>>::type * = nullptr) {
if constexpr (!std::is_trivially_destructible_v<T>) {
if (!std::is_trivially_destructible<T>::value) {
p_class->~T();
}
Memory::free_static(p_class);
}
template <typename T, std::enable_if_t<std::is_base_of_v<godot::Wrapped, T>, bool> = true>
template <class T, std::enable_if_t<std::is_base_of_v<godot::Wrapped, T>, bool> = true>
void memdelete(T *p_class) {
godot::internal::gdextension_interface_object_destroy(p_class->_owner);
godot::internal::gde_interface->object_destroy(p_class->_owner);
}
template <typename T, typename A>
template <class T, class A>
void memdelete_allocator(T *p_class) {
if constexpr (!std::is_trivially_destructible_v<T>) {
if (!std::is_trivially_destructible<T>::value) {
p_class->~T();
}
@@ -137,20 +125,16 @@ public:
_ALWAYS_INLINE_ static void free(void *p_ptr) { Memory::free_static(p_ptr); }
};
template <typename T>
template <class T>
class DefaultTypedAllocator {
public:
template <typename... Args>
template <class... Args>
_ALWAYS_INLINE_ T *new_allocation(const Args &&...p_args) { return memnew(T(p_args...)); }
_ALWAYS_INLINE_ void delete_allocation(T *p_allocation) { memdelete(p_allocation); }
};
#define memnew_arr(m_class, m_count) memnew_arr_template<m_class>(m_count)
_FORCE_INLINE_ uint64_t *_get_element_count_ptr(uint8_t *p_ptr) {
return (uint64_t *)(p_ptr - Memory::DATA_OFFSET + Memory::ELEMENT_OFFSET);
}
template <typename T>
T *memnew_arr_template(size_t p_elements, const char *p_descr = "") {
if (p_elements == 0) {
@@ -160,39 +144,29 @@ T *memnew_arr_template(size_t p_elements, const char *p_descr = "") {
same strategy used by std::vector, and the Vector class, so it should be safe.*/
size_t len = sizeof(T) * p_elements;
uint8_t *mem = (uint8_t *)Memory::alloc_static(len, true);
uint64_t *mem = (uint64_t *)Memory::alloc_static(len, true);
T *failptr = nullptr; // Get rid of a warning.
ERR_FAIL_NULL_V(mem, failptr);
ERR_FAIL_COND_V(!mem, failptr);
*(mem - 1) = p_elements;
uint64_t *_elem_count_ptr = _get_element_count_ptr(mem);
*(_elem_count_ptr) = p_elements;
if constexpr (!std::is_trivially_destructible_v<T>) {
if (!std::is_trivially_destructible<T>::value) {
T *elems = (T *)mem;
/* call operator new */
for (size_t i = 0; i < p_elements; i++) {
new ("", &elems[i], sizeof(T), p_descr) T;
new (&elems[i], sizeof(T), p_descr) T;
}
}
return (T *)mem;
}
template <typename T>
size_t memarr_len(const T *p_class) {
uint8_t *ptr = (uint8_t *)p_class;
uint64_t *_elem_count_ptr = _get_element_count_ptr(ptr);
return *(_elem_count_ptr);
}
template <typename T>
void memdelete_arr(T *p_class) {
uint8_t *ptr = (uint8_t *)p_class;
uint64_t *ptr = (uint64_t *)p_class;
if constexpr (!std::is_trivially_destructible_v<T>) {
uint64_t *_elem_count_ptr = _get_element_count_ptr(ptr);
uint64_t elem_count = *(_elem_count_ptr);
if (!std::is_trivially_destructible<T>::value) {
uint64_t elem_count = *(ptr - 1);
for (uint64_t i = 0; i < elem_count; i++) {
p_class[i].~T();

View File

@@ -132,7 +132,7 @@ public:
std::vector<GDExtensionClassMethodArgumentMetadata> vec;
// First element is return value
vec.reserve(argument_count + 1);
for (int i = 0; i < argument_count + 1; i++) {
for (int i = 0; i < argument_count; i++) {
vec.push_back(get_argument_metadata(i - 1));
}
return vec;
@@ -147,7 +147,7 @@ public:
virtual ~MethodBind();
};
template <typename Derived, typename T, typename R, bool should_returns>
template <class Derived, class T, class R, bool should_returns>
class MethodBindVarArgBase : public MethodBind {
protected:
R(T::*method)
@@ -208,7 +208,7 @@ private:
}
};
template <typename T>
template <class T>
class MethodBindVarArgT : public MethodBindVarArgBase<MethodBindVarArgT<T>, T, void, false> {
friend class MethodBindVarArgBase<MethodBindVarArgT<T>, T, void, false>;
@@ -231,14 +231,14 @@ private:
}
};
template <typename T>
template <class T>
MethodBind *create_vararg_method_bind(void (T::*p_method)(const Variant **, GDExtensionInt, GDExtensionCallError &), const MethodInfo &p_info, bool p_return_nil_is_variant) {
MethodBind *a = memnew((MethodBindVarArgT<T>)(p_method, p_info, p_return_nil_is_variant));
a->set_instance_class(T::get_class_static());
return a;
}
template <typename T, typename R>
template <class T, class R>
class MethodBindVarArgTR : public MethodBindVarArgBase<MethodBindVarArgTR<T, R>, T, R, true> {
friend class MethodBindVarArgBase<MethodBindVarArgTR<T, R>, T, R, true>;
@@ -260,7 +260,7 @@ private:
}
};
template <typename T, typename R>
template <class T, class R>
MethodBind *create_vararg_method_bind(R (T::*p_method)(const Variant **, GDExtensionInt, GDExtensionCallError &), const MethodInfo &p_info, bool p_return_nil_is_variant) {
MethodBind *a = memnew((MethodBindVarArgTR<T, R>)(p_method, p_info, p_return_nil_is_variant));
a->set_instance_class(T::get_class_static());
@@ -268,8 +268,8 @@ MethodBind *create_vararg_method_bind(R (T::*p_method)(const Variant **, GDExten
}
#ifndef TYPED_METHOD_BIND
class _gde_UnexistingClass;
#define MB_T _gde_UnexistingClass
class ___UnexistingClass;
#define MB_T ___UnexistingClass
#else
#define MB_T T
#endif
@@ -277,9 +277,9 @@ class _gde_UnexistingClass;
// No return, not const.
#ifdef TYPED_METHOD_BIND
template <typename T, typename... P>
template <class T, class... P>
#else
template <typename... P>
template <class... P>
#endif // TYPED_METHOD_BIND
class MethodBindT : public MethodBind {
void (MB_T::*method)(P...);
@@ -339,7 +339,7 @@ public:
}
};
template <typename T, typename... P>
template <class T, class... P>
MethodBind *create_method_bind(void (T::*p_method)(P...)) {
#ifdef TYPED_METHOD_BIND
MethodBind *a = memnew((MethodBindT<T, P...>)(p_method));
@@ -353,9 +353,9 @@ MethodBind *create_method_bind(void (T::*p_method)(P...)) {
// No return, const.
#ifdef TYPED_METHOD_BIND
template <typename T, typename... P>
template <class T, class... P>
#else
template <typename... P>
template <class... P>
#endif // TYPED_METHOD_BIND
class MethodBindTC : public MethodBind {
void (MB_T::*method)(P...) const;
@@ -412,11 +412,10 @@ public:
method = p_method;
generate_argument_types(sizeof...(P));
set_argument_count(sizeof...(P));
set_const(true);
}
};
template <typename T, typename... P>
template <class T, class... P>
MethodBind *create_method_bind(void (T::*p_method)(P...) const) {
#ifdef TYPED_METHOD_BIND
MethodBind *a = memnew((MethodBindTC<T, P...>)(p_method));
@@ -430,9 +429,9 @@ MethodBind *create_method_bind(void (T::*p_method)(P...) const) {
// Return, not const.
#ifdef TYPED_METHOD_BIND
template <typename T, typename R, typename... P>
template <class T, class R, class... P>
#else
template <typename R, typename... P>
template <class R, class... P>
#endif // TYPED_METHOD_BIND
class MethodBindTR : public MethodBind {
R(MB_T::*method)
@@ -499,7 +498,7 @@ public:
}
};
template <typename T, typename R, typename... P>
template <class T, class R, class... P>
MethodBind *create_method_bind(R (T::*p_method)(P...)) {
#ifdef TYPED_METHOD_BIND
MethodBind *a = memnew((MethodBindTR<T, R, P...>)(p_method));
@@ -513,9 +512,9 @@ MethodBind *create_method_bind(R (T::*p_method)(P...)) {
// Return, const.
#ifdef TYPED_METHOD_BIND
template <typename T, typename R, typename... P>
template <class T, class R, class... P>
#else
template <typename R, typename... P>
template <class R, class... P>
#endif // TYPED_METHOD_BIND
class MethodBindTRC : public MethodBind {
R(MB_T::*method)
@@ -579,11 +578,10 @@ public:
generate_argument_types(sizeof...(P));
set_argument_count(sizeof...(P));
set_return(true);
set_const(true);
}
};
template <typename T, typename R, typename... P>
template <class T, class R, class... P>
MethodBind *create_method_bind(R (T::*p_method)(P...) const) {
#ifdef TYPED_METHOD_BIND
MethodBind *a = memnew((MethodBindTRC<T, R, P...>)(p_method));
@@ -598,7 +596,7 @@ MethodBind *create_method_bind(R (T::*p_method)(P...) const) {
// no return
template <typename... P>
template <class... P>
class MethodBindTS : public MethodBind {
void (*function)(P...);
@@ -654,7 +652,7 @@ public:
}
};
template <typename... P>
template <class... P>
MethodBind *create_static_method_bind(void (*p_method)(P...)) {
MethodBind *a = memnew((MethodBindTS<P...>)(p_method));
return a;
@@ -662,7 +660,7 @@ MethodBind *create_static_method_bind(void (*p_method)(P...)) {
// return
template <typename R, typename... P>
template <class R, class... P>
class MethodBindTRS : public MethodBind {
R(*function)
(P...);
@@ -724,7 +722,7 @@ public:
}
};
template <typename R, typename... P>
template <class R, class... P>
MethodBind *create_static_method_bind(R (*p_method)(P...)) {
MethodBind *a = memnew((MethodBindTRS<R, P...>)(p_method));
return a;

View File

@@ -33,13 +33,12 @@
#include <godot_cpp/core/defs.hpp>
#include <godot_cpp/core/object.hpp>
#include <godot_cpp/godot.hpp>
#include <godot_cpp/variant/variant.hpp>
namespace godot {
template <typename T>
template <class T>
struct PtrToArg {};
#define MAKE_PTRARG(m_type) \
@@ -161,33 +160,30 @@ MAKE_PTRARG(PackedFloat64Array);
MAKE_PTRARG(PackedStringArray);
MAKE_PTRARG(PackedVector2Array);
MAKE_PTRARG(PackedVector3Array);
MAKE_PTRARG(PackedVector4Array);
MAKE_PTRARG(PackedColorArray);
MAKE_PTRARG_BY_REFERENCE(Variant);
// This is for Object.
template <typename T>
template <class T>
struct PtrToArg<T *> {
static_assert(std::is_base_of<Object, T>::value, "Cannot encode non-Object value as an Object");
_FORCE_INLINE_ static T *convert(const void *p_ptr) {
return likely(p_ptr) ? reinterpret_cast<T *>(godot::internal::get_object_instance_binding(*reinterpret_cast<GDExtensionObjectPtr *>(const_cast<void *>(p_ptr)))) : nullptr;
return reinterpret_cast<T *>(godot::internal::gde_interface->object_get_instance_binding(*reinterpret_cast<GDExtensionObjectPtr *>(const_cast<void *>(p_ptr)), godot::internal::token, &T::___binding_callbacks));
}
typedef Object *EncodeT;
_FORCE_INLINE_ static void encode(T *p_var, void *p_ptr) {
*reinterpret_cast<const void **>(p_ptr) = likely(p_var) ? p_var->_owner : nullptr;
*reinterpret_cast<const void **>(p_ptr) = p_var ? p_var->_owner : nullptr;
}
};
template <typename T>
template <class T>
struct PtrToArg<const T *> {
static_assert(std::is_base_of<Object, T>::value, "Cannot encode non-Object value as an Object");
_FORCE_INLINE_ static const T *convert(const void *p_ptr) {
return likely(p_ptr) ? reinterpret_cast<const T *>(godot::internal::get_object_instance_binding(*reinterpret_cast<GDExtensionObjectPtr *>(const_cast<void *>(p_ptr)))) : nullptr;
return reinterpret_cast<const T *>(godot::internal::gde_interface->object_get_instance_binding(*reinterpret_cast<GDExtensionObjectPtr *>(const_cast<void *>(p_ptr)), godot::internal::token, &T::___binding_callbacks));
}
typedef const Object *EncodeT;
_FORCE_INLINE_ static void encode(T *p_var, void *p_ptr) {
*reinterpret_cast<const void **>(p_ptr) = likely(p_var) ? p_var->_owner : nullptr;
*reinterpret_cast<const void **>(p_ptr) = p_var ? p_var->_owner : nullptr;
}
};

View File

@@ -33,8 +33,6 @@
#include <godot_cpp/core/defs.hpp>
#include <godot_cpp/core/object_id.hpp>
#include <godot_cpp/core/property_info.hpp>
#include <godot_cpp/variant/variant.hpp>
@@ -47,20 +45,13 @@
#include <vector>
#define ADD_SIGNAL(m_signal) ::godot::ClassDB::add_signal(get_class_static(), m_signal)
#define ADD_GROUP(m_name, m_prefix) ::godot::ClassDB::add_property_group(get_class_static(), m_name, m_prefix)
#define ADD_SUBGROUP(m_name, m_prefix) ::godot::ClassDB::add_property_subgroup(get_class_static(), m_name, m_prefix)
#define ADD_PROPERTY(m_property, m_setter, m_getter) ::godot::ClassDB::add_property(get_class_static(), m_property, m_setter, m_getter)
#define ADD_PROPERTYI(m_property, m_setter, m_getter, m_index) ::godot::ClassDB::add_property(get_class_static(), m_property, m_setter, m_getter, m_index)
#define ADD_SIGNAL(m_signal) godot::ClassDB::add_signal(get_class_static(), m_signal)
#define ADD_GROUP(m_name, m_prefix) godot::ClassDB::add_property_group(get_class_static(), m_name, m_prefix)
#define ADD_SUBGROUP(m_name, m_prefix) godot::ClassDB::add_property_subgroup(get_class_static(), m_name, m_prefix)
#define ADD_PROPERTY(m_property, m_setter, m_getter) godot::ClassDB::add_property(get_class_static(), m_property, m_setter, m_getter)
namespace godot {
namespace internal {
Object *get_object_instance_binding(GodotObject *);
} // namespace internal
struct MethodInfo {
StringName name;
PropertyInfo return_val;
@@ -68,8 +59,6 @@ struct MethodInfo {
int id = 0;
std::vector<PropertyInfo> arguments;
std::vector<Variant> default_arguments;
GDExtensionClassMethodArgumentMetadata return_val_metadata;
std::vector<GDExtensionClassMethodArgumentMetadata> arguments_metadata;
inline bool operator==(const MethodInfo &p_method) const { return id == p_method.id; }
inline bool operator<(const MethodInfo &p_method) const { return id == p_method.id ? (name < p_method.name) : (id < p_method.id); }
@@ -80,71 +69,93 @@ struct MethodInfo {
MethodInfo();
MethodInfo(StringName p_name);
template <typename... Args>
template <class... Args>
MethodInfo(StringName p_name, const Args &...args);
MethodInfo(Variant::Type ret);
MethodInfo(Variant::Type ret, StringName p_name);
template <typename... Args>
template <class... Args>
MethodInfo(Variant::Type ret, StringName p_name, const Args &...args);
MethodInfo(const PropertyInfo &p_ret, StringName p_name);
template <typename... Args>
template <class... Args>
MethodInfo(const PropertyInfo &p_ret, StringName p_name, const Args &...);
};
template <typename... Args>
template <class... Args>
MethodInfo::MethodInfo(StringName p_name, const Args &...args) :
name(p_name), flags(GDEXTENSION_METHOD_FLAG_NORMAL) {
arguments = { args... };
}
template <typename... Args>
template <class... Args>
MethodInfo::MethodInfo(Variant::Type ret, StringName p_name, const Args &...args) :
name(p_name), flags(GDEXTENSION_METHOD_FLAG_NORMAL) {
return_val.type = ret;
arguments = { args... };
}
template <typename... Args>
template <class... Args>
MethodInfo::MethodInfo(const PropertyInfo &p_ret, StringName p_name, const Args &...args) :
name(p_name), return_val(p_ret), flags(GDEXTENSION_METHOD_FLAG_NORMAL) {
arguments = { args... };
}
class ObjectID {
uint64_t id = 0;
public:
_FORCE_INLINE_ bool is_ref_counted() const { return (id & (uint64_t(1) << 63)) != 0; }
_FORCE_INLINE_ bool is_valid() const { return id != 0; }
_FORCE_INLINE_ bool is_null() const { return id == 0; }
_FORCE_INLINE_ operator uint64_t() const { return id; }
_FORCE_INLINE_ operator int64_t() const { return id; }
_FORCE_INLINE_ bool operator==(const ObjectID &p_id) const { return id == p_id.id; }
_FORCE_INLINE_ bool operator!=(const ObjectID &p_id) const { return id != p_id.id; }
_FORCE_INLINE_ bool operator<(const ObjectID &p_id) const { return id < p_id.id; }
_FORCE_INLINE_ void operator=(int64_t p_int64) { id = p_int64; }
_FORCE_INLINE_ void operator=(uint64_t p_uint64) { id = p_uint64; }
_FORCE_INLINE_ ObjectID() {}
_FORCE_INLINE_ explicit ObjectID(const uint64_t p_id) { id = p_id; }
_FORCE_INLINE_ explicit ObjectID(const int64_t p_id) { id = p_id; }
};
class ObjectDB {
public:
static Object *get_instance(uint64_t p_object_id) {
GDExtensionObjectPtr obj = internal::gdextension_interface_object_get_instance_from_id(p_object_id);
GDExtensionObjectPtr obj = internal::gde_interface->object_get_instance_from_id(p_object_id);
if (obj == nullptr) {
return nullptr;
}
return internal::get_object_instance_binding(obj);
return reinterpret_cast<Object *>(internal::gde_interface->object_get_instance_binding(obj, internal::token, &Object::___binding_callbacks));
}
};
template <typename T>
template <class T>
T *Object::cast_to(Object *p_object) {
if (p_object == nullptr) {
return nullptr;
}
StringName class_name = T::get_class_static();
GDExtensionObjectPtr casted = internal::gdextension_interface_object_cast_to(p_object->_owner, internal::gdextension_interface_classdb_get_class_tag(class_name._native_ptr()));
GDExtensionObjectPtr casted = internal::gde_interface->object_cast_to(p_object->_owner, internal::gde_interface->classdb_get_class_tag(class_name._native_ptr()));
if (casted == nullptr) {
return nullptr;
}
return dynamic_cast<T *>(internal::get_object_instance_binding(casted));
return reinterpret_cast<T *>(internal::gde_interface->object_get_instance_binding(casted, internal::token, &T::___binding_callbacks));
}
template <typename T>
template <class T>
const T *Object::cast_to(const Object *p_object) {
if (p_object == nullptr) {
return nullptr;
}
StringName class_name = T::get_class_static();
GDExtensionObjectPtr casted = internal::gdextension_interface_object_cast_to(p_object->_owner, internal::gdextension_interface_classdb_get_class_tag(class_name._native_ptr()));
GDExtensionObjectPtr casted = internal::gde_interface->object_cast_to(p_object->_owner, internal::gde_interface->classdb_get_class_tag(class_name._native_ptr()));
if (casted == nullptr) {
return nullptr;
}
return dynamic_cast<const T *>(internal::get_object_instance_binding(casted));
return reinterpret_cast<const T *>(internal::gde_interface->object_get_instance_binding(casted, internal::token, &T::___binding_callbacks));
}
} // namespace godot

View File

@@ -1,62 +0,0 @@
/**************************************************************************/
/* object_id.hpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* 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 GODOT_OBJECT_ID_HPP
#define GODOT_OBJECT_ID_HPP
#include <godot_cpp/core/defs.hpp>
namespace godot {
class ObjectID {
uint64_t id = 0;
public:
_FORCE_INLINE_ bool is_ref_counted() const { return (id & (uint64_t(1) << 63)) != 0; }
_FORCE_INLINE_ bool is_valid() const { return id != 0; }
_FORCE_INLINE_ bool is_null() const { return id == 0; }
_FORCE_INLINE_ operator uint64_t() const { return id; }
_FORCE_INLINE_ operator int64_t() const { return id; }
_FORCE_INLINE_ bool operator==(const ObjectID &p_id) const { return id == p_id.id; }
_FORCE_INLINE_ bool operator!=(const ObjectID &p_id) const { return id != p_id.id; }
_FORCE_INLINE_ bool operator<(const ObjectID &p_id) const { return id < p_id.id; }
_FORCE_INLINE_ void operator=(int64_t p_int64) { id = p_int64; }
_FORCE_INLINE_ void operator=(uint64_t p_uint64) { id = p_uint64; }
_FORCE_INLINE_ ObjectID() {}
_FORCE_INLINE_ explicit ObjectID(const uint64_t p_id) { id = p_id; }
_FORCE_INLINE_ explicit ObjectID(const int64_t p_id) { id = p_id; }
};
} // namespace godot
#endif // GODOT_OBJECT_ID_HPP

View File

@@ -1,73 +0,0 @@
/**************************************************************************/
/* print_string.hpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* 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 GODOT_PRINT_STRING_HPP
#define GODOT_PRINT_STRING_HPP
#include <godot_cpp/variant/utility_functions.hpp>
namespace godot {
inline void print_error(const Variant &p_variant) {
UtilityFunctions::printerr(p_variant);
}
inline void print_line(const Variant &p_variant) {
UtilityFunctions::print(p_variant);
}
inline void print_line_rich(const Variant &p_variant) {
UtilityFunctions::print_rich(p_variant);
}
template <typename... Args>
void print_error(const Variant &p_variant, Args... p_args) {
UtilityFunctions::printerr(p_variant, p_args...);
}
template <typename... Args>
void print_line(const Variant &p_variant, Args... p_args) {
UtilityFunctions::print(p_variant, p_args...);
}
template <typename... Args>
void print_line_rich(const Variant &p_variant, Args... p_args) {
UtilityFunctions::print_rich(p_variant, p_args...);
}
template <typename... Args>
void print_verbose(const Variant &p_variant, Args... p_args) {
UtilityFunctions::print_verbose(p_variant, p_args...);
}
bool is_print_verbose_enabled();
} // namespace godot
#endif // GODOT_PRINT_STRING_HPP

View File

@@ -47,9 +47,9 @@ struct PropertyInfo {
Variant::Type type = Variant::NIL;
StringName name;
StringName class_name;
uint32_t hint = PROPERTY_HINT_NONE;
uint32_t hint = 0;
String hint_string;
uint32_t usage = PROPERTY_USAGE_DEFAULT;
uint32_t usage = 7;
PropertyInfo() = default;
@@ -68,63 +68,6 @@ struct PropertyInfo {
PropertyInfo(GDExtensionVariantType p_type, const StringName &p_name, PropertyHint p_hint = PROPERTY_HINT_NONE, const String &p_hint_string = "", uint32_t p_usage = PROPERTY_USAGE_DEFAULT, const StringName &p_class_name = "") :
PropertyInfo((Variant::Type)p_type, p_name, p_hint, p_hint_string, p_usage, p_class_name) {}
PropertyInfo(const GDExtensionPropertyInfo *p_info) :
PropertyInfo(p_info->type, *reinterpret_cast<StringName *>(p_info->name), (PropertyHint)p_info->hint, *reinterpret_cast<String *>(p_info->hint_string), p_info->usage, *reinterpret_cast<StringName *>(p_info->class_name)) {}
operator Dictionary() const {
Dictionary dict;
dict["name"] = name;
dict["class_name"] = class_name;
dict["type"] = type;
dict["hint"] = hint;
dict["hint_string"] = hint_string;
dict["usage"] = usage;
return dict;
}
static PropertyInfo from_dict(const Dictionary &p_dict) {
PropertyInfo pi;
if (p_dict.has("type")) {
pi.type = Variant::Type(int(p_dict["type"]));
}
if (p_dict.has("name")) {
pi.name = p_dict["name"];
}
if (p_dict.has("class_name")) {
pi.class_name = p_dict["class_name"];
}
if (p_dict.has("hint")) {
pi.hint = PropertyHint(int(p_dict["hint"]));
}
if (p_dict.has("hint_string")) {
pi.hint_string = p_dict["hint_string"];
}
if (p_dict.has("usage")) {
pi.usage = p_dict["usage"];
}
return pi;
}
void _update(GDExtensionPropertyInfo *p_info) {
p_info->type = (GDExtensionVariantType)type;
*(reinterpret_cast<StringName *>(p_info->name)) = name;
p_info->hint = hint;
*(reinterpret_cast<String *>(p_info->hint_string)) = hint_string;
p_info->usage = usage;
*(reinterpret_cast<StringName *>(p_info->class_name)) = class_name;
}
GDExtensionPropertyInfo _to_gdextension() const {
return {
(GDExtensionVariantType)type,
name._native_ptr(),
class_name._native_ptr(),
hint,
hint_string._native_ptr(),
usage,
};
}
};
} // namespace godot

View File

@@ -58,16 +58,6 @@ struct TypesAreSame<A, A> {
static bool const value = true;
};
template <auto A, auto B>
struct FunctionsAreSame {
static bool const value = false;
};
template <auto A>
struct FunctionsAreSame<A, A> {
static bool const value = true;
};
template <typename B, typename D>
struct TypeInherits {
static D *get_d();
@@ -100,7 +90,7 @@ static PropertyInfo make_property_info(Variant::Type p_type, const StringName &p
// instead of a forward declaration. You can always forward declare 'T' in a header file, and then
// include the actual declaration of 'T' in the source file where 'GetTypeInfo<T>' is instantiated.
template <typename T, typename = void>
template <class T, typename = void>
struct GetTypeInfo;
#define MAKE_TYPE_INFO(m_type, m_var_type) \
@@ -148,8 +138,8 @@ MAKE_TYPE_INFO_WITH_META(uint32_t, GDEXTENSION_VARIANT_TYPE_INT, GDEXTENSION_MET
MAKE_TYPE_INFO_WITH_META(int32_t, GDEXTENSION_VARIANT_TYPE_INT, GDEXTENSION_METHOD_ARGUMENT_METADATA_INT_IS_INT32)
MAKE_TYPE_INFO_WITH_META(uint64_t, GDEXTENSION_VARIANT_TYPE_INT, GDEXTENSION_METHOD_ARGUMENT_METADATA_INT_IS_UINT64)
MAKE_TYPE_INFO_WITH_META(int64_t, GDEXTENSION_VARIANT_TYPE_INT, GDEXTENSION_METHOD_ARGUMENT_METADATA_INT_IS_INT64)
MAKE_TYPE_INFO_WITH_META(char16_t, GDEXTENSION_VARIANT_TYPE_INT, GDEXTENSION_METHOD_ARGUMENT_METADATA_INT_IS_CHAR16)
MAKE_TYPE_INFO_WITH_META(char32_t, GDEXTENSION_VARIANT_TYPE_INT, GDEXTENSION_METHOD_ARGUMENT_METADATA_INT_IS_CHAR32)
MAKE_TYPE_INFO(char16_t, GDEXTENSION_VARIANT_TYPE_INT)
MAKE_TYPE_INFO(char32_t, GDEXTENSION_VARIANT_TYPE_INT)
MAKE_TYPE_INFO_WITH_META(float, GDEXTENSION_VARIANT_TYPE_FLOAT, GDEXTENSION_METHOD_ARGUMENT_METADATA_REAL_IS_FLOAT)
MAKE_TYPE_INFO_WITH_META(double, GDEXTENSION_VARIANT_TYPE_FLOAT, GDEXTENSION_METHOD_ARGUMENT_METADATA_REAL_IS_DOUBLE)
@@ -185,7 +175,6 @@ MAKE_TYPE_INFO(PackedFloat64Array, GDEXTENSION_VARIANT_TYPE_PACKED_FLOAT64_ARRAY
MAKE_TYPE_INFO(PackedStringArray, GDEXTENSION_VARIANT_TYPE_PACKED_STRING_ARRAY)
MAKE_TYPE_INFO(PackedVector2Array, GDEXTENSION_VARIANT_TYPE_PACKED_VECTOR2_ARRAY)
MAKE_TYPE_INFO(PackedVector3Array, GDEXTENSION_VARIANT_TYPE_PACKED_VECTOR3_ARRAY)
MAKE_TYPE_INFO(PackedVector4Array, GDEXTENSION_VARIANT_TYPE_PACKED_VECTOR4_ARRAY)
MAKE_TYPE_INFO(PackedColorArray, GDEXTENSION_VARIANT_TYPE_PACKED_COLOR_ARRAY)
// For variant.
@@ -209,8 +198,8 @@ struct GetTypeInfo<const Variant &> {
template <typename T>
struct GetTypeInfo<T *, typename EnableIf<TypeInherits<Object, T>::value>::type> {
static constexpr GDExtensionVariantType VARIANT_TYPE = GDEXTENSION_VARIANT_TYPE_OBJECT;
static constexpr GDExtensionClassMethodArgumentMetadata METADATA = GDEXTENSION_METHOD_ARGUMENT_METADATA_NONE;
static const GDExtensionVariantType VARIANT_TYPE = GDEXTENSION_VARIANT_TYPE_OBJECT;
static const GDExtensionClassMethodArgumentMetadata METADATA = GDEXTENSION_METHOD_ARGUMENT_METADATA_NONE;
static inline PropertyInfo get_class_info() {
return make_property_info(Variant::Type::OBJECT, "", PROPERTY_HINT_RESOURCE_TYPE, T::get_class_static());
}
@@ -218,8 +207,8 @@ struct GetTypeInfo<T *, typename EnableIf<TypeInherits<Object, T>::value>::type>
template <typename T>
struct GetTypeInfo<const T *, typename EnableIf<TypeInherits<Object, T>::value>::type> {
static constexpr GDExtensionVariantType VARIANT_TYPE = GDEXTENSION_VARIANT_TYPE_OBJECT;
static constexpr GDExtensionClassMethodArgumentMetadata METADATA = GDEXTENSION_METHOD_ARGUMENT_METADATA_NONE;
static const GDExtensionVariantType VARIANT_TYPE = GDEXTENSION_VARIANT_TYPE_OBJECT;
static const GDExtensionClassMethodArgumentMetadata METADATA = GDEXTENSION_METHOD_ARGUMENT_METADATA_NONE;
static inline PropertyInfo get_class_info() {
return make_property_info(Variant::Type::OBJECT, "", PROPERTY_HINT_RESOURCE_TYPE, T::get_class_static());
}
@@ -237,8 +226,8 @@ inline String enum_qualified_name_to_class_info_name(const String &p_qualified_n
#define TEMPL_MAKE_ENUM_TYPE_INFO(m_enum, m_impl) \
template <> \
struct GetTypeInfo<m_impl> { \
static constexpr Variant::Type VARIANT_TYPE = Variant::INT; \
static constexpr GDExtensionClassMethodArgumentMetadata METADATA = GDEXTENSION_METHOD_ARGUMENT_METADATA_NONE; \
static const Variant::Type VARIANT_TYPE = Variant::INT; \
static const GDExtensionClassMethodArgumentMetadata METADATA = GDEXTENSION_METHOD_ARGUMENT_METADATA_NONE; \
static inline PropertyInfo get_class_info() { \
return make_property_info(Variant::Type::INT, "", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_CLASS_IS_ENUM, \
enum_qualified_name_to_class_info_name(#m_enum)); \
@@ -252,21 +241,21 @@ inline String enum_qualified_name_to_class_info_name(const String &p_qualified_n
TEMPL_MAKE_ENUM_TYPE_INFO(m_enum, const m_enum &)
template <typename T>
inline StringName _gde_constant_get_enum_name(T param, StringName p_constant) {
inline StringName __constant_get_enum_name(T param, StringName p_constant) {
if (GetTypeInfo<T>::VARIANT_TYPE == Variant::NIL) {
ERR_PRINT(("Missing VARIANT_ENUM_CAST for constant's enum: " + String(p_constant)).utf8().get_data());
}
return GetTypeInfo<T>::get_class_info().class_name;
}
template <typename T>
template <class T>
class BitField {
int64_t value = 0;
public:
_FORCE_INLINE_ void set_flag(T p_flag) { value |= p_flag; }
_FORCE_INLINE_ bool has_flag(T p_flag) const { return value & p_flag; }
_FORCE_INLINE_ void clear_flag(T p_flag) { value &= ~p_flag; }
_FORCE_INLINE_ void clear_flag(T p_flag) { return value &= ~p_flag; }
_FORCE_INLINE_ BitField(int64_t p_value) { value = p_value; }
_FORCE_INLINE_ operator int64_t() const { return value; }
_FORCE_INLINE_ operator Variant() const { return value; }
@@ -275,8 +264,8 @@ public:
#define TEMPL_MAKE_BITFIELD_TYPE_INFO(m_enum, m_impl) \
template <> \
struct GetTypeInfo<m_impl> { \
static constexpr Variant::Type VARIANT_TYPE = Variant::INT; \
static constexpr GDExtensionClassMethodArgumentMetadata METADATA = GDEXTENSION_METHOD_ARGUMENT_METADATA_NONE; \
static const Variant::Type VARIANT_TYPE = Variant::INT; \
static const GDExtensionClassMethodArgumentMetadata METADATA = GDEXTENSION_METHOD_ARGUMENT_METADATA_NONE; \
static inline PropertyInfo get_class_info() { \
return make_property_info(Variant::Type::INT, "", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_CLASS_IS_BITFIELD, \
enum_qualified_name_to_class_info_name(#m_enum)); \
@@ -284,8 +273,8 @@ public:
}; \
template <> \
struct GetTypeInfo<BitField<m_impl>> { \
static constexpr Variant::Type VARIANT_TYPE = Variant::INT; \
static constexpr GDExtensionClassMethodArgumentMetadata METADATA = GDEXTENSION_METHOD_ARGUMENT_METADATA_NONE; \
static const Variant::Type VARIANT_TYPE = Variant::INT; \
static const GDExtensionClassMethodArgumentMetadata METADATA = GDEXTENSION_METHOD_ARGUMENT_METADATA_NONE; \
static inline PropertyInfo get_class_info() { \
return make_property_info(Variant::Type::INT, "", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_CLASS_IS_BITFIELD, \
enum_qualified_name_to_class_info_name(#m_enum)); \
@@ -299,14 +288,14 @@ public:
TEMPL_MAKE_BITFIELD_TYPE_INFO(m_enum, const m_enum &)
template <typename T>
inline StringName _gde_constant_get_bitfield_name(T param, StringName p_constant) {
inline StringName __constant_get_bitfield_name(T param, StringName p_constant) {
if (GetTypeInfo<T>::VARIANT_TYPE == Variant::NIL) {
ERR_PRINT(("Missing VARIANT_ENUM_CAST for constant's bitfield: " + String(p_constant)).utf8().get_data());
}
return GetTypeInfo<BitField<T>>::get_class_info().class_name;
}
template <typename T>
template <class T>
struct PtrToArg<TypedArray<T>> {
_FORCE_INLINE_ static TypedArray<T> convert(const void *p_ptr) {
return TypedArray<T>(*reinterpret_cast<const Array *>(p_ptr));
@@ -317,7 +306,7 @@ struct PtrToArg<TypedArray<T>> {
}
};
template <typename T>
template <class T>
struct PtrToArg<const TypedArray<T> &> {
typedef Array EncodeT;
_FORCE_INLINE_ static TypedArray<T>
@@ -381,14 +370,11 @@ MAKE_TYPED_ARRAY_INFO(Rect2i, Variant::RECT2I)
MAKE_TYPED_ARRAY_INFO(Vector3, Variant::VECTOR3)
MAKE_TYPED_ARRAY_INFO(Vector3i, Variant::VECTOR3I)
MAKE_TYPED_ARRAY_INFO(Transform2D, Variant::TRANSFORM2D)
MAKE_TYPED_ARRAY_INFO(Vector4, Variant::VECTOR4)
MAKE_TYPED_ARRAY_INFO(Vector4i, Variant::VECTOR4I)
MAKE_TYPED_ARRAY_INFO(Plane, Variant::PLANE)
MAKE_TYPED_ARRAY_INFO(Quaternion, Variant::QUATERNION)
MAKE_TYPED_ARRAY_INFO(AABB, Variant::AABB)
MAKE_TYPED_ARRAY_INFO(Basis, Variant::BASIS)
MAKE_TYPED_ARRAY_INFO(Transform3D, Variant::TRANSFORM3D)
MAKE_TYPED_ARRAY_INFO(Projection, Variant::PROJECTION)
MAKE_TYPED_ARRAY_INFO(Color, Variant::COLOR)
MAKE_TYPED_ARRAY_INFO(StringName, Variant::STRING_NAME)
MAKE_TYPED_ARRAY_INFO(NodePath, Variant::NODE_PATH)
@@ -397,22 +383,18 @@ MAKE_TYPED_ARRAY_INFO(Callable, Variant::CALLABLE)
MAKE_TYPED_ARRAY_INFO(Signal, Variant::SIGNAL)
MAKE_TYPED_ARRAY_INFO(Dictionary, Variant::DICTIONARY)
MAKE_TYPED_ARRAY_INFO(Array, Variant::ARRAY)
MAKE_TYPED_ARRAY_INFO(PackedByteArray, Variant::PACKED_BYTE_ARRAY)
MAKE_TYPED_ARRAY_INFO(PackedInt32Array, Variant::PACKED_INT32_ARRAY)
MAKE_TYPED_ARRAY_INFO(PackedInt64Array, Variant::PACKED_INT64_ARRAY)
MAKE_TYPED_ARRAY_INFO(PackedFloat32Array, Variant::PACKED_FLOAT32_ARRAY)
MAKE_TYPED_ARRAY_INFO(PackedFloat64Array, Variant::PACKED_FLOAT64_ARRAY)
MAKE_TYPED_ARRAY_INFO(PackedStringArray, Variant::PACKED_STRING_ARRAY)
MAKE_TYPED_ARRAY_INFO(PackedVector2Array, Variant::PACKED_VECTOR2_ARRAY)
MAKE_TYPED_ARRAY_INFO(PackedVector3Array, Variant::PACKED_VECTOR3_ARRAY)
MAKE_TYPED_ARRAY_INFO(PackedVector4Array, Variant::PACKED_VECTOR4_ARRAY)
MAKE_TYPED_ARRAY_INFO(PackedColorArray, Variant::PACKED_COLOR_ARRAY)
/*
MAKE_TYPED_ARRAY_INFO(IPAddress, Variant::STRING)
MAKE_TYPED_ARRAY_INFO(Vector<uint8_t>, Variant::PACKED_BYTE_ARRAY)
MAKE_TYPED_ARRAY_INFO(Vector<int32_t>, Variant::PACKED_INT32_ARRAY)
MAKE_TYPED_ARRAY_INFO(Vector<int64_t>, Variant::PACKED_INT64_ARRAY)
MAKE_TYPED_ARRAY_INFO(Vector<float>, Variant::PACKED_FLOAT32_ARRAY)
MAKE_TYPED_ARRAY_INFO(Vector<double>, Variant::PACKED_FLOAT64_ARRAY)
MAKE_TYPED_ARRAY_INFO(Vector<String>, Variant::PACKED_STRING_ARRAY)
MAKE_TYPED_ARRAY_INFO(Vector<Vector2>, Variant::PACKED_VECTOR2_ARRAY)
MAKE_TYPED_ARRAY_INFO(Vector<Vector3>, Variant::PACKED_VECTOR3_ARRAY)
MAKE_TYPED_ARRAY_INFO(Vector<Color>, Variant::PACKED_COLOR_ARRAY)
*/
#undef MAKE_TYPED_ARRAY_INFO
#define CLASS_INFO(m_type) (GetTypeInfo<m_type *>::get_class_info())
} // namespace godot

View File

@@ -37,224 +37,42 @@ namespace godot {
namespace internal {
extern "C" GDExtensionInterfaceGetProcAddress gdextension_interface_get_proc_address;
extern "C" const GDExtensionInterface *gde_interface;
extern "C" GDExtensionClassLibraryPtr library;
extern "C" void *token;
extern "C" GDExtensionGodotVersion godot_version;
// All of the GDExtension interface functions.
extern "C" GDExtensionInterfaceGetGodotVersion gdextension_interface_get_godot_version;
extern "C" GDExtensionInterfaceMemAlloc gdextension_interface_mem_alloc;
extern "C" GDExtensionInterfaceMemRealloc gdextension_interface_mem_realloc;
extern "C" GDExtensionInterfaceMemFree gdextension_interface_mem_free;
extern "C" GDExtensionInterfacePrintError gdextension_interface_print_error;
extern "C" GDExtensionInterfacePrintErrorWithMessage gdextension_interface_print_error_with_message;
extern "C" GDExtensionInterfacePrintWarning gdextension_interface_print_warning;
extern "C" GDExtensionInterfacePrintWarningWithMessage gdextension_interface_print_warning_with_message;
extern "C" GDExtensionInterfacePrintScriptError gdextension_interface_print_script_error;
extern "C" GDExtensionInterfacePrintScriptErrorWithMessage gdextension_interface_print_script_error_with_message;
extern "C" GDExtensionInterfaceGetNativeStructSize gdextension_interface_get_native_struct_size;
extern "C" GDExtensionInterfaceVariantNewCopy gdextension_interface_variant_new_copy;
extern "C" GDExtensionInterfaceVariantNewNil gdextension_interface_variant_new_nil;
extern "C" GDExtensionInterfaceVariantDestroy gdextension_interface_variant_destroy;
extern "C" GDExtensionInterfaceVariantCall gdextension_interface_variant_call;
extern "C" GDExtensionInterfaceVariantCallStatic gdextension_interface_variant_call_static;
extern "C" GDExtensionInterfaceVariantEvaluate gdextension_interface_variant_evaluate;
extern "C" GDExtensionInterfaceVariantSet gdextension_interface_variant_set;
extern "C" GDExtensionInterfaceVariantSetNamed gdextension_interface_variant_set_named;
extern "C" GDExtensionInterfaceVariantSetKeyed gdextension_interface_variant_set_keyed;
extern "C" GDExtensionInterfaceVariantSetIndexed gdextension_interface_variant_set_indexed;
extern "C" GDExtensionInterfaceVariantGet gdextension_interface_variant_get;
extern "C" GDExtensionInterfaceVariantGetNamed gdextension_interface_variant_get_named;
extern "C" GDExtensionInterfaceVariantGetKeyed gdextension_interface_variant_get_keyed;
extern "C" GDExtensionInterfaceVariantGetIndexed gdextension_interface_variant_get_indexed;
extern "C" GDExtensionInterfaceVariantIterInit gdextension_interface_variant_iter_init;
extern "C" GDExtensionInterfaceVariantIterNext gdextension_interface_variant_iter_next;
extern "C" GDExtensionInterfaceVariantIterGet gdextension_interface_variant_iter_get;
extern "C" GDExtensionInterfaceVariantHash gdextension_interface_variant_hash;
extern "C" GDExtensionInterfaceVariantRecursiveHash gdextension_interface_variant_recursive_hash;
extern "C" GDExtensionInterfaceVariantHashCompare gdextension_interface_variant_hash_compare;
extern "C" GDExtensionInterfaceVariantBooleanize gdextension_interface_variant_booleanize;
extern "C" GDExtensionInterfaceVariantDuplicate gdextension_interface_variant_duplicate;
extern "C" GDExtensionInterfaceVariantStringify gdextension_interface_variant_stringify;
extern "C" GDExtensionInterfaceVariantGetType gdextension_interface_variant_get_type;
extern "C" GDExtensionInterfaceVariantHasMethod gdextension_interface_variant_has_method;
extern "C" GDExtensionInterfaceVariantHasMember gdextension_interface_variant_has_member;
extern "C" GDExtensionInterfaceVariantHasKey gdextension_interface_variant_has_key;
extern "C" GDExtensionInterfaceVariantGetObjectInstanceId gdextension_interface_variant_get_object_instance_id;
extern "C" GDExtensionInterfaceVariantGetTypeName gdextension_interface_variant_get_type_name;
extern "C" GDExtensionInterfaceVariantCanConvert gdextension_interface_variant_can_convert;
extern "C" GDExtensionInterfaceVariantCanConvertStrict gdextension_interface_variant_can_convert_strict;
extern "C" GDExtensionInterfaceGetVariantFromTypeConstructor gdextension_interface_get_variant_from_type_constructor;
extern "C" GDExtensionInterfaceGetVariantToTypeConstructor gdextension_interface_get_variant_to_type_constructor;
extern "C" GDExtensionInterfaceGetVariantGetInternalPtrFunc gdextension_interface_variant_get_ptr_internal_getter;
extern "C" GDExtensionInterfaceVariantGetPtrOperatorEvaluator gdextension_interface_variant_get_ptr_operator_evaluator;
extern "C" GDExtensionInterfaceVariantGetPtrBuiltinMethod gdextension_interface_variant_get_ptr_builtin_method;
extern "C" GDExtensionInterfaceVariantGetPtrConstructor gdextension_interface_variant_get_ptr_constructor;
extern "C" GDExtensionInterfaceVariantGetPtrDestructor gdextension_interface_variant_get_ptr_destructor;
extern "C" GDExtensionInterfaceVariantConstruct gdextension_interface_variant_construct;
extern "C" GDExtensionInterfaceVariantGetPtrSetter gdextension_interface_variant_get_ptr_setter;
extern "C" GDExtensionInterfaceVariantGetPtrGetter gdextension_interface_variant_get_ptr_getter;
extern "C" GDExtensionInterfaceVariantGetPtrIndexedSetter gdextension_interface_variant_get_ptr_indexed_setter;
extern "C" GDExtensionInterfaceVariantGetPtrIndexedGetter gdextension_interface_variant_get_ptr_indexed_getter;
extern "C" GDExtensionInterfaceVariantGetPtrKeyedSetter gdextension_interface_variant_get_ptr_keyed_setter;
extern "C" GDExtensionInterfaceVariantGetPtrKeyedGetter gdextension_interface_variant_get_ptr_keyed_getter;
extern "C" GDExtensionInterfaceVariantGetPtrKeyedChecker gdextension_interface_variant_get_ptr_keyed_checker;
extern "C" GDExtensionInterfaceVariantGetConstantValue gdextension_interface_variant_get_constant_value;
extern "C" GDExtensionInterfaceVariantGetPtrUtilityFunction gdextension_interface_variant_get_ptr_utility_function;
extern "C" GDExtensionInterfaceStringNewWithLatin1Chars gdextension_interface_string_new_with_latin1_chars;
extern "C" GDExtensionInterfaceStringNewWithUtf8Chars gdextension_interface_string_new_with_utf8_chars;
extern "C" GDExtensionInterfaceStringNewWithUtf16Chars gdextension_interface_string_new_with_utf16_chars;
extern "C" GDExtensionInterfaceStringNewWithUtf32Chars gdextension_interface_string_new_with_utf32_chars;
extern "C" GDExtensionInterfaceStringNewWithWideChars gdextension_interface_string_new_with_wide_chars;
extern "C" GDExtensionInterfaceStringNewWithLatin1CharsAndLen gdextension_interface_string_new_with_latin1_chars_and_len;
extern "C" GDExtensionInterfaceStringNewWithUtf8CharsAndLen gdextension_interface_string_new_with_utf8_chars_and_len;
extern "C" GDExtensionInterfaceStringNewWithUtf8CharsAndLen2 gdextension_interface_string_new_with_utf8_chars_and_len2;
extern "C" GDExtensionInterfaceStringNewWithUtf16CharsAndLen gdextension_interface_string_new_with_utf16_chars_and_len;
extern "C" GDExtensionInterfaceStringNewWithUtf16CharsAndLen2 gdextension_interface_string_new_with_utf16_chars_and_len2;
extern "C" GDExtensionInterfaceStringNewWithUtf32CharsAndLen gdextension_interface_string_new_with_utf32_chars_and_len;
extern "C" GDExtensionInterfaceStringNewWithWideCharsAndLen gdextension_interface_string_new_with_wide_chars_and_len;
extern "C" GDExtensionInterfaceStringToLatin1Chars gdextension_interface_string_to_latin1_chars;
extern "C" GDExtensionInterfaceStringToUtf8Chars gdextension_interface_string_to_utf8_chars;
extern "C" GDExtensionInterfaceStringToUtf16Chars gdextension_interface_string_to_utf16_chars;
extern "C" GDExtensionInterfaceStringToUtf32Chars gdextension_interface_string_to_utf32_chars;
extern "C" GDExtensionInterfaceStringToWideChars gdextension_interface_string_to_wide_chars;
extern "C" GDExtensionInterfaceStringOperatorIndex gdextension_interface_string_operator_index;
extern "C" GDExtensionInterfaceStringOperatorIndexConst gdextension_interface_string_operator_index_const;
extern "C" GDExtensionInterfaceStringOperatorPlusEqString gdextension_interface_string_operator_plus_eq_string;
extern "C" GDExtensionInterfaceStringOperatorPlusEqChar gdextension_interface_string_operator_plus_eq_char;
extern "C" GDExtensionInterfaceStringOperatorPlusEqCstr gdextension_interface_string_operator_plus_eq_cstr;
extern "C" GDExtensionInterfaceStringOperatorPlusEqWcstr gdextension_interface_string_operator_plus_eq_wcstr;
extern "C" GDExtensionInterfaceStringOperatorPlusEqC32str gdextension_interface_string_operator_plus_eq_c32str;
extern "C" GDExtensionInterfaceStringResize gdextension_interface_string_resize;
extern "C" GDExtensionInterfaceStringNameNewWithLatin1Chars gdextension_interface_string_name_new_with_latin1_chars;
extern "C" GDExtensionInterfaceXmlParserOpenBuffer gdextension_interface_xml_parser_open_buffer;
extern "C" GDExtensionInterfaceFileAccessStoreBuffer gdextension_interface_file_access_store_buffer;
extern "C" GDExtensionInterfaceFileAccessGetBuffer gdextension_interface_file_access_get_buffer;
extern "C" GDExtensionInterfaceWorkerThreadPoolAddNativeGroupTask gdextension_interface_worker_thread_pool_add_native_group_task;
extern "C" GDExtensionInterfaceWorkerThreadPoolAddNativeTask gdextension_interface_worker_thread_pool_add_native_task;
extern "C" GDExtensionInterfacePackedByteArrayOperatorIndex gdextension_interface_packed_byte_array_operator_index;
extern "C" GDExtensionInterfacePackedByteArrayOperatorIndexConst gdextension_interface_packed_byte_array_operator_index_const;
extern "C" GDExtensionInterfacePackedColorArrayOperatorIndex gdextension_interface_packed_color_array_operator_index;
extern "C" GDExtensionInterfacePackedColorArrayOperatorIndexConst gdextension_interface_packed_color_array_operator_index_const;
extern "C" GDExtensionInterfacePackedFloat32ArrayOperatorIndex gdextension_interface_packed_float32_array_operator_index;
extern "C" GDExtensionInterfacePackedFloat32ArrayOperatorIndexConst gdextension_interface_packed_float32_array_operator_index_const;
extern "C" GDExtensionInterfacePackedFloat64ArrayOperatorIndex gdextension_interface_packed_float64_array_operator_index;
extern "C" GDExtensionInterfacePackedFloat64ArrayOperatorIndexConst gdextension_interface_packed_float64_array_operator_index_const;
extern "C" GDExtensionInterfacePackedInt32ArrayOperatorIndex gdextension_interface_packed_int32_array_operator_index;
extern "C" GDExtensionInterfacePackedInt32ArrayOperatorIndexConst gdextension_interface_packed_int32_array_operator_index_const;
extern "C" GDExtensionInterfacePackedInt64ArrayOperatorIndex gdextension_interface_packed_int64_array_operator_index;
extern "C" GDExtensionInterfacePackedInt64ArrayOperatorIndexConst gdextension_interface_packed_int64_array_operator_index_const;
extern "C" GDExtensionInterfacePackedStringArrayOperatorIndex gdextension_interface_packed_string_array_operator_index;
extern "C" GDExtensionInterfacePackedStringArrayOperatorIndexConst gdextension_interface_packed_string_array_operator_index_const;
extern "C" GDExtensionInterfacePackedVector2ArrayOperatorIndex gdextension_interface_packed_vector2_array_operator_index;
extern "C" GDExtensionInterfacePackedVector2ArrayOperatorIndexConst gdextension_interface_packed_vector2_array_operator_index_const;
extern "C" GDExtensionInterfacePackedVector3ArrayOperatorIndex gdextension_interface_packed_vector3_array_operator_index;
extern "C" GDExtensionInterfacePackedVector3ArrayOperatorIndexConst gdextension_interface_packed_vector3_array_operator_index_const;
extern "C" GDExtensionInterfacePackedVector4ArrayOperatorIndex gdextension_interface_packed_vector4_array_operator_index;
extern "C" GDExtensionInterfacePackedVector4ArrayOperatorIndexConst gdextension_interface_packed_vector4_array_operator_index_const;
extern "C" GDExtensionInterfaceArrayOperatorIndex gdextension_interface_array_operator_index;
extern "C" GDExtensionInterfaceArrayOperatorIndexConst gdextension_interface_array_operator_index_const;
extern "C" GDExtensionInterfaceArrayRef gdextension_interface_array_ref;
extern "C" GDExtensionInterfaceArraySetTyped gdextension_interface_array_set_typed;
extern "C" GDExtensionInterfaceDictionaryOperatorIndex gdextension_interface_dictionary_operator_index;
extern "C" GDExtensionInterfaceDictionaryOperatorIndexConst gdextension_interface_dictionary_operator_index_const;
extern "C" GDExtensionInterfaceDictionarySetTyped gdextension_interface_dictionary_set_typed;
extern "C" GDExtensionInterfaceObjectMethodBindCall gdextension_interface_object_method_bind_call;
extern "C" GDExtensionInterfaceObjectMethodBindPtrcall gdextension_interface_object_method_bind_ptrcall;
extern "C" GDExtensionInterfaceObjectDestroy gdextension_interface_object_destroy;
extern "C" GDExtensionInterfaceGlobalGetSingleton gdextension_interface_global_get_singleton;
extern "C" GDExtensionInterfaceObjectGetInstanceBinding gdextension_interface_object_get_instance_binding;
extern "C" GDExtensionInterfaceObjectSetInstanceBinding gdextension_interface_object_set_instance_binding;
extern "C" GDExtensionInterfaceObjectFreeInstanceBinding gdextension_interface_object_free_instance_binding;
extern "C" GDExtensionInterfaceObjectSetInstance gdextension_interface_object_set_instance;
extern "C" GDExtensionInterfaceObjectGetClassName gdextension_interface_object_get_class_name;
extern "C" GDExtensionInterfaceObjectCastTo gdextension_interface_object_cast_to;
extern "C" GDExtensionInterfaceObjectGetInstanceFromId gdextension_interface_object_get_instance_from_id;
extern "C" GDExtensionInterfaceObjectGetInstanceId gdextension_interface_object_get_instance_id;
extern "C" GDExtensionInterfaceObjectHasScriptMethod gdextension_interface_object_has_script_method;
extern "C" GDExtensionInterfaceObjectCallScriptMethod gdextension_interface_object_call_script_method;
extern "C" GDExtensionInterfaceCallableCustomCreate2 gdextension_interface_callable_custom_create2;
extern "C" GDExtensionInterfaceCallableCustomGetUserData gdextension_interface_callable_custom_get_userdata;
extern "C" GDExtensionInterfaceRefGetObject gdextension_interface_ref_get_object;
extern "C" GDExtensionInterfaceRefSetObject gdextension_interface_ref_set_object;
extern "C" GDExtensionInterfaceScriptInstanceCreate3 gdextension_interface_script_instance_create3;
extern "C" GDExtensionInterfacePlaceHolderScriptInstanceCreate gdextension_interface_placeholder_script_instance_create;
extern "C" GDExtensionInterfacePlaceHolderScriptInstanceUpdate gdextension_interface_placeholder_script_instance_update;
extern "C" GDExtensionInterfaceClassdbConstructObject2 gdextension_interface_classdb_construct_object2;
extern "C" GDExtensionInterfaceClassdbGetMethodBind gdextension_interface_classdb_get_method_bind;
extern "C" GDExtensionInterfaceClassdbGetClassTag gdextension_interface_classdb_get_class_tag;
extern "C" GDExtensionInterfaceClassdbRegisterExtensionClass4 gdextension_interface_classdb_register_extension_class4;
extern "C" GDExtensionInterfaceClassdbRegisterExtensionClassMethod gdextension_interface_classdb_register_extension_class_method;
extern "C" GDExtensionInterfaceClassdbRegisterExtensionClassVirtualMethod gdextension_interface_classdb_register_extension_class_virtual_method;
extern "C" GDExtensionInterfaceClassdbRegisterExtensionClassIntegerConstant gdextension_interface_classdb_register_extension_class_integer_constant;
extern "C" GDExtensionInterfaceClassdbRegisterExtensionClassProperty gdextension_interface_classdb_register_extension_class_property;
extern "C" GDExtensionInterfaceClassdbRegisterExtensionClassPropertyIndexed gdextension_interface_classdb_register_extension_class_property_indexed;
extern "C" GDExtensionInterfaceClassdbRegisterExtensionClassPropertyGroup gdextension_interface_classdb_register_extension_class_property_group;
extern "C" GDExtensionInterfaceClassdbRegisterExtensionClassPropertySubgroup gdextension_interface_classdb_register_extension_class_property_subgroup;
extern "C" GDExtensionInterfaceClassdbRegisterExtensionClassSignal gdextension_interface_classdb_register_extension_class_signal;
extern "C" GDExtensionInterfaceClassdbUnregisterExtensionClass gdextension_interface_classdb_unregister_extension_class;
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" 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;
extern "C" GDExtensionInterfaceImagePtr gdextension_interface_image_ptr;
class DocDataRegistration {
public:
DocDataRegistration(const char *p_hash, int p_uncompressed_size, int p_compressed_size, const unsigned char *p_data);
};
} // namespace internal
enum ModuleInitializationLevel {
MODULE_INITIALIZATION_LEVEL_CORE = GDEXTENSION_INITIALIZATION_CORE,
MODULE_INITIALIZATION_LEVEL_SERVERS = GDEXTENSION_INITIALIZATION_SERVERS,
MODULE_INITIALIZATION_LEVEL_SCENE = GDEXTENSION_INITIALIZATION_SCENE,
MODULE_INITIALIZATION_LEVEL_EDITOR = GDEXTENSION_INITIALIZATION_EDITOR,
MODULE_INITIALIZATION_LEVEL_MAX
MODULE_INITIALIZATION_LEVEL_EDITOR = GDEXTENSION_INITIALIZATION_EDITOR
};
class GDExtensionBinding {
public:
using Callback = void (*)(ModuleInitializationLevel p_level);
struct InitData {
GDExtensionInitializationLevel minimum_initialization_level = GDEXTENSION_INITIALIZATION_CORE;
Callback init_callback = nullptr;
Callback terminate_callback = nullptr;
};
class InitDataList {
int data_count = 0;
int data_capacity = 0;
InitData **data = nullptr;
public:
void add(InitData *p_cb);
~InitDataList();
};
static bool api_initialized;
static int level_initialized[MODULE_INITIALIZATION_LEVEL_MAX];
static InitDataList initdata;
static GDExtensionBool init(GDExtensionInterfaceGetProcAddress p_get_proc_address, GDExtensionClassLibraryPtr p_library, InitData *p_init_data, GDExtensionInitialization *r_initialization);
static Callback init_callback;
static Callback terminate_callback;
static GDExtensionInitializationLevel minimum_initialization_level;
static GDExtensionBool init(const GDExtensionInterface *p_interface, GDExtensionClassLibraryPtr p_library, GDExtensionInitialization *r_initialization);
public:
static void initialize_level(void *p_userdata, GDExtensionInitializationLevel p_level);
static void deinitialize_level(void *p_userdata, GDExtensionInitializationLevel p_level);
static void initialize_level(void *userdata, GDExtensionInitializationLevel p_level);
static void deinitialize_level(void *userdata, GDExtensionInitializationLevel p_level);
class InitObject {
GDExtensionInterfaceGetProcAddress get_proc_address;
const GDExtensionInterface *gde_interface;
GDExtensionClassLibraryPtr library;
GDExtensionInitialization *initialization;
mutable InitData *init_data = nullptr;
public:
InitObject(GDExtensionInterfaceGetProcAddress p_get_proc_address, GDExtensionClassLibraryPtr p_library, GDExtensionInitialization *r_initialization);
InitObject(const GDExtensionInterface *p_interface, GDExtensionClassLibraryPtr p_library, GDExtensionInitialization *r_initialization) :
gde_interface(p_interface),
library(p_library),
initialization(r_initialization) {}
void register_initializer(Callback p_init) const;
void register_terminator(Callback p_init) const;

View File

@@ -32,160 +32,108 @@
#define GODOT_COWDATA_HPP
#include <godot_cpp/classes/global_constants.hpp>
#include <godot_cpp/core/class_db.hpp>
#include <godot_cpp/core/error_macros.hpp>
#include <godot_cpp/core/math.hpp>
#include <godot_cpp/core/memory.hpp>
#include <godot_cpp/templates/safe_refcount.hpp>
#include <cstring>
#include <new>
#include <type_traits>
namespace godot {
template <typename T>
template <class T>
class Vector;
template <typename T, typename V>
template <class T, class V>
class VMap;
template <typename T>
class CharStringT;
static_assert(std::is_trivially_destructible_v<std::atomic<uint64_t>>);
// Silence a false positive warning (see GH-52119).
#if defined(__GNUC__) && !defined(__clang__)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wplacement-new"
#endif
template <typename T>
template <class T>
class CowData {
template <typename TV>
template <class TV>
friend class Vector;
template <typename TV, typename VV>
template <class TV, class VV>
friend class VMap;
template <typename TS>
friend class CharStringT;
public:
typedef int64_t Size;
typedef uint64_t USize;
static constexpr USize MAX_INT = INT64_MAX;
private:
// Function to find the next power of 2 to an integer.
static _FORCE_INLINE_ USize next_po2(USize x) {
if (x == 0) {
return 0;
}
--x;
x |= x >> 1;
x |= x >> 2;
x |= x >> 4;
x |= x >> 8;
x |= x >> 16;
if (sizeof(USize) == 8) {
x |= x >> 32;
}
return ++x;
}
// Alignment: ↓ max_align_t ↓ USize ↓ max_align_t
// ┌────────────────────┬──┬─────────────┬──┬───────────...
// │ SafeNumeric<USize> │░░│ USize │░░│ T[]
// │ ref. count │░░│ data size │░░│ data
// └────────────────────┴──┴─────────────┴──┴───────────...
// Offset: ↑ REF_COUNT_OFFSET ↑ SIZE_OFFSET ↑ DATA_OFFSET
static constexpr size_t REF_COUNT_OFFSET = 0;
static constexpr size_t SIZE_OFFSET = ((REF_COUNT_OFFSET + sizeof(SafeNumeric<USize>)) % alignof(USize) == 0) ? (REF_COUNT_OFFSET + sizeof(SafeNumeric<USize>)) : ((REF_COUNT_OFFSET + sizeof(SafeNumeric<USize>)) + alignof(USize) - ((REF_COUNT_OFFSET + sizeof(SafeNumeric<USize>)) % alignof(USize)));
static constexpr size_t DATA_OFFSET = ((SIZE_OFFSET + sizeof(USize)) % alignof(max_align_t) == 0) ? (SIZE_OFFSET + sizeof(USize)) : ((SIZE_OFFSET + sizeof(USize)) + alignof(max_align_t) - ((SIZE_OFFSET + sizeof(USize)) % alignof(max_align_t)));
mutable T *_ptr = nullptr;
// internal helpers
static _FORCE_INLINE_ SafeNumeric<USize> *_get_refcount_ptr(uint8_t *p_ptr) {
return (SafeNumeric<USize> *)(p_ptr + REF_COUNT_OFFSET);
}
static _FORCE_INLINE_ USize *_get_size_ptr(uint8_t *p_ptr) {
return (USize *)(p_ptr + SIZE_OFFSET);
}
static _FORCE_INLINE_ T *_get_data_ptr(uint8_t *p_ptr) {
return (T *)(p_ptr + DATA_OFFSET);
}
_FORCE_INLINE_ SafeNumeric<USize> *_get_refcount() const {
_FORCE_INLINE_ SafeNumeric<uint32_t> *_get_refcount() const {
if (!_ptr) {
return nullptr;
}
return (SafeNumeric<USize> *)((uint8_t *)_ptr - DATA_OFFSET + REF_COUNT_OFFSET);
return reinterpret_cast<SafeNumeric<uint32_t> *>(_ptr) - 2;
}
_FORCE_INLINE_ USize *_get_size() const {
_FORCE_INLINE_ uint32_t *_get_size() const {
if (!_ptr) {
return nullptr;
}
return (USize *)((uint8_t *)_ptr - DATA_OFFSET + SIZE_OFFSET);
return reinterpret_cast<uint32_t *>(_ptr) - 1;
}
_FORCE_INLINE_ USize _get_alloc_size(USize p_elements) const {
return next_po2(p_elements * sizeof(T));
}
_FORCE_INLINE_ bool _get_alloc_size_checked(USize p_elements, USize *out) const {
if (unlikely(p_elements == 0)) {
*out = 0;
return true;
_FORCE_INLINE_ T *_get_data() const {
if (!_ptr) {
return nullptr;
}
#if defined(__GNUC__) && defined(IS_32_BIT)
USize o;
USize p;
return reinterpret_cast<T *>(_ptr);
}
_FORCE_INLINE_ size_t _get_alloc_size(size_t p_elements) const {
return next_power_of_2(p_elements * sizeof(T));
}
_FORCE_INLINE_ bool _get_alloc_size_checked(size_t p_elements, size_t *out) const {
#if defined(__GNUC__)
size_t o;
size_t p;
if (__builtin_mul_overflow(p_elements, sizeof(T), &o)) {
*out = 0;
return false;
}
*out = next_po2(o);
if (__builtin_add_overflow(o, static_cast<USize>(32), &p)) {
*out = next_power_of_2(o);
if (__builtin_add_overflow(o, static_cast<size_t>(32), &p)) {
return false; // No longer allocated here.
}
return true;
#else
// Speed is more important than correctness here, do the operations unchecked
// and hope for the best.
*out = _get_alloc_size(p_elements);
return true;
#endif
return *out;
}
void _unref(void *p_data);
void _ref(const CowData *p_from);
void _ref(const CowData &p_from);
USize _copy_on_write();
uint32_t _copy_on_write();
public:
void operator=(const CowData<T> &p_from) { _ref(p_from); }
_FORCE_INLINE_ T *ptrw() {
_copy_on_write();
return _ptr;
return (T *)_get_data();
}
_FORCE_INLINE_ const T *ptr() const {
return _ptr;
return _get_data();
}
_FORCE_INLINE_ Size size() const {
USize *size = (USize *)_get_size();
_FORCE_INLINE_ int size() const {
uint32_t *size = (uint32_t *)_get_size();
if (size) {
return *size;
} else {
@@ -196,42 +144,41 @@ public:
_FORCE_INLINE_ void clear() { resize(0); }
_FORCE_INLINE_ bool is_empty() const { return _ptr == nullptr; }
_FORCE_INLINE_ void set(Size p_index, const T &p_elem) {
_FORCE_INLINE_ void set(int p_index, const T &p_elem) {
ERR_FAIL_INDEX(p_index, size());
_copy_on_write();
_ptr[p_index] = p_elem;
_get_data()[p_index] = p_elem;
}
_FORCE_INLINE_ T &get_m(Size p_index) {
_FORCE_INLINE_ T &get_m(int p_index) {
CRASH_BAD_INDEX(p_index, size());
_copy_on_write();
return _ptr[p_index];
return _get_data()[p_index];
}
_FORCE_INLINE_ const T &get(Size p_index) const {
_FORCE_INLINE_ const T &get(int p_index) const {
CRASH_BAD_INDEX(p_index, size());
return _ptr[p_index];
return _get_data()[p_index];
}
template <bool p_ensure_zero = false>
Error resize(Size p_size);
Error resize(int p_size);
_FORCE_INLINE_ void remove_at(Size p_index) {
_FORCE_INLINE_ void remove_at(int p_index) {
ERR_FAIL_INDEX(p_index, size());
T *p = ptrw();
Size len = size();
for (Size i = p_index; i < len - 1; i++) {
int len = size();
for (int i = p_index; i < len - 1; i++) {
p[i] = p[i + 1];
}
resize(len - 1);
}
Error insert(Size p_pos, const T &p_val) {
Error insert(int 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--) {
for (int i = (size() - 1); i > p_pos; i--) {
set(i, get(i - 1));
}
set(p_pos, p_val);
@@ -239,88 +186,83 @@ public:
return OK;
}
Size find(const T &p_val, Size p_from = 0) const;
Size rfind(const T &p_val, Size p_from = -1) const;
Size count(const T &p_val) const;
int find(const T &p_val, int p_from = 0) const;
_FORCE_INLINE_ CowData() {}
_FORCE_INLINE_ ~CowData();
_FORCE_INLINE_ CowData(CowData<T> &p_from) { _ref(p_from); };
_FORCE_INLINE_ CowData(CowData<T> &p_from) { _ref(p_from); }
};
template <typename T>
template <class T>
void CowData<T>::_unref(void *p_data) {
if (!p_data) {
return;
}
SafeNumeric<USize> *refc = _get_refcount();
SafeNumeric<uint32_t> *refc = _get_refcount();
if (refc->decrement() > 0) {
return; // still in use
}
// clean up
if constexpr (!std::is_trivially_destructible_v<T>) {
USize *count = _get_size();
if (!__has_trivial_destructor(T)) {
uint32_t *count = _get_size();
T *data = (T *)(count + 1);
for (USize i = 0; i < *count; ++i) {
for (uint32_t i = 0; i < *count; ++i) {
// call destructors
data[i].~T();
}
}
// free mem
Memory::free_static(((uint8_t *)p_data) - DATA_OFFSET, false);
Memory::free_static((uint8_t *)p_data, true);
}
template <typename T>
typename CowData<T>::USize CowData<T>::_copy_on_write() {
template <class T>
uint32_t CowData<T>::_copy_on_write() {
if (!_ptr) {
return 0;
}
SafeNumeric<USize> *refc = _get_refcount();
SafeNumeric<uint32_t> *refc = _get_refcount();
USize rc = refc->get();
uint32_t rc = refc->get();
if (unlikely(rc > 1)) {
/* in use by more than me */
USize current_size = *_get_size();
uint32_t current_size = *_get_size();
uint8_t *mem_new = (uint8_t *)Memory::alloc_static(_get_alloc_size(current_size) + DATA_OFFSET, false);
ERR_FAIL_NULL_V(mem_new, 0);
uint32_t *mem_new = (uint32_t *)Memory::alloc_static(_get_alloc_size(current_size), true);
SafeNumeric<USize> *_refc_ptr = _get_refcount_ptr(mem_new);
USize *_size_ptr = _get_size_ptr(mem_new);
T *_data_ptr = _get_data_ptr(mem_new);
new (mem_new - 2) SafeNumeric<uint32_t>(1); // refcount
*(mem_new - 1) = current_size; // size
new (_refc_ptr) SafeNumeric<USize>(1); //refcount
*(_size_ptr) = current_size; //size
T *_data = (T *)(mem_new);
// initialize new elements
if constexpr (std::is_trivially_copyable_v<T>) {
memcpy((uint8_t *)_data_ptr, _ptr, current_size * sizeof(T));
if (__has_trivial_copy(T)) {
memcpy(mem_new, _ptr, current_size * sizeof(T));
} else {
for (USize i = 0; i < current_size; i++) {
memnew_placement(&_data_ptr[i], T(_ptr[i]));
for (uint32_t i = 0; i < current_size; i++) {
memnew_placement(&_data[i], T(_get_data()[i]));
}
}
_unref(_ptr);
_ptr = _data_ptr;
_ptr = _data;
rc = 1;
}
return rc;
}
template <typename T>
template <bool p_ensure_zero>
Error CowData<T>::resize(Size p_size) {
template <class T>
Error CowData<T>::resize(int p_size) {
ERR_FAIL_COND_V(p_size < 0, ERR_INVALID_PARAMETER);
Size current_size = size();
int current_size = size();
if (p_size == current_size) {
return OK;
@@ -334,71 +276,59 @@ Error CowData<T>::resize(Size p_size) {
}
// possibly changing size, copy on write
USize rc = _copy_on_write();
uint32_t rc = _copy_on_write();
USize current_alloc_size = _get_alloc_size(current_size);
USize alloc_size;
size_t current_alloc_size = _get_alloc_size(current_size);
size_t alloc_size;
ERR_FAIL_COND_V(!_get_alloc_size_checked(p_size, &alloc_size), ERR_OUT_OF_MEMORY);
if (p_size > current_size) {
if (alloc_size != current_alloc_size) {
if (current_size == 0) {
// alloc from scratch
uint8_t *mem_new = (uint8_t *)Memory::alloc_static(alloc_size + DATA_OFFSET, false);
ERR_FAIL_NULL_V(mem_new, ERR_OUT_OF_MEMORY);
uint32_t *ptr = (uint32_t *)Memory::alloc_static(alloc_size, true);
ERR_FAIL_COND_V(!ptr, ERR_OUT_OF_MEMORY);
*(ptr - 1) = 0; // size, currently none
new (ptr - 2) SafeNumeric<uint32_t>(1); // refcount
SafeNumeric<USize> *_refc_ptr = _get_refcount_ptr(mem_new);
USize *_size_ptr = _get_size_ptr(mem_new);
T *_data_ptr = _get_data_ptr(mem_new);
_ptr = (T *)ptr;
new (_refc_ptr) SafeNumeric<USize>(1); //refcount
*(_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);
uint32_t *_ptrnew = (uint32_t *)Memory::realloc_static(_ptr, alloc_size, true);
ERR_FAIL_COND_V(!_ptrnew, ERR_OUT_OF_MEMORY);
new (_ptrnew - 2) SafeNumeric<uint32_t>(rc); // refcount
SafeNumeric<USize> *_refc_ptr = _get_refcount_ptr(mem_new);
T *_data_ptr = _get_data_ptr(mem_new);
new (_refc_ptr) SafeNumeric<USize>(rc); //refcount
_ptr = _data_ptr;
_ptr = (T *)(_ptrnew);
}
}
// construct the newly created elements
if constexpr (!std::is_trivially_constructible_v<T>) {
for (Size i = *_get_size(); i < p_size; i++) {
memnew_placement(&_ptr[i], T);
if (!__has_trivial_constructor(T)) {
T *elems = _get_data();
for (int i = *_get_size(); i < p_size; i++) {
memnew_placement(&elems[i], T);
}
} else if (p_ensure_zero) {
memset((void *)(_ptr + current_size), 0, (p_size - current_size) * sizeof(T));
}
*_get_size() = p_size;
} else if (p_size < current_size) {
if constexpr (!std::is_trivially_destructible_v<T>) {
if (!__has_trivial_destructor(T)) {
// deinitialize no longer needed elements
for (USize i = p_size; i < *_get_size(); i++) {
T *t = &_ptr[i];
for (uint32_t i = p_size; i < *_get_size(); i++) {
T *t = &_get_data()[i];
t->~T();
}
}
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);
uint32_t *_ptrnew = (uint32_t *)Memory::realloc_static(_ptr, alloc_size, true);
ERR_FAIL_COND_V(!_ptrnew, ERR_OUT_OF_MEMORY);
new (_ptrnew - 2) SafeNumeric<uint32_t>(rc); // refcount
SafeNumeric<USize> *_refc_ptr = _get_refcount_ptr(mem_new);
T *_data_ptr = _get_data_ptr(mem_new);
new (_refc_ptr) SafeNumeric<USize>(rc); //refcount
_ptr = _data_ptr;
_ptr = (T *)(_ptrnew);
}
*_get_size() = p_size;
@@ -407,15 +337,15 @@ Error CowData<T>::resize(Size p_size) {
return OK;
}
template <typename T>
typename CowData<T>::Size CowData<T>::find(const T &p_val, Size p_from) const {
Size ret = -1;
template <class T>
int CowData<T>::find(const T &p_val, int p_from) const {
int ret = -1;
if (p_from < 0 || size() == 0) {
return ret;
}
for (Size i = p_from; i < size(); i++) {
for (int i = p_from; i < size(); i++) {
if (get(i) == p_val) {
ret = i;
break;
@@ -425,42 +355,12 @@ typename CowData<T>::Size CowData<T>::find(const T &p_val, Size p_from) const {
return ret;
}
template <typename T>
typename CowData<T>::Size CowData<T>::rfind(const T &p_val, Size p_from) const {
const Size s = size();
if (p_from < 0) {
p_from = s + p_from;
}
if (p_from < 0 || p_from >= s) {
p_from = s - 1;
}
for (Size i = p_from; i >= 0; i--) {
if (get(i) == p_val) {
return i;
}
}
return -1;
}
template <typename T>
typename CowData<T>::Size CowData<T>::count(const T &p_val) const {
Size amount = 0;
for (Size i = 0; i < size(); i++) {
if (get(i) == p_val) {
amount++;
}
}
return amount;
}
template <typename T>
template <class T>
void CowData<T>::_ref(const CowData *p_from) {
_ref(*p_from);
}
template <typename T>
template <class T>
void CowData<T>::_ref(const CowData &p_from) {
if (_ptr == p_from._ptr) {
return; // self assign, do nothing.
@@ -478,7 +378,7 @@ void CowData<T>::_ref(const CowData &p_from) {
}
}
template <typename T>
template <class T>
CowData<T>::~CowData() {
_unref(_ptr);
}

View File

@@ -52,7 +52,7 @@ namespace godot {
* The assignment operator copy the pairs from one map to the other.
*/
template <typename TKey, typename TValue>
template <class TKey, class TValue>
struct HashMapElement {
HashMapElement *next = nullptr;
HashMapElement *prev = nullptr;
@@ -62,10 +62,10 @@ struct HashMapElement {
data(p_key, p_value) {}
};
template <typename TKey, typename TValue,
typename Hasher = HashMapHasherDefault,
typename Comparator = HashMapComparatorDefault<TKey>,
typename Allocator = DefaultTypedAllocator<HashMapElement<TKey, TValue>>>
template <class TKey, class TValue,
class Hasher = HashMapHasherDefault,
class Comparator = HashMapComparatorDefault<TKey>,
class Allocator = DefaultTypedAllocator<HashMapElement<TKey, TValue>>>
class HashMap {
public:
const uint32_t MIN_CAPACITY_INDEX = 2; // Use a prime.

View File

@@ -48,9 +48,9 @@ namespace godot {
*
*/
template <typename TKey,
typename Hasher = HashMapHasherDefault,
typename Comparator = HashMapComparatorDefault<TKey>>
template <class TKey,
class Hasher = HashMapHasherDefault,
class Comparator = HashMapComparatorDefault<TKey>>
class HashSet {
public:
static constexpr uint32_t MIN_CAPACITY_INDEX = 2; // Use a prime.

View File

@@ -253,7 +253,7 @@ static _FORCE_INLINE_ uint32_t hash_djb2_one_float(double p_in, uint32_t p_prev
return ((p_prev << 5) + p_prev) + hash_one_uint64(u.i);
}
template <typename T>
template <class T>
static _FORCE_INLINE_ uint32_t hash_make_uint32_t(T p_in) {
union {
T t;
@@ -286,7 +286,7 @@ static _FORCE_INLINE_ uint64_t hash_djb2_one_64(uint64_t p_in, uint64_t p_prev =
return ((p_prev << 5) + p_prev) ^ p_in;
}
template <typename T>
template <class T>
static _FORCE_INLINE_ uint64_t hash_make_uint64_t(T p_in) {
union {
T t;
@@ -298,15 +298,15 @@ static _FORCE_INLINE_ uint64_t hash_make_uint64_t(T p_in) {
return _u._u64;
}
template <typename T>
template <class T>
class Ref;
struct HashMapHasherDefault {
// Generic hash function for any type.
template <typename T>
template <class T>
static _FORCE_INLINE_ uint32_t hash(const T *p_pointer) { return hash_one_uint64((uint64_t)p_pointer); }
template <typename T>
template <class T>
static _FORCE_INLINE_ uint32_t hash(const Ref<T> &p_ref) { return hash_one_uint64((uint64_t)p_ref.operator->()); }
static _FORCE_INLINE_ uint32_t hash(const String &p_string) { return p_string.hash(); }

View File

@@ -45,7 +45,7 @@
namespace godot {
template <typename T, typename A = DefaultAllocator>
template <class T, class A = DefaultAllocator>
class List {
struct _Data;
@@ -139,6 +139,31 @@ public:
typedef T ValueType;
struct Iterator {
_FORCE_INLINE_ T &operator*() const {
return E->get();
}
_FORCE_INLINE_ T *operator->() const { return &E->get(); }
_FORCE_INLINE_ Iterator &operator++() {
E = E->next();
return *this;
}
_FORCE_INLINE_ Iterator &operator--() {
E = E->prev();
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; }
Iterator(Element *p_E) { E = p_E; }
Iterator() {}
Iterator(const Iterator &p_it) { E = p_it.E; }
private:
Element *E = nullptr;
};
struct ConstIterator {
_FORCE_INLINE_ const T &operator*() const {
return E->get();
@@ -164,35 +189,6 @@ public:
const Element *E = nullptr;
};
struct Iterator {
_FORCE_INLINE_ T &operator*() const {
return E->get();
}
_FORCE_INLINE_ T *operator->() const { return &E->get(); }
_FORCE_INLINE_ Iterator &operator++() {
E = E->next();
return *this;
}
_FORCE_INLINE_ Iterator &operator--() {
E = E->prev();
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; }
Iterator(Element *p_E) { E = p_E; }
Iterator() {}
Iterator(const Iterator &p_it) { E = p_it.E; }
operator ConstIterator() const {
return ConstIterator(E);
}
private:
Element *E = nullptr;
};
_FORCE_INLINE_ Iterator begin() {
return Iterator(front());
}
@@ -225,7 +221,7 @@ private:
int size_cache = 0;
bool erase(const Element *p_I) {
ERR_FAIL_NULL_V(p_I, false);
ERR_FAIL_COND_V(!p_I, false);
ERR_FAIL_COND_V(p_I->data != this, false);
if (first == p_I) {
@@ -414,7 +410,7 @@ public:
/**
* find an element in the list,
*/
template <typename T_v>
template <class T_v>
Element *find(const T_v &p_val) {
Element *it = front();
while (it) {
@@ -523,14 +519,7 @@ public:
}
}
// Index operator, kept for compatibility.
_FORCE_INLINE_ T &operator[](int p_index) {
return get(p_index);
}
// Random access to elements, use with care,
// do not use for iteration.
T &get(int p_index) {
T &operator[](int p_index) {
CRASH_BAD_INDEX(p_index, size());
Element *I = front();
@@ -543,14 +532,7 @@ public:
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 {
const T &operator[](int p_index) const {
CRASH_BAD_INDEX(p_index, size());
const Element *I = front();
@@ -664,7 +646,7 @@ public:
sort_custom<Comparator<T>>();
}
template <typename C>
template <class C>
void sort_custom_inplace() {
if (size() < 2) {
return;
@@ -711,7 +693,7 @@ public:
_data->last = to;
}
template <typename C>
template <class C>
struct AuxiliaryComparator {
C compare;
_FORCE_INLINE_ bool operator()(const Element *a, const Element *b) const {
@@ -719,7 +701,7 @@ public:
}
};
template <typename C>
template <class C>
void sort_custom() {
// this version uses auxiliary memory for speed.
// if you don't want to use auxiliary memory, use the in_place version

View File

@@ -31,10 +31,10 @@
#ifndef GODOT_LOCAL_VECTOR_HPP
#define GODOT_LOCAL_VECTOR_HPP
#include <godot_cpp/core/error_macros.hpp>
#include <godot_cpp/core/memory.hpp>
#include <godot_cpp/templates/sort_array.hpp>
#include <godot_cpp/templates/vector.hpp>
#include "godot_cpp/core/error_macros.hpp"
#include "godot_cpp/core/memory.hpp"
#include "godot_cpp/templates/sort_array.hpp"
#include "godot_cpp/templates/vector.hpp"
#include <initializer_list>
#include <type_traits>
@@ -43,7 +43,7 @@ namespace godot {
// If tight, it grows strictly as much as needed.
// Otherwise, it grows exponentially (the default and what you want in most cases).
template <typename T, typename U = uint32_t, bool force_trivial = false, bool tight = false>
template <class T, class U = uint32_t, bool force_trivial = false, bool tight = false>
class LocalVector {
private:
U count = 0;
@@ -257,11 +257,7 @@ public:
return -1;
}
bool has(const T &p_val) const {
return find(p_val) != -1;
}
template <typename C>
template <class C>
void sort_custom() {
U len = count;
if (len == 0) {
@@ -335,7 +331,7 @@ public:
}
};
template <typename T, typename U = uint32_t, bool force_trivial = false>
template <class T, class U = uint32_t, bool force_trivial = false>
using TightLocalVector = LocalVector<T, U, force_trivial, true>;
} // namespace godot

View File

@@ -33,7 +33,7 @@
namespace godot {
template <typename F, typename S>
template <class F, class S>
struct Pair {
F first;
S second;
@@ -49,17 +49,17 @@ struct Pair {
}
};
template <typename F, typename S>
template <class F, class S>
bool operator==(const Pair<F, S> &pair, const Pair<F, S> &other) {
return (pair.first == other.first) && (pair.second == other.second);
}
template <typename F, typename S>
template <class F, class S>
bool operator!=(const Pair<F, S> &pair, const Pair<F, S> &other) {
return (pair.first != other.first) || (pair.second != other.second);
}
template <typename F, typename S>
template <class F, class S>
struct PairSort {
bool operator()(const Pair<F, S> &A, const Pair<F, S> &B) const {
if (A.first != B.first) {
@@ -69,7 +69,7 @@ struct PairSort {
}
};
template <typename K, typename V>
template <class K, class V>
struct KeyValue {
const K key;
V value;
@@ -85,17 +85,17 @@ struct KeyValue {
}
};
template <typename K, typename V>
template <class K, class V>
bool operator==(const KeyValue<K, V> &pair, const KeyValue<K, V> &other) {
return (pair.key == other.key) && (pair.value == other.value);
}
template <typename K, typename V>
template <class K, class V>
bool operator!=(const KeyValue<K, V> &pair, const KeyValue<K, V> &other) {
return (pair.key != other.key) || (pair.value != other.value);
}
template <typename K, typename V>
template <class K, class V>
struct KeyValueSort {
bool operator()(const KeyValue<K, V> &A, const KeyValue<K, V> &B) const {
return A.key < B.key;

View File

@@ -40,7 +40,7 @@ namespace godot {
// 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
template <typename K, typename V, typename C = Comparator<K>, typename A = DefaultAllocator>
template <class K, class V, class C = Comparator<K>, class A = DefaultAllocator>
class RBMap {
enum Color {
RED,

View File

@@ -38,7 +38,7 @@
namespace godot {
template <typename T, typename C = Comparator<T>, typename A = DefaultAllocator>
template <class T, class C = Comparator<T>, class A = DefaultAllocator>
class RBSet {
enum Color {
RED,

View File

@@ -42,7 +42,7 @@
namespace godot {
template <typename T, bool THREAD_SAFE = false>
template <class T, bool THREAD_SAFE = false>
class RID_Alloc {
T **chunks = nullptr;
uint32_t **free_list_chunks = nullptr;
@@ -186,12 +186,12 @@ public:
}
void initialize_rid(RID p_rid) {
T *mem = get_or_null(p_rid, true);
ERR_FAIL_NULL(mem);
ERR_FAIL_COND(!mem);
memnew_placement(mem, T);
}
void initialize_rid(RID p_rid, const T &p_value) {
T *mem = get_or_null(p_rid, true);
ERR_FAIL_NULL(mem);
ERR_FAIL_COND(!mem);
memnew_placement(mem, T(p_value));
}
@@ -347,7 +347,7 @@ public:
}
};
template <typename T, bool THREAD_SAFE = false>
template <class T, bool THREAD_SAFE = false>
class RID_PtrOwner {
RID_Alloc<T *, THREAD_SAFE> alloc;
@@ -374,7 +374,7 @@ public:
_FORCE_INLINE_ void replace(const RID &p_rid, T *p_new_ptr) {
T **ptr = alloc.get_or_null(p_rid);
ERR_FAIL_NULL(ptr);
ERR_FAIL_COND(!ptr);
*ptr = p_new_ptr;
}
@@ -406,7 +406,7 @@ public:
alloc(p_target_chunk_byte_size) {}
};
template <typename T, bool THREAD_SAFE = false>
template <class T, bool THREAD_SAFE = false>
class RID_Owner {
RID_Alloc<T, THREAD_SAFE> alloc;

View File

@@ -48,16 +48,7 @@ namespace godot {
// value and, as an important benefit, you can be sure the value is properly synchronized
// even with threads that are already running.
// These are used in very specific areas of the engine where it's critical that these guarantees are held
#define SAFE_NUMERIC_TYPE_PUN_GUARANTEES(m_type) \
static_assert(sizeof(SafeNumeric<m_type>) == sizeof(m_type)); \
static_assert(alignof(SafeNumeric<m_type>) == alignof(m_type)); \
static_assert(std::is_trivially_destructible<std::atomic<m_type>>::value);
#define SAFE_FLAG_TYPE_PUN_GUARANTEES \
static_assert(sizeof(SafeFlag) == sizeof(bool)); \
static_assert(alignof(SafeFlag) == alignof(bool));
template <typename T>
template <class T>
class SafeNumeric {
std::atomic<T> value;
@@ -132,7 +123,7 @@ public:
}
}
_ALWAYS_INLINE_ explicit SafeNumeric(T p_value = static_cast<T>(0)) {
_ALWAYS_INLINE_ explicit SafeNumeric<T>(T p_value = static_cast<T>(0)) {
set(p_value);
}
};
@@ -195,7 +186,7 @@ public:
#else
template <typename T>
template <class T>
class SafeNumeric {
protected:
T value;

View File

@@ -35,7 +35,7 @@
namespace godot {
template <typename T, typename Comparator = _DefaultComparator<T>>
template <class T, class Comparator = _DefaultComparator<T>>
class SearchArray {
public:
Comparator compare;

View File

@@ -36,7 +36,7 @@
namespace godot {
template <typename T>
template <class T>
class SelfList {
public:
class List {

View File

@@ -41,7 +41,7 @@ namespace godot {
break; \
}
template <typename T>
template <class T>
struct _DefaultComparator {
_FORCE_INLINE_ bool operator()(const T &a, const T &b) const { return (a < b); }
};
@@ -52,7 +52,7 @@ struct _DefaultComparator {
#define SORT_ARRAY_VALIDATE_ENABLED false
#endif
template <typename T, typename Comparator = _DefaultComparator<T>, bool Validate = SORT_ARRAY_VALIDATE_ENABLED>
template <class T, class Comparator = _DefaultComparator<T>, bool Validate = SORT_ARRAY_VALIDATE_ENABLED>
class SortArray {
enum {
INTROSORT_THRESHOLD = 16

View File

@@ -52,7 +52,7 @@ class ThreadWorkPool {
virtual ~BaseWork() = default;
};
template <typename C, typename M, typename U>
template <class C, class M, class U>
struct Work : public BaseWork {
C *instance;
M method;
@@ -94,9 +94,9 @@ class ThreadWorkPool {
}
public:
template <typename C, typename M, typename U>
template <class C, class M, class U>
void begin_work(uint32_t p_elements, C *p_instance, M p_method, U p_userdata) {
ERR_FAIL_NULL(threads); // Never initialized.
ERR_FAIL_COND(!threads); // never initialized
ERR_FAIL_COND(current_work != nullptr);
index.store(0, std::memory_order_release);
@@ -123,18 +123,18 @@ public:
}
bool is_done_dispatching() const {
ERR_FAIL_NULL_V(current_work, true);
ERR_FAIL_COND_V(current_work == nullptr, true);
return index.load(std::memory_order_acquire) >= current_work->max_elements;
}
uint32_t get_work_index() const {
ERR_FAIL_NULL_V(current_work, 0);
ERR_FAIL_COND_V(current_work == nullptr, 0);
uint32_t idx = index.load(std::memory_order_acquire);
return Math::min(idx, current_work->max_elements);
}
void end_work() {
ERR_FAIL_NULL(current_work);
ERR_FAIL_COND(current_work == nullptr);
for (uint32_t i = 0; i < threads_working; i++) {
threads[i].completed.wait();
threads[i].work = nullptr;
@@ -145,7 +145,7 @@ public:
current_work = nullptr;
}
template <typename C, typename M, typename U>
template <class C, class M, class U>
void do_work(uint32_t p_elements, C *p_instance, M p_method, U p_userdata) {
switch (p_elements) {
case 0:

View File

@@ -47,42 +47,38 @@
namespace godot {
template <typename T>
template <class T>
class VectorWriteProxy {
public:
_FORCE_INLINE_ T &operator[](typename CowData<T>::Size p_index) {
_FORCE_INLINE_ T &operator[](int p_index) {
CRASH_BAD_INDEX(p_index, ((Vector<T> *)(this))->_cowdata.size());
return ((Vector<T> *)(this))->_cowdata.ptrw()[p_index];
}
};
template <typename T>
template <class T>
class Vector {
friend class VectorWriteProxy<T>;
public:
VectorWriteProxy<T> write;
typedef typename CowData<T>::Size Size;
private:
CowData<T> _cowdata;
public:
bool push_back(T p_elem);
_FORCE_INLINE_ bool append(const T &p_elem) { return push_back(p_elem); } //alias
_FORCE_INLINE_ bool append(const T &p_elem) { return push_back(p_elem); } // alias
void fill(T p_elem);
void remove_at(Size p_index) { _cowdata.remove_at(p_index); }
_FORCE_INLINE_ bool erase(const T &p_val) {
Size idx = find(p_val);
void remove_at(int p_index) { _cowdata.remove_at(p_index); }
void erase(const T &p_val) {
int idx = find(p_val);
if (idx >= 0) {
remove_at(idx);
return true;
}
return false;
}
void reverse();
_FORCE_INLINE_ T *ptrw() { return _cowdata.ptrw(); }
@@ -90,45 +86,37 @@ public:
_FORCE_INLINE_ void clear() { resize(0); }
_FORCE_INLINE_ bool is_empty() const { return _cowdata.is_empty(); }
_FORCE_INLINE_ T get(Size p_index) { return _cowdata.get(p_index); }
_FORCE_INLINE_ const T &get(Size p_index) const { return _cowdata.get(p_index); }
_FORCE_INLINE_ void set(Size p_index, const T &p_elem) { _cowdata.set(p_index, p_elem); }
_FORCE_INLINE_ Size size() const { return _cowdata.size(); }
Error resize(Size p_size) { return _cowdata.resize(p_size); }
Error resize_zeroed(Size p_size) { return _cowdata.template resize<true>(p_size); }
_FORCE_INLINE_ const T &operator[](Size p_index) const { return _cowdata.get(p_index); }
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); }
_FORCE_INLINE_ T get(int p_index) { return _cowdata.get(p_index); }
_FORCE_INLINE_ const T &get(int p_index) const { return _cowdata.get(p_index); }
_FORCE_INLINE_ void set(int p_index, const T &p_elem) { _cowdata.set(p_index, p_elem); }
_FORCE_INLINE_ int size() const { return _cowdata.size(); }
Error resize(int p_size) { return _cowdata.resize(p_size); }
_FORCE_INLINE_ const T &operator[](int p_index) const { return _cowdata.get(p_index); }
Error insert(int p_pos, T p_val) { return _cowdata.insert(p_pos, p_val); }
int find(const T &p_val, int p_from = 0) const { return _cowdata.find(p_val, p_from); }
void append_array(Vector<T> p_other);
_FORCE_INLINE_ bool has(const T &p_val) const { return find(p_val) != -1; }
void sort() {
sort_custom<_DefaultComparator<T>>();
}
template <typename Comparator, bool Validate = SORT_ARRAY_VALIDATE_ENABLED, typename... Args>
void sort_custom(Args &&...args) {
Size len = _cowdata.size();
template <class C>
void sort_custom() {
int len = _cowdata.size();
if (len == 0) {
return;
}
T *data = ptrw();
SortArray<T, Comparator, Validate> sorter{ args... };
SortArray<T, C> sorter;
sorter.sort(data, len);
}
Size bsearch(const T &p_value, bool p_before) {
return bsearch_custom<_DefaultComparator<T>>(p_value, p_before);
void sort() {
sort_custom<_DefaultComparator<T>>();
}
template <typename Comparator, typename Value, typename... Args>
Size bsearch_custom(const Value &p_value, bool p_before, Args &&...args) {
SearchArray<T, Comparator> search{ args... };
int bsearch(const T &p_value, bool p_before) {
SearchArray<T> search;
return search.bisect(ptrw(), size(), p_value, p_before);
}
@@ -137,7 +125,7 @@ public:
}
void ordered_insert(const T &p_val) {
Size i;
int i;
for (i = 0; i < _cowdata.size(); i++) {
if (p_val < operator[](i)) {
break;
@@ -152,36 +140,33 @@ public:
Vector<uint8_t> to_byte_array() const {
Vector<uint8_t> ret;
if (is_empty()) {
return ret;
}
ret.resize(size() * sizeof(T));
memcpy(ret.ptrw(), ptr(), sizeof(T) * size());
return ret;
}
Vector<T> slice(Size p_begin, Size p_end = CowData<T>::MAX_INT) const {
Vector<T> slice(int p_begin, int p_end = INT_MAX) const {
Vector<T> result;
const Size s = size();
const int s = size();
Size begin = CLAMP(p_begin, -s, s);
int begin = Math::clamp(p_begin, -s, s);
if (begin < 0) {
begin += s;
}
Size end = CLAMP(p_end, -s, s);
int end = Math::clamp(p_end, -s, s);
if (end < 0) {
end += s;
}
ERR_FAIL_COND_V(begin > end, result);
Size result_size = end - begin;
int result_size = end - begin;
result.resize(result_size);
const T *const r = ptr();
T *const w = result.ptrw();
for (Size i = 0; i < result_size; ++i) {
for (int i = 0; i < result_size; ++i) {
w[i] = r[begin + i];
}
@@ -189,11 +174,11 @@ public:
}
bool operator==(const Vector<T> &p_arr) const {
Size s = size();
int s = size();
if (s != p_arr.size()) {
return false;
}
for (Size i = 0; i < s; i++) {
for (int i = 0; i < s; i++) {
if (operator[](i) != p_arr[i]) {
return false;
}
@@ -202,11 +187,11 @@ public:
}
bool operator!=(const Vector<T> &p_arr) const {
Size s = size();
int s = size();
if (s != p_arr.size()) {
return true;
}
for (Size i = 0; i < s; i++) {
for (int i = 0; i < s; i++) {
if (operator[](i) != p_arr[i]) {
return true;
}
@@ -283,7 +268,7 @@ public:
Error err = _cowdata.resize(p_init.size());
ERR_FAIL_COND(err);
Size i = 0;
int i = 0;
for (const T &element : p_init) {
_cowdata.set(i++, element);
}
@@ -293,28 +278,28 @@ public:
_FORCE_INLINE_ ~Vector() {}
};
template <typename T>
template <class T>
void Vector<T>::reverse() {
for (Size i = 0; i < size() / 2; i++) {
for (int i = 0; i < size() / 2; i++) {
T *p = ptrw();
SWAP(p[i], p[size() - i - 1]);
}
}
template <typename T>
template <class T>
void Vector<T>::append_array(Vector<T> p_other) {
const Size ds = p_other.size();
const int ds = p_other.size();
if (ds == 0) {
return;
}
const Size bs = size();
const int bs = size();
resize(bs + ds);
for (Size i = 0; i < ds; ++i) {
for (int i = 0; i < ds; ++i) {
ptrw()[bs + i] = p_other[i];
}
}
template <typename T>
template <class T>
bool Vector<T>::push_back(T p_elem) {
Error err = resize(size() + 1);
ERR_FAIL_COND_V(err, true);
@@ -323,10 +308,10 @@ bool Vector<T>::push_back(T p_elem) {
return false;
}
template <typename T>
template <class T>
void Vector<T>::fill(T p_elem) {
T *p = ptrw();
for (Size i = 0; i < size(); i++) {
for (int i = 0; i < size(); i++) {
p[i] = p_elem;
}
}

View File

@@ -35,7 +35,7 @@
namespace godot {
template <typename T, typename V>
template <class T, class V>
class VMap {
public:
struct Pair {

View File

@@ -35,7 +35,7 @@
namespace godot {
template <typename T>
template <class T>
class VSet {
Vector<T> _data;

View File

@@ -43,7 +43,7 @@ namespace godot {
class Variant;
struct [[nodiscard]] AABB {
struct _NO_DISCARD_ AABB {
Vector3 position;
Vector3 size;
@@ -65,7 +65,6 @@ struct [[nodiscard]] AABB {
bool operator!=(const AABB &p_rval) const;
bool is_equal_approx(const AABB &p_aabb) const;
bool is_finite() const;
_FORCE_INLINE_ bool intersects(const AABB &p_aabb) const; /// Both AABBs overlap
_FORCE_INLINE_ bool intersects_inclusive(const AABB &p_aabb) const; /// Both AABBs (or their faces) overlap
_FORCE_INLINE_ bool encloses(const AABB &p_aabb) const; /// p_aabb is completely inside this
@@ -103,7 +102,7 @@ struct [[nodiscard]] AABB {
_FORCE_INLINE_ void expand_to(const Vector3 &p_vector); /** expand to contain a point if necessary */
_FORCE_INLINE_ AABB abs() const {
return AABB(position + size.minf(0), size.abs());
return AABB(Vector3(position.x + MIN(size.x, (real_t)0), position.y + MIN(size.y, (real_t)0), position.z + MIN(size.z, (real_t)0)), size.abs());
}
Variant intersects_segment_bind(const Vector3 &p_from, const Vector3 &p_to) const;
@@ -202,11 +201,11 @@ inline bool AABB::encloses(const AABB &p_aabb) const {
return (
(src_min.x <= dst_min.x) &&
(src_max.x >= dst_max.x) &&
(src_max.x > dst_max.x) &&
(src_min.y <= dst_min.y) &&
(src_max.y >= dst_max.y) &&
(src_max.y > dst_max.y) &&
(src_min.z <= dst_min.z) &&
(src_max.z >= dst_max.z));
(src_max.z > dst_max.z));
}
Vector3 AABB::get_support(const Vector3 &p_normal) const {

View File

@@ -28,9 +28,6 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#ifndef GODOT_ARRAY_HELPERS_HPP
#define GODOT_ARRAY_HELPERS_HPP
namespace godot {
namespace helpers {
template <typename T, typename ValueT>
@@ -51,5 +48,3 @@ T append_all(T appendable) {
}
} // namespace helpers
} // namespace godot
#endif // GODOT_ARRAY_HELPERS_HPP

View File

@@ -37,7 +37,7 @@
namespace godot {
struct [[nodiscard]] Basis {
struct _NO_DISCARD_ Basis {
Vector3 rows[3] = {
Vector3(1, 0, 0),
Vector3(0, 1, 0),
@@ -128,7 +128,6 @@ struct [[nodiscard]] Basis {
}
bool is_equal_approx(const Basis &p_basis) const;
bool is_finite() const;
bool operator==(const Basis &p_matrix) const;
bool operator!=(const Basis &p_matrix) const;
@@ -224,7 +223,7 @@ struct [[nodiscard]] Basis {
operator Quaternion() const { return get_quaternion(); }
static Basis looking_at(const Vector3 &p_target, const Vector3 &p_up = Vector3(0, 1, 0), bool p_use_model_front = false);
static Basis looking_at(const Vector3 &p_target, const Vector3 &p_up = Vector3(0, 1, 0));
Basis(const Quaternion &p_quaternion) { set_quaternion(p_quaternion); }
Basis(const Quaternion &p_quaternion, const Vector3 &p_scale) { set_quaternion_scale(p_quaternion, p_scale); }

View File

@@ -1,65 +0,0 @@
/**************************************************************************/
/* callable_custom.hpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* 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 GODOT_CALLABLE_CUSTOM_HPP
#define GODOT_CALLABLE_CUSTOM_HPP
#include <godot_cpp/core/object_id.hpp>
#include <godot_cpp/variant/string_name.hpp>
namespace godot {
class Object;
class CallableCustomBase {
public:
virtual ObjectID get_object() const = 0;
virtual int get_argument_count(bool &r_is_valid) const;
virtual void call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, GDExtensionCallError &r_call_error) const = 0;
virtual ~CallableCustomBase() {}
};
class CallableCustom : public CallableCustomBase {
public:
typedef bool (*CompareEqualFunc)(const CallableCustom *p_a, const CallableCustom *p_b);
typedef bool (*CompareLessFunc)(const CallableCustom *p_a, const CallableCustom *p_b);
virtual uint32_t hash() const = 0;
virtual String get_as_text() const = 0;
virtual CompareEqualFunc get_compare_equal_func() const = 0;
virtual CompareLessFunc get_compare_less_func() const = 0;
virtual bool is_valid() const;
virtual ObjectID get_object() const = 0;
virtual void call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, GDExtensionCallError &r_call_error) const = 0;
};
} // namespace godot
#endif // GODOT_CALLABLE_CUSTOM_HPP

View File

@@ -1,273 +0,0 @@
/**************************************************************************/
/* callable_method_pointer.hpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* 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 GODOT_CALLABLE_METHOD_POINTER_HPP
#define GODOT_CALLABLE_METHOD_POINTER_HPP
#include <godot_cpp/core/binder_common.hpp>
#include <godot_cpp/variant/variant.hpp>
namespace godot {
class CallableCustomMethodPointerBase : public CallableCustomBase {
uint32_t *comp_ptr = nullptr;
uint32_t comp_size;
uint32_t h;
protected:
void _setup(uint32_t *p_base_ptr, uint32_t p_ptr_size);
public:
_FORCE_INLINE_ const uint32_t *get_comp_ptr() const { return comp_ptr; }
_FORCE_INLINE_ uint32_t get_comp_size() const { return comp_size; }
_FORCE_INLINE_ uint32_t get_hash() const { return h; }
};
namespace internal {
Callable create_callable_from_ccmp(CallableCustomMethodPointerBase *p_callable_method_pointer);
} // namespace internal
//
// No return value.
//
template <typename T, typename... P>
class CallableCustomMethodPointer : public CallableCustomMethodPointerBase {
struct Data {
T *instance;
void (T::*method)(P...);
} data;
static_assert(sizeof(Data) % 4 == 0);
public:
virtual ObjectID get_object() const override {
return ObjectID(data.instance->get_instance_id());
}
virtual int get_argument_count(bool &r_is_valid) const override {
r_is_valid = true;
return sizeof...(P);
}
virtual void call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, GDExtensionCallError &r_call_error) const override {
call_with_variant_args(data.instance, data.method, p_arguments, p_argcount, r_call_error);
}
CallableCustomMethodPointer(T *p_instance, void (T::*p_method)(P...)) {
memset(&data, 0, sizeof(Data));
data.instance = p_instance;
data.method = p_method;
_setup((uint32_t *)&data, sizeof(Data));
}
};
template <typename T, typename... P>
Callable create_custom_callable_function_pointer(T *p_instance, void (T::*p_method)(P...)) {
typedef CallableCustomMethodPointer<T, P...> CCMP;
CCMP *ccmp = memnew(CCMP(p_instance, p_method));
return ::godot::internal::create_callable_from_ccmp(ccmp);
}
//
// With return value.
//
template <typename T, typename R, typename... P>
class CallableCustomMethodPointerRet : public CallableCustomMethodPointerBase {
struct Data {
T *instance;
R(T::*method)
(P...);
} data;
static_assert(sizeof(Data) % 4 == 0);
public:
virtual ObjectID get_object() const override {
return ObjectID(data.instance->get_instance_id());
}
virtual int get_argument_count(bool &r_is_valid) const override {
r_is_valid = true;
return sizeof...(P);
}
virtual void call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, GDExtensionCallError &r_call_error) const override {
call_with_variant_args_ret(data.instance, data.method, p_arguments, p_argcount, r_return_value, r_call_error);
}
CallableCustomMethodPointerRet(T *p_instance, R (T::*p_method)(P...)) {
memset(&data, 0, sizeof(Data));
data.instance = p_instance;
data.method = p_method;
_setup((uint32_t *)&data, sizeof(Data));
}
};
template <typename T, typename R, typename... P>
Callable create_custom_callable_function_pointer(T *p_instance, R (T::*p_method)(P...)) {
typedef CallableCustomMethodPointerRet<T, R, P...> CCMP; // Messes with memnew otherwise.
CCMP *ccmp = memnew(CCMP(p_instance, p_method));
return ::godot::internal::create_callable_from_ccmp(ccmp);
}
//
// Const with return value.
//
template <typename T, typename R, typename... P>
class CallableCustomMethodPointerRetC : public CallableCustomMethodPointerBase {
struct Data {
T *instance;
R(T::*method)
(P...) const;
} data;
static_assert(sizeof(Data) % 4 == 0);
public:
virtual ObjectID get_object() const override {
return ObjectID(data.instance->get_instance_id());
}
virtual int get_argument_count(bool &r_is_valid) const override {
r_is_valid = true;
return sizeof...(P);
}
virtual void call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, GDExtensionCallError &r_call_error) const override {
call_with_variant_args_retc(data.instance, data.method, p_arguments, p_argcount, r_return_value, r_call_error);
}
CallableCustomMethodPointerRetC(const T *p_instance, R (T::*p_method)(P...) const) {
memset(&data, 0, sizeof(Data));
data.instance = const_cast<T *>(p_instance);
data.method = p_method;
_setup((uint32_t *)&data, sizeof(Data));
}
};
template <typename T, typename R, typename... P>
Callable create_custom_callable_function_pointer(const T *p_instance, R (T::*p_method)(P...) const) {
typedef CallableCustomMethodPointerRetC<T, R, P...> CCMP; // Messes with memnew otherwise.
CCMP *ccmp = memnew(CCMP(p_instance, p_method));
return ::godot::internal::create_callable_from_ccmp(ccmp);
}
//
// Static method with no return value.
//
template <typename... P>
class CallableCustomStaticMethodPointer : public CallableCustomMethodPointerBase {
struct Data {
void (*method)(P...);
} data;
static_assert(sizeof(Data) % 4 == 0);
public:
virtual ObjectID get_object() const override {
return ObjectID();
}
virtual int get_argument_count(bool &r_is_valid) const override {
r_is_valid = true;
return sizeof...(P);
}
virtual void call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, GDExtensionCallError &r_call_error) const override {
call_with_variant_args_static_ret(data.method, p_arguments, p_argcount, r_return_value, r_call_error);
r_return_value = Variant();
}
CallableCustomStaticMethodPointer(void (*p_method)(P...)) {
memset(&data, 0, sizeof(Data));
data.method = p_method;
_setup((uint32_t *)&data, sizeof(Data));
}
};
template <typename... P>
Callable create_custom_callable_static_function_pointer(void (*p_method)(P...)) {
typedef CallableCustomStaticMethodPointer<P...> CCMP;
CCMP *ccmp = memnew(CCMP(p_method));
return ::godot::internal::create_callable_from_ccmp(ccmp);
}
//
// Static method with return value.
//
template <typename R, typename... P>
class CallableCustomStaticMethodPointerRet : public CallableCustomMethodPointerBase {
struct Data {
R(*method)
(P...);
} data;
static_assert(sizeof(Data) % 4 == 0);
public:
virtual ObjectID get_object() const override {
return ObjectID();
}
virtual int get_argument_count(bool &r_is_valid) const override {
r_is_valid = true;
return sizeof...(P);
}
virtual void call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, GDExtensionCallError &r_call_error) const override {
call_with_variant_args_static_ret(data.method, p_arguments, p_argcount, r_return_value, r_call_error);
}
CallableCustomStaticMethodPointerRet(R (*p_method)(P...)) {
memset(&data, 0, sizeof(Data));
data.method = p_method;
_setup((uint32_t *)&data, sizeof(Data));
}
};
template <typename R, typename... P>
Callable create_custom_callable_static_function_pointer(R (*p_method)(P...)) {
typedef CallableCustomStaticMethodPointerRet<R, P...> CCMP;
CCMP *ccmp = memnew(CCMP(p_method));
return ::godot::internal::create_callable_from_ccmp(ccmp);
}
//
// The API:
//
#define callable_mp(I, M) ::godot::create_custom_callable_function_pointer(I, M)
#define callable_mp_static(M) ::godot::create_custom_callable_static_function_pointer(M)
} // namespace godot
#endif // GODOT_CALLABLE_METHOD_POINTER_HPP

View File

@@ -31,111 +31,82 @@
#ifndef GODOT_CHAR_STRING_HPP
#define GODOT_CHAR_STRING_HPP
#include <godot_cpp/templates/cowdata.hpp>
#include <cstddef>
#include <cstdint>
namespace godot {
template <typename T>
class CharStringT;
template <typename T>
class CharProxy {
template <typename TS>
friend class CharStringT;
const int64_t _index;
CowData<T> &_cowdata;
static inline const T _null = 0;
_FORCE_INLINE_ CharProxy(const int64_t &p_index, CowData<T> &p_cowdata) :
_index(p_index),
_cowdata(p_cowdata) {}
public:
_FORCE_INLINE_ CharProxy(const CharProxy<T> &p_other) :
_index(p_other._index),
_cowdata(p_other._cowdata) {}
_FORCE_INLINE_ operator T() const {
if (unlikely(_index == _cowdata.size())) {
return _null;
}
return _cowdata.get(_index);
}
_FORCE_INLINE_ const T *operator&() const {
return _cowdata.ptr() + _index;
}
_FORCE_INLINE_ void operator=(const T &p_other) const {
_cowdata.set(_index, p_other);
}
_FORCE_INLINE_ void operator=(const CharProxy<T> &p_other) const {
_cowdata.set(_index, p_other.operator T());
}
};
template <typename T>
class CharStringT {
class CharString {
friend class String;
CowData<T> _cowdata;
static inline const T _null = 0;
const char *_data = nullptr;
int _length = 0;
CharString(const char *str, int length);
public:
_FORCE_INLINE_ T *ptrw() { return _cowdata.ptrw(); }
_FORCE_INLINE_ const T *ptr() const { return _cowdata.ptr(); }
_FORCE_INLINE_ int64_t size() const { return _cowdata.size(); }
Error resize(int64_t p_size) { return _cowdata.resize(p_size); }
int length() const;
const char *get_data() const;
_FORCE_INLINE_ T get(int64_t p_index) const { return _cowdata.get(p_index); }
_FORCE_INLINE_ void set(int64_t p_index, const T &p_elem) { _cowdata.set(p_index, p_elem); }
_FORCE_INLINE_ const T &operator[](int64_t p_index) const {
if (unlikely(p_index == _cowdata.size())) {
return _null;
}
return _cowdata.get(p_index);
}
_FORCE_INLINE_ CharProxy<T> operator[](int64_t p_index) { return CharProxy<T>(p_index, _cowdata); }
_FORCE_INLINE_ CharStringT() {}
_FORCE_INLINE_ CharStringT(const CharStringT<T> &p_str) { _cowdata._ref(p_str._cowdata); }
_FORCE_INLINE_ void operator=(const CharStringT<T> &p_str) { _cowdata._ref(p_str._cowdata); }
_FORCE_INLINE_ CharStringT(const T *p_cstr) { copy_from(p_cstr); }
void operator=(const T *p_cstr);
bool operator<(const CharStringT<T> &p_right) const;
CharStringT<T> &operator+=(T p_char);
int64_t length() const { return size() ? size() - 1 : 0; }
const T *get_data() const;
operator const T *() const { return get_data(); };
protected:
void copy_from(const T *p_cstr);
CharString(CharString &&p_str);
void operator=(CharString &&p_str);
CharString() {}
~CharString();
};
template <>
const char *CharStringT<char>::get_data() const;
class Char16String {
friend class String;
template <>
const char16_t *CharStringT<char16_t>::get_data() const;
const char16_t *_data = nullptr;
int _length = 0;
template <>
const char32_t *CharStringT<char32_t>::get_data() const;
Char16String(const char16_t *str, int length);
template <>
const wchar_t *CharStringT<wchar_t>::get_data() const;
public:
int length() const;
const char16_t *get_data() const;
typedef CharStringT<char> CharString;
typedef CharStringT<char16_t> Char16String;
typedef CharStringT<char32_t> Char32String;
typedef CharStringT<wchar_t> CharWideString;
Char16String(Char16String &&p_str);
void operator=(Char16String &&p_str);
Char16String() {}
~Char16String();
};
class Char32String {
friend class String;
const char32_t *_data = nullptr;
int _length = 0;
Char32String(const char32_t *str, int length);
public:
int length() const;
const char32_t *get_data() const;
Char32String(Char32String &&p_str);
void operator=(Char32String &&p_str);
Char32String() {}
~Char32String();
};
class CharWideString {
friend class String;
const wchar_t *_data = nullptr;
int _length = 0;
CharWideString(const wchar_t *str, int length);
public:
int length() const;
const wchar_t *get_data() const;
CharWideString(CharWideString &&p_str);
void operator=(CharWideString &&p_str);
CharWideString() {}
~CharWideString();
};
} // namespace godot

View File

@@ -37,7 +37,7 @@ namespace godot {
class String;
struct [[nodiscard]] Color {
struct _NO_DISCARD_ Color {
union {
struct {
float r;

View File

@@ -28,9 +28,6 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#ifndef GODOT_COLOR_NAMES_INC_HPP
#define GODOT_COLOR_NAMES_INC_HPP
namespace godot {
// Names from https://en.wikipedia.org/wiki/X11_color_names
@@ -192,5 +189,3 @@ static NamedColor named_colors[] = {
};
} // namespace godot
#endif // GODOT_COLOR_NAMES_INC_HPP

View File

@@ -38,7 +38,7 @@ namespace godot {
class Variant;
struct [[nodiscard]] Plane {
struct _NO_DISCARD_ Plane {
Vector3 normal;
real_t d = 0;
@@ -77,7 +77,6 @@ struct [[nodiscard]] Plane {
Plane operator-() const { return Plane(-normal, -d); }
bool is_equal_approx(const Plane &p_plane) const;
bool is_equal_approx_any_side(const Plane &p_plane) const;
bool is_finite() const;
_FORCE_INLINE_ bool operator==(const Plane &p_plane) const;
_FORCE_INLINE_ bool operator!=(const Plane &p_plane) const;

View File

@@ -44,7 +44,7 @@ struct Rect2;
struct Transform3D;
struct Vector2;
struct [[nodiscard]] Projection {
struct _NO_DISCARD_ Projection {
enum Planes {
PLANE_NEAR,
PLANE_FAR,

View File

@@ -31,13 +31,12 @@
#ifndef GODOT_QUATERNION_HPP
#define GODOT_QUATERNION_HPP
#include <godot_cpp/classes/global_constants.hpp>
#include <godot_cpp/core/math.hpp>
#include <godot_cpp/variant/vector3.hpp>
namespace godot {
struct [[nodiscard]] Quaternion {
struct _NO_DISCARD_ Quaternion {
union {
struct {
real_t x;
@@ -48,15 +47,14 @@ struct [[nodiscard]] Quaternion {
real_t components[4] = { 0, 0, 0, 1.0 };
};
_FORCE_INLINE_ real_t &operator[](int p_idx) {
return components[p_idx];
_FORCE_INLINE_ real_t &operator[](int idx) {
return components[idx];
}
_FORCE_INLINE_ const real_t &operator[](int p_idx) const {
return components[p_idx];
_FORCE_INLINE_ const real_t &operator[](int idx) const {
return components[idx];
}
_FORCE_INLINE_ real_t length_squared() const;
bool is_equal_approx(const Quaternion &p_quaternion) const;
bool is_finite() const;
real_t length() const;
void normalize();
Quaternion normalized() const;
@@ -67,13 +65,14 @@ struct [[nodiscard]] Quaternion {
_FORCE_INLINE_ real_t dot(const Quaternion &p_q) const;
real_t angle_to(const Quaternion &p_to) const;
Vector3 get_euler(EulerOrder p_order = EulerOrder::EULER_ORDER_YXZ) const;
static Quaternion from_euler(const Vector3 &p_euler);
Vector3 get_euler_xyz() const;
Vector3 get_euler_yxz() const;
Vector3 get_euler() const { return get_euler_yxz(); }
Quaternion slerp(const Quaternion &p_to, real_t p_weight) const;
Quaternion slerpni(const Quaternion &p_to, real_t p_weight) const;
Quaternion spherical_cubic_interpolate(const Quaternion &p_b, const Quaternion &p_pre_a, const Quaternion &p_post_b, real_t p_weight) const;
Quaternion spherical_cubic_interpolate_in_time(const Quaternion &p_b, const Quaternion &p_pre_a, const Quaternion &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;
Quaternion slerp(const Quaternion &p_to, const real_t &p_weight) const;
Quaternion slerpni(const Quaternion &p_to, const real_t &p_weight) const;
Quaternion spherical_cubic_interpolate(const Quaternion &p_b, const Quaternion &p_pre_a, const Quaternion &p_post_b, const real_t &p_weight) const;
Quaternion spherical_cubic_interpolate_in_time(const Quaternion &p_b, const Quaternion &p_pre_a, const Quaternion &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 get_axis() const;
real_t get_angle() const;
@@ -89,28 +88,28 @@ struct [[nodiscard]] Quaternion {
void operator*=(const Quaternion &p_q);
Quaternion operator*(const Quaternion &p_q) const;
_FORCE_INLINE_ Vector3 xform(const Vector3 &p_v) const {
_FORCE_INLINE_ Vector3 xform(const Vector3 &v) const {
#ifdef MATH_CHECKS
ERR_FAIL_COND_V_MSG(!is_normalized(), p_v, "The quaternion " + operator String() + " must be normalized.");
ERR_FAIL_COND_V_MSG(!is_normalized(), v, "The quaternion must be normalized.");
#endif
Vector3 u(x, y, z);
Vector3 uv = u.cross(p_v);
return p_v + ((uv * w) + u.cross(uv)) * ((real_t)2);
Vector3 uv = u.cross(v);
return v + ((uv * w) + u.cross(uv)) * ((real_t)2);
}
_FORCE_INLINE_ Vector3 xform_inv(const Vector3 &p_v) const {
return inverse().xform(p_v);
_FORCE_INLINE_ Vector3 xform_inv(const Vector3 &v) const {
return inverse().xform(v);
}
_FORCE_INLINE_ void operator+=(const Quaternion &p_q);
_FORCE_INLINE_ void operator-=(const Quaternion &p_q);
_FORCE_INLINE_ void operator*=(real_t p_s);
_FORCE_INLINE_ void operator/=(real_t p_s);
_FORCE_INLINE_ Quaternion operator+(const Quaternion &p_q2) const;
_FORCE_INLINE_ Quaternion operator-(const Quaternion &p_q2) const;
_FORCE_INLINE_ void operator*=(const real_t &s);
_FORCE_INLINE_ void operator/=(const real_t &s);
_FORCE_INLINE_ Quaternion operator+(const Quaternion &q2) const;
_FORCE_INLINE_ Quaternion operator-(const Quaternion &q2) const;
_FORCE_INLINE_ Quaternion operator-() const;
_FORCE_INLINE_ Quaternion operator*(real_t p_s) const;
_FORCE_INLINE_ Quaternion operator/(real_t p_s) const;
_FORCE_INLINE_ Quaternion operator*(const real_t &s) const;
_FORCE_INLINE_ Quaternion operator/(const real_t &s) const;
_FORCE_INLINE_ bool operator==(const Quaternion &p_quaternion) const;
_FORCE_INLINE_ bool operator!=(const Quaternion &p_quaternion) const;
@@ -128,6 +127,8 @@ struct [[nodiscard]] Quaternion {
Quaternion(const Vector3 &p_axis, real_t p_angle);
Quaternion(const Vector3 &p_euler);
Quaternion(const Quaternion &p_q) :
x(p_q.x),
y(p_q.y),
@@ -142,9 +143,9 @@ struct [[nodiscard]] Quaternion {
w = p_q.w;
}
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);
Quaternion(const Vector3 &v0, const Vector3 &v1) { // Shortest arc.
Vector3 c = v0.cross(v1);
real_t d = v0.dot(v1);
if (d < -1.0f + (real_t)CMP_EPSILON) {
x = 0;
@@ -185,25 +186,25 @@ void Quaternion::operator-=(const Quaternion &p_q) {
w -= p_q.w;
}
void Quaternion::operator*=(real_t p_s) {
x *= p_s;
y *= p_s;
z *= p_s;
w *= p_s;
void Quaternion::operator*=(const real_t &s) {
x *= s;
y *= s;
z *= s;
w *= s;
}
void Quaternion::operator/=(real_t p_s) {
*this *= 1.0f / p_s;
void Quaternion::operator/=(const real_t &s) {
*this *= 1.0f / s;
}
Quaternion Quaternion::operator+(const Quaternion &p_q2) const {
Quaternion Quaternion::operator+(const Quaternion &q2) const {
const Quaternion &q1 = *this;
return Quaternion(q1.x + p_q2.x, q1.y + p_q2.y, q1.z + p_q2.z, q1.w + p_q2.w);
return Quaternion(q1.x + q2.x, q1.y + q2.y, q1.z + q2.z, q1.w + q2.w);
}
Quaternion Quaternion::operator-(const Quaternion &p_q2) const {
Quaternion Quaternion::operator-(const Quaternion &q2) const {
const Quaternion &q1 = *this;
return Quaternion(q1.x - p_q2.x, q1.y - p_q2.y, q1.z - p_q2.z, q1.w - p_q2.w);
return Quaternion(q1.x - q2.x, q1.y - q2.y, q1.z - q2.z, q1.w - q2.w);
}
Quaternion Quaternion::operator-() const {
@@ -211,12 +212,12 @@ Quaternion Quaternion::operator-() const {
return Quaternion(-q2.x, -q2.y, -q2.z, -q2.w);
}
Quaternion Quaternion::operator*(real_t p_s) const {
return Quaternion(x * p_s, y * p_s, z * p_s, w * p_s);
Quaternion Quaternion::operator*(const real_t &s) const {
return Quaternion(x * s, y * s, z * s, w * s);
}
Quaternion Quaternion::operator/(real_t p_s) const {
return *this * (1.0f / p_s);
Quaternion Quaternion::operator/(const real_t &s) const {
return *this * (1.0f / s);
}
bool Quaternion::operator==(const Quaternion &p_quaternion) const {
@@ -227,7 +228,7 @@ bool Quaternion::operator!=(const Quaternion &p_quaternion) const {
return x != p_quaternion.x || y != p_quaternion.y || z != p_quaternion.z || w != p_quaternion.w;
}
_FORCE_INLINE_ Quaternion operator*(real_t p_real, const Quaternion &p_quaternion) {
_FORCE_INLINE_ Quaternion operator*(const real_t &p_real, const Quaternion &p_quaternion) {
return p_quaternion * p_real;
}

View File

@@ -40,7 +40,7 @@ class String;
struct Rect2i;
struct Transform2D;
struct [[nodiscard]] Rect2 {
struct _NO_DISCARD_ Rect2 {
Point2 position;
Size2 size;
@@ -146,7 +146,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 instersection 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;
@@ -154,12 +154,14 @@ struct [[nodiscard]] Rect2 {
return Rect2();
}
new_rect.position = p_rect.position.max(position);
new_rect.position.x = Math::max(p_rect.position.x, position.x);
new_rect.position.y = Math::max(p_rect.position.y, position.y);
Point2 p_rect_end = p_rect.position + p_rect.size;
Point2 end = position + size;
new_rect.size = p_rect_end.min(end) - new_rect.position;
new_rect.size.x = Math::min(p_rect_end.x, end.x) - new_rect.position.x;
new_rect.size.y = Math::min(p_rect_end.y, end.y) - new_rect.position.y;
return new_rect;
}
@@ -172,9 +174,11 @@ struct [[nodiscard]] Rect2 {
#endif
Rect2 new_rect;
new_rect.position = p_rect.position.min(position);
new_rect.position.x = Math::min(p_rect.position.x, position.x);
new_rect.position.y = Math::min(p_rect.position.y, position.y);
new_rect.size = (p_rect.position + p_rect.size).max(position + size);
new_rect.size.x = Math::max(p_rect.position.x + p_rect.size.x, position.x + size.x);
new_rect.size.y = Math::max(p_rect.position.y + p_rect.size.y, position.y + size.y);
new_rect.size = new_rect.size - new_rect.position; // Make relative again.
@@ -205,7 +209,6 @@ struct [[nodiscard]] Rect2 {
}
bool is_equal_approx(const Rect2 &p_rect) const;
bool is_finite() const;
bool operator==(const Rect2 &p_rect) const { return position == p_rect.position && size == p_rect.size; }
bool operator!=(const Rect2 &p_rect) const { return position != p_rect.position || size != p_rect.size; }
@@ -280,7 +283,7 @@ struct [[nodiscard]] Rect2 {
}
_FORCE_INLINE_ Rect2 abs() const {
return Rect2(position + size.minf(0), size.abs());
return Rect2(Point2(position.x + Math::min(size.x, (real_t)0), position.y + Math::min(size.y, (real_t)0)), size.abs());
}
Vector2 get_support(const Vector2 &p_normal) const {

View File

@@ -39,7 +39,7 @@ namespace godot {
class String;
struct Rect2;
struct [[nodiscard]] Rect2i {
struct _NO_DISCARD_ Rect2i {
Point2i position;
Size2i size;
@@ -89,7 +89,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 instersection 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;
@@ -97,12 +97,14 @@ struct [[nodiscard]] Rect2i {
return Rect2i();
}
new_rect.position = p_rect.position.max(position);
new_rect.position.x = Math::max(p_rect.position.x, position.x);
new_rect.position.y = Math::max(p_rect.position.y, position.y);
Point2i p_rect_end = p_rect.position + p_rect.size;
Point2i end = position + size;
new_rect.size = p_rect_end.min(end) - new_rect.position;
new_rect.size.x = Math::min(p_rect_end.x, end.x) - new_rect.position.x;
new_rect.size.y = Math::min(p_rect_end.y, end.y) - new_rect.position.y;
return new_rect;
}
@@ -115,9 +117,11 @@ struct [[nodiscard]] Rect2i {
#endif
Rect2i new_rect;
new_rect.position = p_rect.position.min(position);
new_rect.position.x = Math::min(p_rect.position.x, position.x);
new_rect.position.y = Math::min(p_rect.position.y, position.y);
new_rect.size = (p_rect.position + p_rect.size).max(position + size);
new_rect.size.x = Math::max(p_rect.position.x + p_rect.size.x, position.x + size.x);
new_rect.size.y = Math::max(p_rect.position.y + p_rect.size.y, position.y + size.y);
new_rect.size = new_rect.size - new_rect.position; // Make relative again.
@@ -215,7 +219,7 @@ struct [[nodiscard]] Rect2i {
}
_FORCE_INLINE_ Rect2i abs() const {
return Rect2i(position + size.mini(0), size.abs());
return Rect2i(Point2i(position.x + Math::min(size.x, 0), position.y + Math::min(size.y, 0)), size.abs());
}
_FORCE_INLINE_ void set_end(const Vector2i &p_end) {

View File

@@ -39,7 +39,7 @@ namespace godot {
class String;
struct [[nodiscard]] Transform2D {
struct _NO_DISCARD_ Transform2D {
// Warning #1: 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])
@@ -99,7 +99,6 @@ struct [[nodiscard]] Transform2D {
void orthonormalize();
Transform2D orthonormalized() const;
bool is_equal_approx(const Transform2D &p_transform) const;
bool is_finite() const;
Transform2D looking_at(const Vector2 &p_target) const;

View File

@@ -39,7 +39,7 @@
namespace godot {
struct [[nodiscard]] Transform3D {
struct _NO_DISCARD_ Transform3D {
Basis basis;
Vector3 origin;
@@ -78,7 +78,6 @@ struct [[nodiscard]] Transform3D {
void orthogonalize();
Transform3D orthogonalized() const;
bool is_equal_approx(const Transform3D &p_transform) const;
bool is_finite() const;
bool operator==(const Transform3D &p_transform) const;
bool operator!=(const Transform3D &p_transform) const;

View File

@@ -36,7 +36,7 @@
namespace godot {
template <typename T>
template <class T>
class TypedArray : public Array {
public:
_FORCE_INLINE_ void operator=(const Array &p_array) {
@@ -44,15 +44,10 @@ public:
_ref(p_array);
}
_FORCE_INLINE_ TypedArray(const Variant &p_variant) :
TypedArray(Array(p_variant)) {
Array(p_variant.operator Array(), Variant::OBJECT, T::get_class_static(), Variant()) {
}
_FORCE_INLINE_ TypedArray(const Array &p_array) {
set_typed(Variant::OBJECT, T::get_class_static(), Variant());
if (is_same_typed(p_array)) {
_ref(p_array);
} else {
assign(p_array);
}
_FORCE_INLINE_ TypedArray(const Array &p_array) :
Array(p_array, Variant::OBJECT, T::get_class_static(), Variant()) {
}
_FORCE_INLINE_ TypedArray() {
set_typed(Variant::OBJECT, T::get_class_static(), Variant());
@@ -70,23 +65,16 @@ public:
_ref(p_array); \
} \
_FORCE_INLINE_ TypedArray(const Variant &p_variant) : \
TypedArray(Array(p_variant)) { \
Array(p_variant.operator Array(), m_variant_type, StringName(), Variant()) { \
} \
_FORCE_INLINE_ TypedArray(const Array &p_array) { \
set_typed(m_variant_type, StringName(), Variant()); \
if (is_same_typed(p_array)) { \
_ref(p_array); \
} else { \
assign(p_array); \
} \
_FORCE_INLINE_ TypedArray(const Array &p_array) : \
Array(p_array, m_variant_type, StringName(), Variant()) { \
} \
_FORCE_INLINE_ TypedArray() { \
set_typed(m_variant_type, StringName(), Variant()); \
} \
};
// All Variant::OBJECT types are intentionally omitted from this list because they are handled by
// the unspecialized TypedArray definition.
MAKE_TYPED_ARRAY(bool, Variant::BOOL)
MAKE_TYPED_ARRAY(uint8_t, Variant::INT)
MAKE_TYPED_ARRAY(int8_t, Variant::INT)
@@ -106,14 +94,11 @@ MAKE_TYPED_ARRAY(Rect2i, Variant::RECT2I)
MAKE_TYPED_ARRAY(Vector3, Variant::VECTOR3)
MAKE_TYPED_ARRAY(Vector3i, Variant::VECTOR3I)
MAKE_TYPED_ARRAY(Transform2D, Variant::TRANSFORM2D)
MAKE_TYPED_ARRAY(Vector4, Variant::VECTOR4)
MAKE_TYPED_ARRAY(Vector4i, Variant::VECTOR4I)
MAKE_TYPED_ARRAY(Plane, Variant::PLANE)
MAKE_TYPED_ARRAY(Quaternion, Variant::QUATERNION)
MAKE_TYPED_ARRAY(AABB, Variant::AABB)
MAKE_TYPED_ARRAY(Basis, Variant::BASIS)
MAKE_TYPED_ARRAY(Transform3D, Variant::TRANSFORM3D)
MAKE_TYPED_ARRAY(Projection, Variant::PROJECTION)
MAKE_TYPED_ARRAY(Color, Variant::COLOR)
MAKE_TYPED_ARRAY(StringName, Variant::STRING_NAME)
MAKE_TYPED_ARRAY(NodePath, Variant::NODE_PATH)
@@ -130,12 +115,7 @@ MAKE_TYPED_ARRAY(PackedFloat64Array, Variant::PACKED_FLOAT64_ARRAY)
MAKE_TYPED_ARRAY(PackedStringArray, Variant::PACKED_STRING_ARRAY)
MAKE_TYPED_ARRAY(PackedVector2Array, Variant::PACKED_VECTOR2_ARRAY)
MAKE_TYPED_ARRAY(PackedVector3Array, Variant::PACKED_VECTOR3_ARRAY)
MAKE_TYPED_ARRAY(PackedVector4Array, Variant::PACKED_VECTOR4_ARRAY)
MAKE_TYPED_ARRAY(PackedColorArray, Variant::PACKED_COLOR_ARRAY)
// If the IPAddress struct is added to godot-cpp, the following could also be added:
//MAKE_TYPED_ARRAY(IPAddress, Variant::STRING)
#undef MAKE_TYPED_ARRAY
} // namespace godot

View File

@@ -1,439 +0,0 @@
/**************************************************************************/
/* typed_dictionary.hpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* 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 GODOT_TYPED_DICTIONARY_HPP
#define GODOT_TYPED_DICTIONARY_HPP
#include <godot_cpp/core/type_info.hpp>
#include <godot_cpp/variant/dictionary.hpp>
#include <godot_cpp/variant/variant.hpp>
namespace godot {
template <typename K, typename V>
class TypedDictionary : public Dictionary {
public:
_FORCE_INLINE_ void operator=(const Dictionary &p_dictionary) {
ERR_FAIL_COND_MSG(!is_same_typed(p_dictionary), "Cannot assign a 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, K::get_class_static(), Variant(), Variant::OBJECT, V::get_class_static(), Variant());
if (is_same_typed(p_dictionary)) {
Dictionary::operator=(p_dictionary);
} else {
assign(p_dictionary);
}
}
_FORCE_INLINE_ TypedDictionary() {
set_typed(Variant::OBJECT, K::get_class_static(), Variant(), Variant::OBJECT, V::get_class_static(), Variant());
}
};
//specialization for the rest of variant types
#define MAKE_TYPED_DICTIONARY_WITH_OBJECT(m_type, m_variant_type) \
template <typename T> \
class TypedDictionary<T, m_type> : 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 <typename T> \
class TypedDictionary<m_type, T> : 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_EXPANDED(m_type_key, m_variant_type_key, m_type_value, m_variant_type_value) \
template <> \
class TypedDictionary<m_type_key, m_type_value> : 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_key, StringName(), Variant(), m_variant_type_value, StringName(), Variant()); \
if (is_same_typed(p_dictionary)) { \
Dictionary::operator=(p_dictionary); \
} else { \
assign(p_dictionary); \
} \
} \
_FORCE_INLINE_ TypedDictionary() { \
set_typed(m_variant_type_key, StringName(), Variant(), m_variant_type_value, StringName(), Variant()); \
} \
};
#define MAKE_TYPED_DICTIONARY_NIL(m_type, m_variant_type) \
MAKE_TYPED_DICTIONARY_WITH_OBJECT(m_type, m_variant_type) \
MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, bool, Variant::BOOL) \
MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, uint8_t, Variant::INT) \
MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, int8_t, Variant::INT) \
MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, uint16_t, Variant::INT) \
MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, int16_t, Variant::INT) \
MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, uint32_t, Variant::INT) \
MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, int32_t, Variant::INT) \
MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, uint64_t, Variant::INT) \
MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, int64_t, Variant::INT) \
MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, float, Variant::FLOAT) \
MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, double, Variant::FLOAT) \
MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, String, Variant::STRING) \
MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, Vector2, Variant::VECTOR2) \
MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, Vector2i, Variant::VECTOR2I) \
MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, Rect2, Variant::RECT2) \
MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, Rect2i, Variant::RECT2I) \
MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, Vector3, Variant::VECTOR3) \
MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, Vector3i, Variant::VECTOR3I) \
MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, Transform2D, Variant::TRANSFORM2D) \
MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, Plane, Variant::PLANE) \
MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, Quaternion, Variant::QUATERNION) \
MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, AABB, Variant::AABB) \
MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, Basis, Variant::BASIS) \
MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, Transform3D, Variant::TRANSFORM3D) \
MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, Color, Variant::COLOR) \
MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, StringName, Variant::STRING_NAME) \
MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, NodePath, Variant::NODE_PATH) \
MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, RID, Variant::RID) \
MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, Callable, Variant::CALLABLE) \
MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, Signal, Variant::SIGNAL) \
MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, Dictionary, Variant::DICTIONARY) \
MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, Array, Variant::ARRAY) \
MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, PackedByteArray, Variant::PACKED_BYTE_ARRAY) \
MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, PackedInt32Array, Variant::PACKED_INT32_ARRAY) \
MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, PackedInt64Array, Variant::PACKED_INT64_ARRAY) \
MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, PackedFloat32Array, Variant::PACKED_FLOAT32_ARRAY) \
MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, PackedFloat64Array, Variant::PACKED_FLOAT64_ARRAY) \
MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, PackedStringArray, Variant::PACKED_STRING_ARRAY) \
MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, PackedVector2Array, Variant::PACKED_VECTOR2_ARRAY) \
MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, PackedVector3Array, Variant::PACKED_VECTOR3_ARRAY) \
MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, PackedColorArray, Variant::PACKED_COLOR_ARRAY) \
MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, PackedVector4Array, Variant::PACKED_VECTOR4_ARRAY) \
/*MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, IPAddress, Variant::STRING)*/
#define MAKE_TYPED_DICTIONARY(m_type, m_variant_type) \
MAKE_TYPED_DICTIONARY_EXPANDED(m_type, m_variant_type, Variant, Variant::NIL) \
MAKE_TYPED_DICTIONARY_NIL(m_type, m_variant_type)
MAKE_TYPED_DICTIONARY_NIL(Variant, Variant::NIL)
MAKE_TYPED_DICTIONARY(bool, Variant::BOOL)
MAKE_TYPED_DICTIONARY(uint8_t, Variant::INT)
MAKE_TYPED_DICTIONARY(int8_t, Variant::INT)
MAKE_TYPED_DICTIONARY(uint16_t, Variant::INT)
MAKE_TYPED_DICTIONARY(int16_t, Variant::INT)
MAKE_TYPED_DICTIONARY(uint32_t, Variant::INT)
MAKE_TYPED_DICTIONARY(int32_t, Variant::INT)
MAKE_TYPED_DICTIONARY(uint64_t, Variant::INT)
MAKE_TYPED_DICTIONARY(int64_t, Variant::INT)
MAKE_TYPED_DICTIONARY(float, Variant::FLOAT)
MAKE_TYPED_DICTIONARY(double, Variant::FLOAT)
MAKE_TYPED_DICTIONARY(String, Variant::STRING)
MAKE_TYPED_DICTIONARY(Vector2, Variant::VECTOR2)
MAKE_TYPED_DICTIONARY(Vector2i, Variant::VECTOR2I)
MAKE_TYPED_DICTIONARY(Rect2, Variant::RECT2)
MAKE_TYPED_DICTIONARY(Rect2i, Variant::RECT2I)
MAKE_TYPED_DICTIONARY(Vector3, Variant::VECTOR3)
MAKE_TYPED_DICTIONARY(Vector3i, Variant::VECTOR3I)
MAKE_TYPED_DICTIONARY(Transform2D, Variant::TRANSFORM2D)
MAKE_TYPED_DICTIONARY(Plane, Variant::PLANE)
MAKE_TYPED_DICTIONARY(Quaternion, Variant::QUATERNION)
MAKE_TYPED_DICTIONARY(AABB, Variant::AABB)
MAKE_TYPED_DICTIONARY(Basis, Variant::BASIS)
MAKE_TYPED_DICTIONARY(Transform3D, Variant::TRANSFORM3D)
MAKE_TYPED_DICTIONARY(Color, Variant::COLOR)
MAKE_TYPED_DICTIONARY(StringName, Variant::STRING_NAME)
MAKE_TYPED_DICTIONARY(NodePath, Variant::NODE_PATH)
MAKE_TYPED_DICTIONARY(RID, Variant::RID)
MAKE_TYPED_DICTIONARY(Callable, Variant::CALLABLE)
MAKE_TYPED_DICTIONARY(Signal, Variant::SIGNAL)
MAKE_TYPED_DICTIONARY(Dictionary, Variant::DICTIONARY)
MAKE_TYPED_DICTIONARY(Array, Variant::ARRAY)
MAKE_TYPED_DICTIONARY(PackedByteArray, Variant::PACKED_BYTE_ARRAY)
MAKE_TYPED_DICTIONARY(PackedInt32Array, Variant::PACKED_INT32_ARRAY)
MAKE_TYPED_DICTIONARY(PackedInt64Array, Variant::PACKED_INT64_ARRAY)
MAKE_TYPED_DICTIONARY(PackedFloat32Array, Variant::PACKED_FLOAT32_ARRAY)
MAKE_TYPED_DICTIONARY(PackedFloat64Array, Variant::PACKED_FLOAT64_ARRAY)
MAKE_TYPED_DICTIONARY(PackedStringArray, Variant::PACKED_STRING_ARRAY)
MAKE_TYPED_DICTIONARY(PackedVector2Array, Variant::PACKED_VECTOR2_ARRAY)
MAKE_TYPED_DICTIONARY(PackedVector3Array, Variant::PACKED_VECTOR3_ARRAY)
MAKE_TYPED_DICTIONARY(PackedColorArray, Variant::PACKED_COLOR_ARRAY)
MAKE_TYPED_DICTIONARY(PackedVector4Array, Variant::PACKED_VECTOR4_ARRAY)
/*
MAKE_TYPED_DICTIONARY(IPAddress, Variant::STRING)
*/
#undef MAKE_TYPED_DICTIONARY
#undef MAKE_TYPED_DICTIONARY_NIL
#undef MAKE_TYPED_DICTIONARY_EXPANDED
#undef MAKE_TYPED_DICTIONARY_WITH_OBJECT
template <typename K, typename V>
struct PtrToArg<TypedDictionary<K, V>> {
_FORCE_INLINE_ static TypedDictionary<K, V> convert(const void *p_ptr) {
return TypedDictionary<K, V>(*reinterpret_cast<const Dictionary *>(p_ptr));
}
typedef Dictionary EncodeT;
_FORCE_INLINE_ static void encode(TypedDictionary<K, V> p_val, void *p_ptr) {
*(Dictionary *)p_ptr = p_val;
}
};
template <typename K, typename V>
struct PtrToArg<const TypedDictionary<K, V> &> {
typedef Dictionary EncodeT;
_FORCE_INLINE_ static TypedDictionary<K, V>
convert(const void *p_ptr) {
return TypedDictionary<K, V>(*reinterpret_cast<const Dictionary *>(p_ptr));
}
};
template <typename K, typename V>
struct GetTypeInfo<TypedDictionary<K, V>> {
static constexpr GDExtensionVariantType VARIANT_TYPE = GDEXTENSION_VARIANT_TYPE_DICTIONARY;
static constexpr GDExtensionClassMethodArgumentMetadata METADATA = GDEXTENSION_METHOD_ARGUMENT_METADATA_NONE;
static inline PropertyInfo get_class_info() {
return PropertyInfo(Variant::Type::DICTIONARY, String(), PROPERTY_HINT_DICTIONARY_TYPE, vformat("%s;%s", K::get_class_static(), V::get_class_static()));
}
};
template <typename K, typename V>
struct GetTypeInfo<const TypedDictionary<K, V> &> {
static constexpr GDExtensionVariantType VARIANT_TYPE = GDEXTENSION_VARIANT_TYPE_DICTIONARY;
static constexpr GDExtensionClassMethodArgumentMetadata METADATA = GDEXTENSION_METHOD_ARGUMENT_METADATA_NONE;
static inline PropertyInfo get_class_info() {
return PropertyInfo(Variant::Type::DICTIONARY, String(), PROPERTY_HINT_DICTIONARY_TYPE, vformat("%s;%s", K::get_class_static(), V::get_class_static()));
}
};
#define MAKE_TYPED_DICTIONARY_INFO_WITH_OBJECT(m_type, m_variant_type) \
template <typename T> \
struct GetTypeInfo<TypedDictionary<T, m_type>> { \
static constexpr GDExtensionVariantType VARIANT_TYPE = GDEXTENSION_VARIANT_TYPE_DICTIONARY; \
static constexpr GDExtensionClassMethodArgumentMetadata METADATA = GDEXTENSION_METHOD_ARGUMENT_METADATA_NONE; \
static inline PropertyInfo get_class_info() { \
return PropertyInfo(Variant::Type::DICTIONARY, String(), PROPERTY_HINT_DICTIONARY_TYPE, \
vformat("%s;%s", T::get_class_static(), m_variant_type == Variant::Type::NIL ? "Variant" : Variant::get_type_name(m_variant_type).utf8().get_data())); \
} \
}; \
template <typename T> \
struct GetTypeInfo<const TypedDictionary<T, m_type> &> { \
static constexpr GDExtensionVariantType VARIANT_TYPE = GDEXTENSION_VARIANT_TYPE_DICTIONARY; \
static constexpr GDExtensionClassMethodArgumentMetadata METADATA = GDEXTENSION_METHOD_ARGUMENT_METADATA_NONE; \
static inline PropertyInfo get_class_info() { \
return PropertyInfo(Variant::Type::DICTIONARY, String(), PROPERTY_HINT_DICTIONARY_TYPE, \
vformat("%s;%s", T::get_class_static(), m_variant_type == Variant::Type::NIL ? "Variant" : Variant::get_type_name(m_variant_type).utf8().get_data())); \
} \
}; \
template <typename T> \
struct GetTypeInfo<TypedDictionary<m_type, T>> { \
static constexpr GDExtensionVariantType VARIANT_TYPE = GDEXTENSION_VARIANT_TYPE_DICTIONARY; \
static constexpr GDExtensionClassMethodArgumentMetadata METADATA = GDEXTENSION_METHOD_ARGUMENT_METADATA_NONE; \
static inline PropertyInfo get_class_info() { \
return PropertyInfo(Variant::Type::DICTIONARY, String(), PROPERTY_HINT_DICTIONARY_TYPE, \
vformat("%s;%s", m_variant_type == Variant::Type::NIL ? "Variant" : Variant::get_type_name(m_variant_type).utf8().get_data(), T::get_class_static())); \
} \
}; \
template <typename T> \
struct GetTypeInfo<const TypedDictionary<m_type, T> &> { \
static constexpr GDExtensionVariantType VARIANT_TYPE = GDEXTENSION_VARIANT_TYPE_DICTIONARY; \
static constexpr GDExtensionClassMethodArgumentMetadata METADATA = GDEXTENSION_METHOD_ARGUMENT_METADATA_NONE; \
static inline PropertyInfo get_class_info() { \
return PropertyInfo(Variant::Type::DICTIONARY, String(), PROPERTY_HINT_DICTIONARY_TYPE, \
vformat("%s;%s", m_variant_type == Variant::Type::NIL ? "Variant" : Variant::get_type_name(m_variant_type).utf8().get_data(), T::get_class_static())); \
} \
};
#define MAKE_TYPED_DICTIONARY_INFO_EXPANDED(m_type_key, m_variant_type_key, m_type_value, m_variant_type_value) \
template <> \
struct GetTypeInfo<TypedDictionary<m_type_key, m_type_value>> { \
static constexpr GDExtensionVariantType VARIANT_TYPE = GDEXTENSION_VARIANT_TYPE_DICTIONARY; \
static constexpr GDExtensionClassMethodArgumentMetadata METADATA = GDEXTENSION_METHOD_ARGUMENT_METADATA_NONE; \
static inline PropertyInfo get_class_info() { \
return PropertyInfo(Variant::Type::DICTIONARY, String(), PROPERTY_HINT_DICTIONARY_TYPE, \
vformat("%s;%s", m_variant_type_key == Variant::Type::NIL ? "Variant" : Variant::get_type_name(m_variant_type_key).utf8().get_data(), \
m_variant_type_value == Variant::Type::NIL ? "Variant" : Variant::get_type_name(m_variant_type_value).utf8().get_data())); \
} \
}; \
template <> \
struct GetTypeInfo<const TypedDictionary<m_type_key, m_type_value> &> { \
static constexpr GDExtensionVariantType VARIANT_TYPE = GDEXTENSION_VARIANT_TYPE_DICTIONARY; \
static constexpr GDExtensionClassMethodArgumentMetadata METADATA = GDEXTENSION_METHOD_ARGUMENT_METADATA_NONE; \
static inline PropertyInfo get_class_info() { \
return PropertyInfo(Variant::Type::DICTIONARY, String(), PROPERTY_HINT_DICTIONARY_TYPE, \
vformat("%s;%s", m_variant_type_key == Variant::Type::NIL ? "Variant" : Variant::get_type_name(m_variant_type_key).utf8().get_data(), \
m_variant_type_value == Variant::Type::NIL ? "Variant" : Variant::get_type_name(m_variant_type_value).utf8().get_data())); \
} \
};
#define MAKE_TYPED_DICTIONARY_INFO_NIL(m_type, m_variant_type) \
MAKE_TYPED_DICTIONARY_INFO_WITH_OBJECT(m_type, m_variant_type) \
MAKE_TYPED_DICTIONARY_INFO_EXPANDED(m_type, m_variant_type, bool, Variant::BOOL) \
MAKE_TYPED_DICTIONARY_INFO_EXPANDED(m_type, m_variant_type, uint8_t, Variant::INT) \
MAKE_TYPED_DICTIONARY_INFO_EXPANDED(m_type, m_variant_type, int8_t, Variant::INT) \
MAKE_TYPED_DICTIONARY_INFO_EXPANDED(m_type, m_variant_type, uint16_t, Variant::INT) \
MAKE_TYPED_DICTIONARY_INFO_EXPANDED(m_type, m_variant_type, int16_t, Variant::INT) \
MAKE_TYPED_DICTIONARY_INFO_EXPANDED(m_type, m_variant_type, uint32_t, Variant::INT) \
MAKE_TYPED_DICTIONARY_INFO_EXPANDED(m_type, m_variant_type, int32_t, Variant::INT) \
MAKE_TYPED_DICTIONARY_INFO_EXPANDED(m_type, m_variant_type, uint64_t, Variant::INT) \
MAKE_TYPED_DICTIONARY_INFO_EXPANDED(m_type, m_variant_type, int64_t, Variant::INT) \
MAKE_TYPED_DICTIONARY_INFO_EXPANDED(m_type, m_variant_type, float, Variant::FLOAT) \
MAKE_TYPED_DICTIONARY_INFO_EXPANDED(m_type, m_variant_type, double, Variant::FLOAT) \
MAKE_TYPED_DICTIONARY_INFO_EXPANDED(m_type, m_variant_type, String, Variant::STRING) \
MAKE_TYPED_DICTIONARY_INFO_EXPANDED(m_type, m_variant_type, Vector2, Variant::VECTOR2) \
MAKE_TYPED_DICTIONARY_INFO_EXPANDED(m_type, m_variant_type, Vector2i, Variant::VECTOR2I) \
MAKE_TYPED_DICTIONARY_INFO_EXPANDED(m_type, m_variant_type, Rect2, Variant::RECT2) \
MAKE_TYPED_DICTIONARY_INFO_EXPANDED(m_type, m_variant_type, Rect2i, Variant::RECT2I) \
MAKE_TYPED_DICTIONARY_INFO_EXPANDED(m_type, m_variant_type, Vector3, Variant::VECTOR3) \
MAKE_TYPED_DICTIONARY_INFO_EXPANDED(m_type, m_variant_type, Vector3i, Variant::VECTOR3I) \
MAKE_TYPED_DICTIONARY_INFO_EXPANDED(m_type, m_variant_type, Transform2D, Variant::TRANSFORM2D) \
MAKE_TYPED_DICTIONARY_INFO_EXPANDED(m_type, m_variant_type, Plane, Variant::PLANE) \
MAKE_TYPED_DICTIONARY_INFO_EXPANDED(m_type, m_variant_type, Quaternion, Variant::QUATERNION) \
MAKE_TYPED_DICTIONARY_INFO_EXPANDED(m_type, m_variant_type, AABB, Variant::AABB) \
MAKE_TYPED_DICTIONARY_INFO_EXPANDED(m_type, m_variant_type, Basis, Variant::BASIS) \
MAKE_TYPED_DICTIONARY_INFO_EXPANDED(m_type, m_variant_type, Transform3D, Variant::TRANSFORM3D) \
MAKE_TYPED_DICTIONARY_INFO_EXPANDED(m_type, m_variant_type, Color, Variant::COLOR) \
MAKE_TYPED_DICTIONARY_INFO_EXPANDED(m_type, m_variant_type, StringName, Variant::STRING_NAME) \
MAKE_TYPED_DICTIONARY_INFO_EXPANDED(m_type, m_variant_type, NodePath, Variant::NODE_PATH) \
MAKE_TYPED_DICTIONARY_INFO_EXPANDED(m_type, m_variant_type, RID, Variant::RID) \
MAKE_TYPED_DICTIONARY_INFO_EXPANDED(m_type, m_variant_type, Callable, Variant::CALLABLE) \
MAKE_TYPED_DICTIONARY_INFO_EXPANDED(m_type, m_variant_type, Signal, Variant::SIGNAL) \
MAKE_TYPED_DICTIONARY_INFO_EXPANDED(m_type, m_variant_type, Dictionary, Variant::DICTIONARY) \
MAKE_TYPED_DICTIONARY_INFO_EXPANDED(m_type, m_variant_type, Array, Variant::ARRAY) \
MAKE_TYPED_DICTIONARY_INFO_EXPANDED(m_type, m_variant_type, PackedByteArray, Variant::PACKED_BYTE_ARRAY) \
MAKE_TYPED_DICTIONARY_INFO_EXPANDED(m_type, m_variant_type, PackedInt32Array, Variant::PACKED_INT32_ARRAY) \
MAKE_TYPED_DICTIONARY_INFO_EXPANDED(m_type, m_variant_type, PackedInt64Array, Variant::PACKED_INT64_ARRAY) \
MAKE_TYPED_DICTIONARY_INFO_EXPANDED(m_type, m_variant_type, PackedFloat32Array, Variant::PACKED_FLOAT32_ARRAY) \
MAKE_TYPED_DICTIONARY_INFO_EXPANDED(m_type, m_variant_type, PackedFloat64Array, Variant::PACKED_FLOAT64_ARRAY) \
MAKE_TYPED_DICTIONARY_INFO_EXPANDED(m_type, m_variant_type, PackedStringArray, Variant::PACKED_STRING_ARRAY) \
MAKE_TYPED_DICTIONARY_INFO_EXPANDED(m_type, m_variant_type, PackedVector2Array, Variant::PACKED_VECTOR2_ARRAY) \
MAKE_TYPED_DICTIONARY_INFO_EXPANDED(m_type, m_variant_type, PackedVector3Array, Variant::PACKED_VECTOR3_ARRAY) \
MAKE_TYPED_DICTIONARY_INFO_EXPANDED(m_type, m_variant_type, PackedVector4Array, Variant::PACKED_VECTOR4_ARRAY) \
MAKE_TYPED_DICTIONARY_INFO_EXPANDED(m_type, m_variant_type, PackedColorArray, Variant::PACKED_COLOR_ARRAY) \
/* MAKE_TYPED_DICTIONARY_INFO_EXPANDED(m_type, m_variant_type, IPAddress, Variant::STRING) */
#define MAKE_TYPED_DICTIONARY_INFO(m_type, m_variant_type) \
MAKE_TYPED_DICTIONARY_INFO_EXPANDED(m_type, m_variant_type, Variant, Variant::NIL) \
MAKE_TYPED_DICTIONARY_INFO_NIL(m_type, m_variant_type)
MAKE_TYPED_DICTIONARY_INFO_NIL(Variant, Variant::NIL)
MAKE_TYPED_DICTIONARY_INFO(bool, Variant::BOOL)
MAKE_TYPED_DICTIONARY_INFO(uint8_t, Variant::INT)
MAKE_TYPED_DICTIONARY_INFO(int8_t, Variant::INT)
MAKE_TYPED_DICTIONARY_INFO(uint16_t, Variant::INT)
MAKE_TYPED_DICTIONARY_INFO(int16_t, Variant::INT)
MAKE_TYPED_DICTIONARY_INFO(uint32_t, Variant::INT)
MAKE_TYPED_DICTIONARY_INFO(int32_t, Variant::INT)
MAKE_TYPED_DICTIONARY_INFO(uint64_t, Variant::INT)
MAKE_TYPED_DICTIONARY_INFO(int64_t, Variant::INT)
MAKE_TYPED_DICTIONARY_INFO(float, Variant::FLOAT)
MAKE_TYPED_DICTIONARY_INFO(double, Variant::FLOAT)
MAKE_TYPED_DICTIONARY_INFO(String, Variant::STRING)
MAKE_TYPED_DICTIONARY_INFO(Vector2, Variant::VECTOR2)
MAKE_TYPED_DICTIONARY_INFO(Vector2i, Variant::VECTOR2I)
MAKE_TYPED_DICTIONARY_INFO(Rect2, Variant::RECT2)
MAKE_TYPED_DICTIONARY_INFO(Rect2i, Variant::RECT2I)
MAKE_TYPED_DICTIONARY_INFO(Vector3, Variant::VECTOR3)
MAKE_TYPED_DICTIONARY_INFO(Vector3i, Variant::VECTOR3I)
MAKE_TYPED_DICTIONARY_INFO(Transform2D, Variant::TRANSFORM2D)
MAKE_TYPED_DICTIONARY_INFO(Plane, Variant::PLANE)
MAKE_TYPED_DICTIONARY_INFO(Quaternion, Variant::QUATERNION)
MAKE_TYPED_DICTIONARY_INFO(AABB, Variant::AABB)
MAKE_TYPED_DICTIONARY_INFO(Basis, Variant::BASIS)
MAKE_TYPED_DICTIONARY_INFO(Transform3D, Variant::TRANSFORM3D)
MAKE_TYPED_DICTIONARY_INFO(Color, Variant::COLOR)
MAKE_TYPED_DICTIONARY_INFO(StringName, Variant::STRING_NAME)
MAKE_TYPED_DICTIONARY_INFO(NodePath, Variant::NODE_PATH)
MAKE_TYPED_DICTIONARY_INFO(RID, Variant::RID)
MAKE_TYPED_DICTIONARY_INFO(Callable, Variant::CALLABLE)
MAKE_TYPED_DICTIONARY_INFO(Signal, Variant::SIGNAL)
MAKE_TYPED_DICTIONARY_INFO(Dictionary, Variant::DICTIONARY)
MAKE_TYPED_DICTIONARY_INFO(Array, Variant::ARRAY)
MAKE_TYPED_DICTIONARY_INFO(PackedByteArray, Variant::PACKED_BYTE_ARRAY)
MAKE_TYPED_DICTIONARY_INFO(PackedInt32Array, Variant::PACKED_INT32_ARRAY)
MAKE_TYPED_DICTIONARY_INFO(PackedInt64Array, Variant::PACKED_INT64_ARRAY)
MAKE_TYPED_DICTIONARY_INFO(PackedFloat32Array, Variant::PACKED_FLOAT32_ARRAY)
MAKE_TYPED_DICTIONARY_INFO(PackedFloat64Array, Variant::PACKED_FLOAT64_ARRAY)
MAKE_TYPED_DICTIONARY_INFO(PackedStringArray, Variant::PACKED_STRING_ARRAY)
MAKE_TYPED_DICTIONARY_INFO(PackedVector2Array, Variant::PACKED_VECTOR2_ARRAY)
MAKE_TYPED_DICTIONARY_INFO(PackedVector3Array, Variant::PACKED_VECTOR3_ARRAY)
MAKE_TYPED_DICTIONARY_INFO(PackedVector4Array, Variant::PACKED_VECTOR4_ARRAY)
MAKE_TYPED_DICTIONARY_INFO(PackedColorArray, Variant::PACKED_COLOR_ARRAY)
/*
MAKE_TYPED_DICTIONARY_INFO(IPAddress, Variant::STRING)
*/
#undef MAKE_TYPED_DICTIONARY_INFO
#undef MAKE_TYPED_DICTIONARY_INFO_NIL
#undef MAKE_TYPED_DICTIONARY_INFO_EXPANDED
#undef MAKE_TYPED_DICTIONARY_INFO_WITH_OBJECT
} // namespace godot
#endif // GODOT_TYPED_DICTIONARY_HPP

View File

@@ -47,9 +47,10 @@ class ObjectID;
class Variant {
uint8_t opaque[GODOT_CPP_VARIANT_SIZE]{ 0 };
_FORCE_INLINE_ GDExtensionVariantPtr _native_ptr() const { return const_cast<uint8_t(*)[GODOT_CPP_VARIANT_SIZE]>(&opaque); }
friend class GDExtensionBinding;
friend class MethodBind;
friend class VariantInternal;
static void init_bindings();
@@ -101,7 +102,6 @@ public:
PACKED_VECTOR2_ARRAY,
PACKED_VECTOR3_ARRAY,
PACKED_COLOR_ARRAY,
PACKED_VECTOR4_ARRAY,
VARIANT_MAX
};
@@ -122,7 +122,6 @@ public:
OP_NEGATE,
OP_POSITIVE,
OP_MODULE,
OP_POWER,
// bitwise
OP_SHIFT_LEFT,
OP_SHIFT_RIGHT,
@@ -145,7 +144,6 @@ private:
static GDExtensionTypeFromVariantConstructorFunc to_type_constructor[VARIANT_MAX];
public:
_FORCE_INLINE_ GDExtensionVariantPtr _native_ptr() const { return const_cast<uint8_t(*)[GODOT_CPP_VARIANT_SIZE]>(&opaque); }
Variant();
Variant(std::nullptr_t n) :
Variant() {}
@@ -156,17 +154,9 @@ public:
Variant(int64_t v);
Variant(int32_t v) :
Variant(static_cast<int64_t>(v)) {}
Variant(int16_t v) :
Variant(static_cast<int64_t>(v)) {}
Variant(int8_t v) :
Variant(static_cast<int64_t>(v)) {}
Variant(uint64_t v) :
Variant(static_cast<int64_t>(v)) {}
Variant(uint32_t v) :
Variant(static_cast<int64_t>(v)) {}
Variant(uint16_t v) :
Variant(static_cast<int64_t>(v)) {}
Variant(uint8_t v) :
Variant(uint64_t v) :
Variant(static_cast<int64_t>(v)) {}
Variant(double v);
Variant(float v) :
@@ -214,18 +204,13 @@ public:
Variant(const PackedVector2Array &v);
Variant(const PackedVector3Array &v);
Variant(const PackedColorArray &v);
Variant(const PackedVector4Array &v);
~Variant();
operator bool() const;
operator int64_t() const;
operator int32_t() const;
operator int16_t() const;
operator int8_t() const;
operator uint64_t() const;
operator uint32_t() const;
operator uint16_t() const;
operator uint8_t() const;
operator double() const;
operator float() const;
operator String() const;
@@ -263,9 +248,6 @@ public:
operator PackedVector2Array() const;
operator PackedVector3Array() const;
operator PackedColorArray() const;
operator PackedVector4Array() const;
Object *get_validated_object() const;
Variant &operator=(const Variant &other);
Variant &operator=(Variant &&other);
@@ -273,33 +255,25 @@ public:
bool operator!=(const Variant &other) const;
bool operator<(const Variant &other) const;
void callp(const StringName &method, const Variant **args, int argcount, Variant &r_ret, GDExtensionCallError &r_error);
void call(const StringName &method, const Variant **args, int argcount, Variant &r_ret, GDExtensionCallError &r_error);
template <typename... Args>
template <class... Args>
Variant call(const StringName &method, Args... args) {
std::array<Variant, sizeof...(args)> vargs = { args... };
std::array<const Variant *, sizeof...(args)> argptrs;
for (size_t i = 0; i < vargs.size(); i++) {
argptrs[i] = &vargs[i];
}
Variant result;
GDExtensionCallError error;
callp(method, argptrs.data(), argptrs.size(), result, error);
std::array<GDExtensionConstVariantPtr, sizeof...(Args)> call_args = { Variant(args)... };
call(method, call_args.data(), call_args.size(), result, error);
return result;
}
static void callp_static(Variant::Type type, const StringName &method, const Variant **args, int argcount, Variant &r_ret, GDExtensionCallError &r_error);
static void call_static(Variant::Type type, const StringName &method, const Variant **args, int argcount, Variant &r_ret, GDExtensionCallError &r_error);
template <typename... Args>
template <class... Args>
static Variant call_static(Variant::Type type, const StringName &method, Args... args) {
std::array<Variant, sizeof...(args)> vargs = { args... };
std::array<const Variant *, sizeof...(args)> argptrs;
for (size_t i = 0; i < vargs.size(); i++) {
argptrs[i] = &vargs[i];
}
Variant result;
GDExtensionCallError error;
callp_static(type, method, argptrs.data(), argptrs.size(), sizeof...(args), result, error);
std::array<GDExtensionConstVariantPtr, sizeof...(Args)> call_args = { Variant(args)... };
call_static(type, method, call_args.data(), call_args.size(), result, error);
return result;
}
@@ -330,6 +304,8 @@ public:
bool booleanize() const;
String stringify() const;
Variant duplicate(bool deep = false) const;
static void blend(const Variant &a, const Variant &b, float c, Variant &r_dst);
static void interpolate(const Variant &a, const Variant &b, float c, Variant &r_dst);
static String get_type_name(Variant::Type type);
static bool can_convert(Variant::Type from, Variant::Type to);
@@ -358,14 +334,6 @@ String vformat(const String &p_text, const VarArgs... p_args) {
return p_text % args_array;
}
#include <godot_cpp/variant/builtin_vararg_methods.hpp>
#ifdef REAL_T_IS_DOUBLE
using PackedRealArray = PackedFloat64Array;
#else
using PackedRealArray = PackedFloat32Array;
#endif // REAL_T_IS_DOUBLE
} // namespace godot
#endif // GODOT_VARIANT_HPP

View File

@@ -1,509 +0,0 @@
/**************************************************************************/
/* variant_internal.hpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* 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 GODOT_VARIANT_INTERNAL_HPP
#define GODOT_VARIANT_INTERNAL_HPP
#include <gdextension_interface.h>
#include <godot_cpp/variant/variant.hpp>
namespace godot {
// For use when you want to access the internal pointer of a Variant directly.
// Use with caution. You need to be sure that the type is correct.
namespace internal {
template <typename T>
struct VariantInternalType {};
template <>
struct VariantInternalType<bool> {
static constexpr Variant::Type type = Variant::BOOL;
};
template <>
struct VariantInternalType<int64_t> {
static constexpr Variant::Type type = Variant::INT;
};
template <>
struct VariantInternalType<double> {
static constexpr Variant::Type type = Variant::FLOAT;
};
template <>
struct VariantInternalType<String> {
static constexpr Variant::Type type = Variant::STRING;
};
template <>
struct VariantInternalType<Vector2> {
static constexpr Variant::Type type = Variant::VECTOR2;
};
template <>
struct VariantInternalType<Vector2i> {
static constexpr Variant::Type type = Variant::VECTOR2I;
};
template <>
struct VariantInternalType<Rect2> {
static constexpr Variant::Type type = Variant::RECT2;
};
template <>
struct VariantInternalType<Rect2i> {
static constexpr Variant::Type type = Variant::RECT2I;
};
template <>
struct VariantInternalType<Vector3> {
static constexpr Variant::Type type = Variant::VECTOR3;
};
template <>
struct VariantInternalType<Vector3i> {
static constexpr Variant::Type type = Variant::VECTOR3I;
};
template <>
struct VariantInternalType<Transform2D> {
static constexpr Variant::Type type = Variant::TRANSFORM2D;
};
template <>
struct VariantInternalType<Vector4> {
static constexpr Variant::Type type = Variant::VECTOR4;
};
template <>
struct VariantInternalType<Vector4i> {
static constexpr Variant::Type type = Variant::VECTOR4I;
};
template <>
struct VariantInternalType<Plane> {
static constexpr Variant::Type type = Variant::PLANE;
};
template <>
struct VariantInternalType<Quaternion> {
static constexpr Variant::Type type = Variant::QUATERNION;
};
template <>
struct VariantInternalType<AABB> {
static constexpr Variant::Type type = Variant::AABB;
};
template <>
struct VariantInternalType<Basis> {
static constexpr Variant::Type type = Variant::BASIS;
};
template <>
struct VariantInternalType<Transform3D> {
static constexpr Variant::Type type = Variant::TRANSFORM3D;
};
template <>
struct VariantInternalType<Projection> {
static constexpr Variant::Type type = Variant::PROJECTION;
};
template <>
struct VariantInternalType<Color> {
static constexpr Variant::Type type = Variant::COLOR;
};
template <>
struct VariantInternalType<StringName> {
static constexpr Variant::Type type = Variant::STRING_NAME;
};
template <>
struct VariantInternalType<NodePath> {
static constexpr Variant::Type type = Variant::NODE_PATH;
};
template <>
struct VariantInternalType<RID> {
static constexpr Variant::Type type = Variant::RID;
};
template <>
struct VariantInternalType<Object *> {
static constexpr Variant::Type type = Variant::OBJECT;
};
template <>
struct VariantInternalType<Callable> {
static constexpr Variant::Type type = Variant::CALLABLE;
};
template <>
struct VariantInternalType<Signal> {
static constexpr Variant::Type type = Variant::SIGNAL;
};
template <>
struct VariantInternalType<Dictionary> {
static constexpr Variant::Type type = Variant::DICTIONARY;
};
template <>
struct VariantInternalType<Array> {
static constexpr Variant::Type type = Variant::ARRAY;
};
template <>
struct VariantInternalType<PackedByteArray> {
static constexpr Variant::Type type = Variant::PACKED_BYTE_ARRAY;
};
template <>
struct VariantInternalType<PackedInt32Array> {
static constexpr Variant::Type type = Variant::PACKED_INT32_ARRAY;
};
template <>
struct VariantInternalType<PackedInt64Array> {
static constexpr Variant::Type type = Variant::PACKED_INT64_ARRAY;
};
template <>
struct VariantInternalType<PackedFloat32Array> {
static constexpr Variant::Type type = Variant::PACKED_FLOAT32_ARRAY;
};
template <>
struct VariantInternalType<PackedFloat64Array> {
static constexpr Variant::Type type = Variant::PACKED_FLOAT64_ARRAY;
};
template <>
struct VariantInternalType<PackedStringArray> {
static constexpr Variant::Type type = Variant::PACKED_STRING_ARRAY;
};
template <>
struct VariantInternalType<PackedVector2Array> {
static constexpr Variant::Type type = Variant::PACKED_VECTOR2_ARRAY;
};
template <>
struct VariantInternalType<PackedVector3Array> {
static constexpr Variant::Type type = Variant::PACKED_VECTOR3_ARRAY;
};
template <>
struct VariantInternalType<PackedColorArray> {
static constexpr Variant::Type type = Variant::PACKED_COLOR_ARRAY;
};
template <>
struct VariantInternalType<PackedVector4Array> {
static constexpr Variant::Type type = Variant::PACKED_VECTOR4_ARRAY;
};
} //namespace internal
class VariantInternal {
friend class Variant;
static GDExtensionVariantGetInternalPtrFunc get_internal_func[Variant::VARIANT_MAX];
static void init_bindings();
public:
template <typename T>
_FORCE_INLINE_ static T *get_internal_value(Variant *v) {
return static_cast<T *>(get_internal_func[internal::VariantInternalType<T>::type](v));
}
template <typename T>
_FORCE_INLINE_ static const T *get_internal_value(const Variant *v) {
return static_cast<const T *>(get_internal_func[internal::VariantInternalType<T>::type](const_cast<Variant *>(v)));
}
// Atomic types.
_FORCE_INLINE_ static bool *get_bool(Variant *v) { return get_internal_value<bool>(v); }
_FORCE_INLINE_ static const bool *get_bool(const Variant *v) { return get_internal_value<bool>(v); }
_FORCE_INLINE_ static int64_t *get_int(Variant *v) { return get_internal_value<int64_t>(v); }
_FORCE_INLINE_ static const int64_t *get_int(const Variant *v) { return get_internal_value<int64_t>(v); }
_FORCE_INLINE_ static double *get_float(Variant *v) { return get_internal_value<double>(v); }
_FORCE_INLINE_ static const double *get_float(const Variant *v) { return get_internal_value<double>(v); }
_FORCE_INLINE_ static String *get_string(Variant *v) { return get_internal_value<String>(v); }
_FORCE_INLINE_ static const String *get_string(const Variant *v) { return get_internal_value<String>(v); }
// Math types.
_FORCE_INLINE_ static Vector2 *get_vector2(Variant *v) { return get_internal_value<Vector2>(v); }
_FORCE_INLINE_ static const Vector2 *get_vector2(const Variant *v) { return get_internal_value<Vector2>(v); }
_FORCE_INLINE_ static Vector2i *get_vector2i(Variant *v) { return get_internal_value<Vector2i>(v); }
_FORCE_INLINE_ static const Vector2i *get_vector2i(const Variant *v) { return get_internal_value<Vector2i>(v); }
_FORCE_INLINE_ static Rect2 *get_rect2(Variant *v) { return get_internal_value<Rect2>(v); }
_FORCE_INLINE_ static const Rect2 *get_rect2(const Variant *v) { return get_internal_value<Rect2>(v); }
_FORCE_INLINE_ static Rect2i *get_rect2i(Variant *v) { return get_internal_value<Rect2i>(v); }
_FORCE_INLINE_ static const Rect2i *get_rect2i(const Variant *v) { return get_internal_value<Rect2i>(v); }
_FORCE_INLINE_ static Vector3 *get_vector3(Variant *v) { return get_internal_value<Vector3>(v); }
_FORCE_INLINE_ static const Vector3 *get_vector3(const Variant *v) { return get_internal_value<Vector3>(v); }
_FORCE_INLINE_ static Vector3i *get_vector3i(Variant *v) { return get_internal_value<Vector3i>(v); }
_FORCE_INLINE_ static const Vector3i *get_vector3i(const Variant *v) { return get_internal_value<Vector3i>(v); }
_FORCE_INLINE_ static Vector4 *get_vector4(Variant *v) { return get_internal_value<Vector4>(v); }
_FORCE_INLINE_ static const Vector4 *get_vector4(const Variant *v) { return get_internal_value<Vector4>(v); }
_FORCE_INLINE_ static Vector4i *get_vector4i(Variant *v) { return get_internal_value<Vector4i>(v); }
_FORCE_INLINE_ static const Vector4i *get_vector4i(const Variant *v) { return get_internal_value<Vector4i>(v); }
_FORCE_INLINE_ static Transform2D *get_transform2d(Variant *v) { return get_internal_value<Transform2D>(v); }
_FORCE_INLINE_ static const Transform2D *get_transform2d(const Variant *v) { return get_internal_value<Transform2D>(v); }
_FORCE_INLINE_ static Plane *get_plane(Variant *v) { return get_internal_value<Plane>(v); }
_FORCE_INLINE_ static const Plane *get_plane(const Variant *v) { return get_internal_value<Plane>(v); }
_FORCE_INLINE_ static Quaternion *get_quaternion(Variant *v) { return get_internal_value<Quaternion>(v); }
_FORCE_INLINE_ static const Quaternion *get_quaternion(const Variant *v) { return get_internal_value<Quaternion>(v); }
_FORCE_INLINE_ static AABB *get_aabb(Variant *v) { return get_internal_value<AABB>(v); }
_FORCE_INLINE_ static const AABB *get_aabb(const Variant *v) { return get_internal_value<AABB>(v); }
_FORCE_INLINE_ static Basis *get_basis(Variant *v) { return get_internal_value<Basis>(v); }
_FORCE_INLINE_ static const Basis *get_basis(const Variant *v) { return get_internal_value<Basis>(v); }
_FORCE_INLINE_ static Transform3D *get_transform(Variant *v) { return get_internal_value<Transform3D>(v); }
_FORCE_INLINE_ static const Transform3D *get_transform(const Variant *v) { return get_internal_value<Transform3D>(v); }
_FORCE_INLINE_ static Projection *get_projection(Variant *v) { return get_internal_value<Projection>(v); }
_FORCE_INLINE_ static const Projection *get_projection(const Variant *v) { return get_internal_value<Projection>(v); }
// Misc types.
_FORCE_INLINE_ static Color *get_color(Variant *v) { return get_internal_value<Color>(v); }
_FORCE_INLINE_ static const Color *get_color(const Variant *v) { return get_internal_value<Color>(v); }
_FORCE_INLINE_ static StringName *get_string_name(Variant *v) { return get_internal_value<StringName>(v); }
_FORCE_INLINE_ static const StringName *get_string_name(const Variant *v) { return get_internal_value<StringName>(v); }
_FORCE_INLINE_ static NodePath *get_node_path(Variant *v) { return get_internal_value<NodePath>(v); }
_FORCE_INLINE_ static const NodePath *get_node_path(const Variant *v) { return get_internal_value<NodePath>(v); }
_FORCE_INLINE_ static RID *get_rid(Variant *v) { return get_internal_value<RID>(v); }
_FORCE_INLINE_ static const RID *get_rid(const Variant *v) { return get_internal_value<RID>(v); }
_FORCE_INLINE_ static Callable *get_callable(Variant *v) { return get_internal_value<Callable>(v); }
_FORCE_INLINE_ static const Callable *get_callable(const Variant *v) { return get_internal_value<Callable>(v); }
_FORCE_INLINE_ static Signal *get_signal(Variant *v) { return get_internal_value<Signal>(v); }
_FORCE_INLINE_ static const Signal *get_signal(const Variant *v) { return get_internal_value<Signal>(v); }
_FORCE_INLINE_ static Dictionary *get_dictionary(Variant *v) { return get_internal_value<Dictionary>(v); }
_FORCE_INLINE_ static const Dictionary *get_dictionary(const Variant *v) { return get_internal_value<Dictionary>(v); }
_FORCE_INLINE_ static Array *get_array(Variant *v) { return get_internal_value<Array>(v); }
_FORCE_INLINE_ static const Array *get_array(const Variant *v) { return get_internal_value<Array>(v); }
// Typed arrays.
_FORCE_INLINE_ static PackedByteArray *get_byte_array(Variant *v) { return get_internal_value<PackedByteArray>(v); }
_FORCE_INLINE_ static const PackedByteArray *get_byte_array(const Variant *v) { return get_internal_value<PackedByteArray>(v); }
_FORCE_INLINE_ static PackedInt32Array *get_int32_array(Variant *v) { return get_internal_value<PackedInt32Array>(v); }
_FORCE_INLINE_ static const PackedInt32Array *get_int32_array(const Variant *v) { return get_internal_value<PackedInt32Array>(v); }
_FORCE_INLINE_ static PackedInt64Array *get_int64_array(Variant *v) { return get_internal_value<PackedInt64Array>(v); }
_FORCE_INLINE_ static const PackedInt64Array *get_int64_array(const Variant *v) { return get_internal_value<PackedInt64Array>(v); }
_FORCE_INLINE_ static PackedFloat32Array *get_float32_array(Variant *v) { return get_internal_value<PackedFloat32Array>(v); }
_FORCE_INLINE_ static const PackedFloat32Array *get_float32_array(const Variant *v) { return get_internal_value<PackedFloat32Array>(v); }
_FORCE_INLINE_ static PackedFloat64Array *get_float64_array(Variant *v) { return get_internal_value<PackedFloat64Array>(v); }
_FORCE_INLINE_ static const PackedFloat64Array *get_float64_array(const Variant *v) { return get_internal_value<PackedFloat64Array>(v); }
_FORCE_INLINE_ static PackedStringArray *get_string_array(Variant *v) { return get_internal_value<PackedStringArray>(v); }
_FORCE_INLINE_ static const PackedStringArray *get_string_array(const Variant *v) { return get_internal_value<PackedStringArray>(v); }
_FORCE_INLINE_ static PackedVector2Array *get_vector2_array(Variant *v) { return get_internal_value<PackedVector2Array>(v); }
_FORCE_INLINE_ static const PackedVector2Array *get_vector2_array(const Variant *v) { return get_internal_value<PackedVector2Array>(v); }
_FORCE_INLINE_ static PackedVector3Array *get_vector3_array(Variant *v) { return get_internal_value<PackedVector3Array>(v); }
_FORCE_INLINE_ static const PackedVector3Array *get_vector3_array(const Variant *v) { return get_internal_value<PackedVector3Array>(v); }
_FORCE_INLINE_ static PackedColorArray *get_color_array(Variant *v) { return get_internal_value<PackedColorArray>(v); }
_FORCE_INLINE_ static const PackedColorArray *get_color_array(const Variant *v) { return get_internal_value<PackedColorArray>(v); }
_FORCE_INLINE_ static PackedVector4Array *get_vector4_array(Variant *v) { return get_internal_value<PackedVector4Array>(v); }
_FORCE_INLINE_ static const PackedVector4Array *get_vector4_array(const Variant *v) { return get_internal_value<PackedVector4Array>(v); }
_FORCE_INLINE_ static Object **get_object(Variant *v) { return get_internal_value<Object *>(v); }
_FORCE_INLINE_ static const Object **get_object(const Variant *v) { return (const Object **)get_internal_value<Object *>(v); }
_FORCE_INLINE_ static void *get_opaque_pointer(Variant *v) {
switch (v->get_type()) {
case Variant::NIL:
return nullptr;
case Variant::BOOL:
return get_bool(v);
case Variant::INT:
return get_int(v);
case Variant::FLOAT:
return get_float(v);
case Variant::STRING:
return get_string(v);
case Variant::VECTOR2:
return get_vector2(v);
case Variant::VECTOR2I:
return get_vector2i(v);
case Variant::VECTOR3:
return get_vector3(v);
case Variant::VECTOR3I:
return get_vector3i(v);
case Variant::VECTOR4:
return get_vector4(v);
case Variant::VECTOR4I:
return get_vector4i(v);
case Variant::RECT2:
return get_rect2(v);
case Variant::RECT2I:
return get_rect2i(v);
case Variant::TRANSFORM3D:
return get_transform(v);
case Variant::PROJECTION:
return get_projection(v);
case Variant::TRANSFORM2D:
return get_transform2d(v);
case Variant::QUATERNION:
return get_quaternion(v);
case Variant::PLANE:
return get_plane(v);
case Variant::BASIS:
return get_basis(v);
case Variant::AABB:
return get_aabb(v);
case Variant::COLOR:
return get_color(v);
case Variant::STRING_NAME:
return get_string_name(v);
case Variant::NODE_PATH:
return get_node_path(v);
case Variant::RID:
return get_rid(v);
case Variant::CALLABLE:
return get_callable(v);
case Variant::SIGNAL:
return get_signal(v);
case Variant::DICTIONARY:
return get_dictionary(v);
case Variant::ARRAY:
return get_array(v);
case Variant::PACKED_BYTE_ARRAY:
return get_byte_array(v);
case Variant::PACKED_INT32_ARRAY:
return get_int32_array(v);
case Variant::PACKED_INT64_ARRAY:
return get_int64_array(v);
case Variant::PACKED_FLOAT32_ARRAY:
return get_float32_array(v);
case Variant::PACKED_FLOAT64_ARRAY:
return get_float64_array(v);
case Variant::PACKED_STRING_ARRAY:
return get_string_array(v);
case Variant::PACKED_VECTOR2_ARRAY:
return get_vector2_array(v);
case Variant::PACKED_VECTOR3_ARRAY:
return get_vector3_array(v);
case Variant::PACKED_COLOR_ARRAY:
return get_color_array(v);
case Variant::PACKED_VECTOR4_ARRAY:
return get_vector4_array(v);
case Variant::OBJECT:
return get_object(v);
case Variant::VARIANT_MAX:
ERR_FAIL_V(nullptr);
}
ERR_FAIL_V(nullptr);
}
_FORCE_INLINE_ static const void *get_opaque_pointer(const Variant *v) {
switch (v->get_type()) {
case Variant::NIL:
return nullptr;
case Variant::BOOL:
return get_bool(v);
case Variant::INT:
return get_int(v);
case Variant::FLOAT:
return get_float(v);
case Variant::STRING:
return get_string(v);
case Variant::VECTOR2:
return get_vector2(v);
case Variant::VECTOR2I:
return get_vector2i(v);
case Variant::VECTOR3:
return get_vector3(v);
case Variant::VECTOR3I:
return get_vector3i(v);
case Variant::VECTOR4:
return get_vector4(v);
case Variant::VECTOR4I:
return get_vector4i(v);
case Variant::RECT2:
return get_rect2(v);
case Variant::RECT2I:
return get_rect2i(v);
case Variant::TRANSFORM3D:
return get_transform(v);
case Variant::PROJECTION:
return get_projection(v);
case Variant::TRANSFORM2D:
return get_transform2d(v);
case Variant::QUATERNION:
return get_quaternion(v);
case Variant::PLANE:
return get_plane(v);
case Variant::BASIS:
return get_basis(v);
case Variant::AABB:
return get_aabb(v);
case Variant::COLOR:
return get_color(v);
case Variant::STRING_NAME:
return get_string_name(v);
case Variant::NODE_PATH:
return get_node_path(v);
case Variant::RID:
return get_rid(v);
case Variant::CALLABLE:
return get_callable(v);
case Variant::SIGNAL:
return get_signal(v);
case Variant::DICTIONARY:
return get_dictionary(v);
case Variant::ARRAY:
return get_array(v);
case Variant::PACKED_BYTE_ARRAY:
return get_byte_array(v);
case Variant::PACKED_INT32_ARRAY:
return get_int32_array(v);
case Variant::PACKED_INT64_ARRAY:
return get_int64_array(v);
case Variant::PACKED_FLOAT32_ARRAY:
return get_float32_array(v);
case Variant::PACKED_FLOAT64_ARRAY:
return get_float64_array(v);
case Variant::PACKED_STRING_ARRAY:
return get_string_array(v);
case Variant::PACKED_VECTOR2_ARRAY:
return get_vector2_array(v);
case Variant::PACKED_VECTOR3_ARRAY:
return get_vector3_array(v);
case Variant::PACKED_COLOR_ARRAY:
return get_color_array(v);
case Variant::PACKED_VECTOR4_ARRAY:
return get_vector4_array(v);
case Variant::OBJECT:
return get_object(v);
case Variant::VARIANT_MAX:
ERR_FAIL_V(nullptr);
}
ERR_FAIL_V(nullptr);
}
};
template <typename T>
struct VariantGetInternalPtr {
static internal::VariantInternalType<T> *get_ptr(Variant *v) { return VariantInternal::get_internal_value<T>(v); }
static const internal::VariantInternalType<T> *get_ptr(const Variant *v) { return VariantInternal::get_internal_value<T>(v); }
};
template <typename T>
struct can_set_variant_internal_value {
static const bool value = true;
};
template <>
struct can_set_variant_internal_value<Object *> {
static const bool value = false;
};
template <typename T>
struct VariantInternalAccessor {
static _FORCE_INLINE_ const T &get(const Variant *v) { return *VariantInternal::get_internal_value<T>(v); }
// Enable set() only for those types where we can set (all but Object *).
template <typename U = T, typename = std::enable_if_t<can_set_variant_internal_value<U>::value>>
static _FORCE_INLINE_ void set(Variant *v, const internal::VariantInternalType<U> &p_value) {
*VariantInternal::get_internal_value<U>(v) = p_value;
}
};
template <typename T, std::enable_if_t<can_set_variant_internal_value<T>::value>>
struct VariantDefaultInitializer {
static _FORCE_INLINE_ void init(Variant *v) { *VariantInternal::get_internal_value<T>(v) = T(); }
};
} // namespace godot
#endif // GODOT_VARIANT_INTERNAL_HPP

View File

@@ -39,7 +39,7 @@ namespace godot {
class String;
struct Vector2i;
struct [[nodiscard]] Vector2 {
struct _NO_DISCARD_ Vector2 {
static const int AXIS_COUNT = 2;
enum Axis {
@@ -91,18 +91,10 @@ struct [[nodiscard]] Vector2 {
return Vector2(MIN(x, p_vector2.x), MIN(y, p_vector2.y));
}
Vector2 minf(real_t p_scalar) const {
return Vector2(MIN(x, p_scalar), MIN(y, p_scalar));
}
Vector2 max(const Vector2 &p_vector2) const {
return Vector2(MAX(x, p_vector2.x), MAX(y, p_vector2.y));
}
Vector2 maxf(real_t p_scalar) const {
return Vector2(MAX(x, p_scalar), MAX(y, p_scalar));
}
real_t distance_to(const Vector2 &p_vector2) const;
real_t distance_squared_to(const Vector2 &p_vector2) const;
real_t angle_to(const Vector2 &p_vector2) const;
@@ -131,7 +123,6 @@ struct [[nodiscard]] Vector2 {
bool is_equal_approx(const Vector2 &p_v) const;
bool is_zero_approx() const;
bool is_finite() const;
Vector2 operator+(const Vector2 &p_v) const;
void operator+=(const Vector2 &p_v);
@@ -177,9 +168,7 @@ struct [[nodiscard]] Vector2 {
Vector2 ceil() const;
Vector2 round() const;
Vector2 snapped(const Vector2 &p_by) const;
Vector2 snappedf(real_t p_by) const;
Vector2 clamp(const Vector2 &p_min, const Vector2 &p_max) const;
Vector2 clampf(real_t p_min, real_t p_max) const;
real_t aspect() const { return width / height; }
operator String() const;

View File

@@ -39,7 +39,7 @@ namespace godot {
class String;
struct Vector2;
struct [[nodiscard]] Vector2i {
struct _NO_DISCARD_ Vector2i {
static const int AXIS_COUNT = 2;
enum Axis {
@@ -83,18 +83,10 @@ struct [[nodiscard]] Vector2i {
return Vector2i(MIN(x, p_vector2i.x), MIN(y, p_vector2i.y));
}
Vector2i mini(int32_t p_scalar) const {
return Vector2i(MIN(x, p_scalar), MIN(y, p_scalar));
}
Vector2i max(const Vector2i &p_vector2i) const {
return Vector2i(MAX(x, p_vector2i.x), MAX(y, p_vector2i.y));
}
Vector2i maxi(int32_t p_scalar) const {
return Vector2i(MAX(x, p_scalar), MAX(y, p_scalar));
}
Vector2i operator+(const Vector2i &p_v) const;
void operator+=(const Vector2i &p_v);
Vector2i operator-(const Vector2i &p_v) const;
@@ -125,16 +117,10 @@ 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;
operator String() const;
operator Vector2() const;

View File

@@ -41,7 +41,7 @@ struct Basis;
struct Vector2;
struct Vector3i;
struct [[nodiscard]] Vector3 {
struct _NO_DISCARD_ Vector3 {
static const int AXIS_COUNT = 3;
enum Axis {
@@ -78,22 +78,6 @@ struct [[nodiscard]] Vector3 {
return x < y ? (y < z ? Vector3::AXIS_Z : Vector3::AXIS_Y) : (x < z ? Vector3::AXIS_Z : Vector3::AXIS_X);
}
Vector3 min(const Vector3 &p_vector3) const {
return Vector3(MIN(x, p_vector3.x), MIN(y, p_vector3.y), MIN(z, p_vector3.z));
}
Vector3 minf(real_t p_scalar) const {
return Vector3(MIN(x, p_scalar), MIN(y, p_scalar), MIN(z, p_scalar));
}
Vector3 max(const Vector3 &p_vector3) const {
return Vector3(MAX(x, p_vector3.x), MAX(y, p_vector3.y), MAX(z, p_vector3.z));
}
Vector3 maxf(real_t p_scalar) const {
return Vector3(MAX(x, p_scalar), MAX(y, p_scalar), MAX(z, p_scalar));
}
_FORCE_INLINE_ real_t length() const;
_FORCE_INLINE_ real_t length_squared() const;
@@ -106,9 +90,7 @@ struct [[nodiscard]] Vector3 {
_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 rotate(const Vector3 &p_axis, const real_t p_angle);
Vector3 rotated(const Vector3 &p_axis, const real_t p_angle) const;
@@ -138,7 +120,6 @@ struct [[nodiscard]] Vector3 {
_FORCE_INLINE_ Vector3 ceil() const;
_FORCE_INLINE_ Vector3 round() const;
Vector3 clamp(const Vector3 &p_min, const Vector3 &p_max) const;
Vector3 clampf(real_t p_min, real_t p_max) const;
_FORCE_INLINE_ real_t distance_to(const Vector3 &p_to) const;
_FORCE_INLINE_ real_t distance_squared_to(const Vector3 &p_to) const;
@@ -157,7 +138,6 @@ struct [[nodiscard]] Vector3 {
bool is_equal_approx(const Vector3 &p_v) const;
bool is_zero_approx() const;
bool is_finite() const;
/* Operators */

View File

@@ -39,7 +39,7 @@ namespace godot {
class String;
struct Vector3;
struct [[nodiscard]] Vector3i {
struct _NO_DISCARD_ Vector3i {
static const int AXIS_COUNT = 3;
enum Axis {
@@ -71,36 +71,14 @@ struct [[nodiscard]] Vector3i {
Vector3i::Axis min_axis_index() const;
Vector3i::Axis max_axis_index() const;
Vector3i min(const Vector3i &p_vector3i) const {
return Vector3i(MIN(x, p_vector3i.x), MIN(y, p_vector3i.y), MIN(z, p_vector3i.z));
}
Vector3i mini(int32_t p_scalar) const {
return Vector3i(MIN(x, p_scalar), MIN(y, p_scalar), MIN(z, p_scalar));
}
Vector3i max(const Vector3i &p_vector3i) const {
return Vector3i(MAX(x, p_vector3i.x), MAX(y, p_vector3i.y), MAX(z, p_vector3i.z));
}
Vector3i maxi(int32_t p_scalar) const {
return Vector3i(MAX(x, p_scalar), MAX(y, p_scalar), MAX(z, p_scalar));
}
_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;
/* Operators */
@@ -150,14 +128,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));
}

View File

@@ -38,7 +38,7 @@ namespace godot {
class String;
struct [[nodiscard]] Vector4 {
struct _NO_DISCARD_ Vector4 {
static const int AXIS_COUNT = 4;
enum Axis {
@@ -55,42 +55,24 @@ 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 };
real_t components[4] = { 0, 0, 0, 0 };
};
_FORCE_INLINE_ real_t &operator[](const int p_axis) {
DEV_ASSERT((unsigned int)p_axis < 4);
return coord[p_axis];
return components[p_axis];
}
_FORCE_INLINE_ const real_t &operator[](const int p_axis) const {
DEV_ASSERT((unsigned int)p_axis < 4);
return coord[p_axis];
return components[p_axis];
}
Vector4::Axis min_axis_index() const;
Vector4::Axis max_axis_index() const;
Vector4 min(const Vector4 &p_vector4) const {
return Vector4(MIN(x, p_vector4.x), MIN(y, p_vector4.y), MIN(z, p_vector4.z), MIN(w, p_vector4.w));
}
Vector4 minf(real_t p_scalar) const {
return Vector4(MIN(x, p_scalar), MIN(y, p_scalar), MIN(z, p_scalar), MIN(w, p_scalar));
}
Vector4 max(const Vector4 &p_vector4) const {
return Vector4(MAX(x, p_vector4.x), MAX(y, p_vector4.y), MAX(z, p_vector4.z), MAX(w, p_vector4.w));
}
Vector4 maxf(real_t p_scalar) const {
return Vector4(MAX(x, p_scalar), MAX(y, p_scalar), MAX(z, p_scalar), MAX(w, p_scalar));
}
_FORCE_INLINE_ real_t length_squared() const;
bool is_equal_approx(const Vector4 &p_vec4) const;
bool is_zero_approx() const;
bool is_finite() const;
real_t length() const;
void normalize();
Vector4 normalized() const;
@@ -112,11 +94,8 @@ struct [[nodiscard]] Vector4 {
Vector4 posmod(const real_t p_mod) const;
Vector4 posmodv(const Vector4 &p_modv) const;
void snap(const Vector4 &p_step);
void snapf(real_t p_step);
Vector4 snapped(const Vector4 &p_step) const;
Vector4 snappedf(real_t p_step) const;
Vector4 clamp(const Vector4 &p_min, const Vector4 &p_max) const;
Vector4 clampf(real_t p_min, real_t p_max) const;
Vector4 inverse() const;
_FORCE_INLINE_ real_t dot(const Vector4 &p_vec4) const;

View File

@@ -39,7 +39,7 @@ namespace godot {
class String;
struct Vector4;
struct [[nodiscard]] Vector4i {
struct _NO_DISCARD_ Vector4i {
static const int AXIS_COUNT = 4;
enum Axis {
@@ -73,36 +73,14 @@ struct [[nodiscard]] Vector4i {
Vector4i::Axis min_axis_index() const;
Vector4i::Axis max_axis_index() const;
Vector4i min(const Vector4i &p_vector4i) const {
return Vector4i(MIN(x, p_vector4i.x), MIN(y, p_vector4i.y), MIN(z, p_vector4i.z), MIN(w, p_vector4i.w));
}
Vector4i mini(int32_t p_scalar) const {
return Vector4i(MIN(x, p_scalar), MIN(y, p_scalar), MIN(z, p_scalar), MIN(w, p_scalar));
}
Vector4i max(const Vector4i &p_vector4i) const {
return Vector4i(MAX(x, p_vector4i.x), MAX(y, p_vector4i.y), MAX(z, p_vector4i.z), MAX(w, p_vector4i.w));
}
Vector4i maxi(int32_t p_scalar) const {
return Vector4i(MAX(x, p_scalar), MAX(y, p_scalar), MAX(z, p_scalar), MAX(w, p_scalar));
}
_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_ 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;
/* Operators */
@@ -154,14 +132,6 @@ 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();
}
Vector4i Vector4i::abs() const {
return Vector4i(Math::abs(x), Math::abs(y), Math::abs(z), Math::abs(w));
}

37
misc/hooks/README.md Normal file
View File

@@ -0,0 +1,37 @@
# Git hooks for Godot Engine
This folder contains Git hooks meant to be installed locally by Godot Engine
contributors to make sure they comply with our requirements.
## List of hooks
- Pre-commit hook for `clang-format`: Applies `clang-format` to the staged
files before accepting a commit; blocks the commit and generates a patch if
the style is not respected.
You may need to edit the file if your `clang-format` binary is not in the
`PATH`, or if you want to enable colored output with `pygmentize`.
- Pre-commit hook for `black`: Applies `black` to the staged Python files
before accepting a commit.
- Pre-commit hook for `make_rst`: Checks the class reference syntax using
`make_rst.py`.
## Installation
Copy all the files from this folder into your `.git/hooks` folder, and make
sure the hooks and helper scripts are executable.
#### Linux/MacOS
The hooks rely on bash scripts and tools which should be in the system `PATH`,
so they should work out of the box on Linux/macOS.
#### Windows
##### clang-format
- Download LLVM for Windows (version 13 or later) from
<https://releases.llvm.org/download.html>
- Make sure LLVM is added to the `PATH` during installation
##### black
- Python installation: make sure Python is added to the `PATH`
- Install `black` - in any console: `pip3 install black`

View File

@@ -0,0 +1,48 @@
#!/bin/sh
# Provide the canonicalize filename (physical filename with out any symlinks)
# like the GNU version readlink with the -f option regardless of the version of
# readlink (GNU or BSD).
# This file is part of a set of unofficial pre-commit hooks available
# at github.
# Link: https://github.com/githubbrowser/Pre-commit-hooks
# Contact: David Martin, david.martin.mailbox@googlemail.com
###########################################################
# There should be no need to change anything below this line.
# Canonicalize by recursively following every symlink in every component of the
# specified filename. This should reproduce the results of the GNU version of
# readlink with the -f option.
#
# Reference: https://stackoverflow.com/questions/1055671/how-can-i-get-the-behavior-of-gnus-readlink-f-on-a-mac
canonicalize_filename () {
local target_file="$1"
local physical_directory=""
local result=""
# Need to restore the working directory after work.
local working_dir="`pwd`"
cd -- "$(dirname -- "$target_file")"
target_file="$(basename -- "$target_file")"
# Iterate down a (possible) chain of symlinks
while [ -L "$target_file" ]
do
target_file="$(readlink -- "$target_file")"
cd -- "$(dirname -- "$target_file")"
target_file="$(basename -- "$target_file")"
done
# Compute the canonicalized name by finding the physical path
# for the directory we're in and appending the target file.
physical_directory="`pwd -P`"
result="$physical_directory/$target_file"
# restore the working directory after work.
cd -- "$working_dir"
echo "$result"
}

50
misc/hooks/pre-commit Executable file
View File

@@ -0,0 +1,50 @@
#!/bin/sh
# Git pre-commit hook that runs multiple hooks specified in $HOOKS.
# Make sure this script is executable. Bypass hooks with git commit --no-verify.
# This file is part of a set of unofficial pre-commit hooks available
# at github.
# Link: https://github.com/githubbrowser/Pre-commit-hooks
# Contact: David Martin, david.martin.mailbox@googlemail.com
###########################################################
# CONFIGURATION:
# pre-commit hooks to be executed. They should be in the same .git/hooks/ folder
# as this script. Hooks should return 0 if successful and nonzero to cancel the
# commit. They are executed in the order in which they are listed.
#HOOKS="pre-commit-compile pre-commit-uncrustify"
HOOKS="pre-commit-clang-format pre-commit-black"
###########################################################
# There should be no need to change anything below this line.
. "$(dirname -- "$0")/canonicalize_filename.sh"
# exit on error
set -e
# Absolute path to this script, e.g. /home/user/bin/foo.sh
SCRIPT="$(canonicalize_filename "$0")"
# Absolute path this script is in, thus /home/user/bin
SCRIPTPATH="$(dirname -- "$SCRIPT")"
for hook in $HOOKS
do
echo "Running hook: $hook"
# run hook if it exists
# if it returns with nonzero exit with 1 and thus abort the commit
if [ -f "$SCRIPTPATH/$hook" ]; then
"$SCRIPTPATH/$hook"
if [ $? != 0 ]; then
exit 1
fi
else
echo "Error: file $hook not found."
echo "Aborting commit. Make sure the hook is in $SCRIPTPATH and executable."
echo "You can disable it by removing it from the list in $SCRIPT."
echo "You can skip all pre-commit hooks with --no-verify (not recommended)."
exit 1
fi
done

202
misc/hooks/pre-commit-black Executable file
View File

@@ -0,0 +1,202 @@
#!/usr/bin/env bash
# git pre-commit hook that runs a black stylecheck.
# Based on pre-commit-clang-format.
##################################################################
# SETTINGS
# Set path to black binary.
BLACK=`which black 2>/dev/null`
BLACK_OPTIONS="-l 120"
# Remove any older patches from previous commits. Set to true or false.
DELETE_OLD_PATCHES=false
# File types to parse.
FILE_NAMES="SConstruct SCsub"
FILE_EXTS=".py"
# Use pygmentize instead of cat to parse diff with highlighting.
# Install it with `pip install pygments` (Linux) or `easy_install Pygments` (Mac)
PYGMENTIZE=`which pygmentize 2>/dev/null`
if [ ! -z "$PYGMENTIZE" ]; then
READER="pygmentize -l diff"
else
READER=cat
fi
# Path to zenity
ZENITY=`which zenity 2>/dev/null`
# Path to xmessage
XMSG=`which xmessage 2>/dev/null`
# Path to powershell (Windows only)
PWSH=`which powershell 2>/dev/null`
##################################################################
# There should be no need to change anything below this line.
. "$(dirname -- "$0")/canonicalize_filename.sh"
# exit on error
set -e
# check whether the given file matches any of the set extensions
matches_name_or_extension() {
local filename=$(basename "$1")
local extension=".${filename##*.}"
for name in $FILE_NAMES; do [[ "$name" == "$filename" ]] && return 0; done
for ext in $FILE_EXTS; do [[ "$ext" == "$extension" ]] && return 0; done
return 1
}
# necessary check for initial commit
if git rev-parse --verify HEAD >/dev/null 2>&1 ; then
against=HEAD
else
# Initial commit: diff against an empty tree object
against=4b825dc642cb6eb9a060e54bf8d69288fbee4904
fi
if [ ! -x "$BLACK" ] ; then
if [ ! -t 1 ] ; then
if [ -x "$ZENITY" ] ; then
$ZENITY --error --title="Error" --text="Error: black executable not found."
exit 1
elif [ -x "$XMSG" ] ; then
$XMSG -center -title "Error" "Error: black executable not found."
exit 1
elif [ \( \( "$OSTYPE" = "msys" \) -o \( "$OSTYPE" = "win32" \) \) -a \( -x "$PWSH" \) ]; then
winmessage="$(canonicalize_filename "./.git/hooks/winmessage.ps1")"
$PWSH -noprofile -executionpolicy bypass -file "$winmessage" -center -title "Error" --text "Error: black executable not found."
exit 1
fi
fi
printf "Error: black executable not found.\n"
printf "Set the correct path in $(canonicalize_filename "$0").\n"
exit 1
fi
# create a random filename to store our generated patch
prefix="pre-commit-black"
suffix="$(date +%s)"
patch="/tmp/$prefix-$suffix.patch"
# clean up any older black patches
$DELETE_OLD_PATCHES && rm -f /tmp/$prefix*.patch
# create one patch containing all changes to the files
git diff-index --cached --diff-filter=ACMR --name-only $against -- | while read file;
do
# ignore thirdparty files
if grep -q "thirdparty" <<< $file; then
continue;
fi
# ignore file if not one of the names or extensions we handle
if ! matches_name_or_extension "$file"; then
continue;
fi
# format our file with black, create a patch with diff and append it to our $patch
# The sed call is necessary to transform the patch from
# --- $file timestamp
# +++ $file timestamp
# to both lines working on the same file and having a/ and b/ prefix.
# Else it can not be applied with 'git apply'.
"$BLACK" "$BLACK_OPTIONS" --diff "$file" | \
sed -e "1s|--- |--- a/|" -e "2s|+++ |+++ b/|" >> "$patch"
done
# if no patch has been generated all is ok, clean up the file stub and exit
if [ ! -s "$patch" ] ; then
printf "Files in this commit comply with the black formatter rules.\n"
rm -f "$patch"
exit 0
fi
# a patch has been created, notify the user and exit
printf "\nThe following differences were found between the code to commit "
printf "and the black formatter rules:\n\n"
if [ -t 1 ] ; then
$READER "$patch"
printf "\n"
# Allows us to read user input below, assigns stdin to keyboard
exec < /dev/tty
terminal="1"
else
cat "$patch"
printf "\n"
# Allows non zero zenity/powershell output
set +e
terminal="0"
fi
while true; do
if [ $terminal = "0" ] ; then
if [ -x "$ZENITY" ] ; then
choice=$($ZENITY --text-info --filename="$patch" --width=800 --height=600 --title="Do you want to apply that patch?" --ok-label="Apply" --cancel-label="Do not apply" --extra-button="Apply and stage")
if [ "$?" = "0" ] ; then
yn="Y"
else
if [ "$choice" = "Apply and stage" ] ; then
yn="S"
else
yn="N"
fi
fi
elif [ -x "$XMSG" ] ; then
$XMSG -file "$patch" -buttons "Apply":100,"Apply and stage":200,"Do not apply":0 -center -default "Do not apply" -geometry 800x600 -title "Do you want to apply that patch?"
choice=$?
if [ "$choice" = "100" ] ; then
yn="Y"
elif [ "$choice" = "200" ] ; then
yn="S"
else
yn="N"
fi
elif [ \( \( "$OSTYPE" = "msys" \) -o \( "$OSTYPE" = "win32" \) \) -a \( -x "$PWSH" \) ]; then
winmessage="$(canonicalize_filename "./.git/hooks/winmessage.ps1")"
$PWSH -noprofile -executionpolicy bypass -file "$winmessage" -file "$patch" -buttons "Apply":100,"Apply and stage":200,"Do not apply":0 -center -default "Do not apply" -geometry 800x600 -title "Do you want to apply that patch?"
choice=$?
if [ "$choice" = "100" ] ; then
yn="Y"
elif [ "$choice" = "200" ] ; then
yn="S"
else
yn="N"
fi
else
printf "Error: zenity, xmessage, or powershell executable not found.\n"
exit 1
fi
else
read -p "Do you want to apply that patch (Y - Apply, N - Do not apply, S - Apply and stage files)? [Y/N/S] " yn
fi
case $yn in
[Yy] ) git apply $patch;
printf "The patch was applied. You can now stage the changes and commit again.\n\n";
break
;;
[Nn] ) printf "\nYou can apply these changes with:\n git apply $patch\n";
printf "(may need to be called from the root directory of your repository)\n";
printf "Aborting commit. Apply changes and commit again or skip checking with";
printf " --no-verify (not recommended).\n\n";
break
;;
[Ss] ) git apply $patch;
git diff-index --cached --diff-filter=ACMR --name-only $against -- | while read file;
do git add $file;
done
printf "The patch was applied and the changed files staged. You can now commit.\n\n";
break
;;
* ) echo "Please answer yes or no."
;;
esac
done
exit 1 # we don't commit in any case

View File

@@ -0,0 +1,242 @@
#!/usr/bin/env bash
# git pre-commit hook that runs a clang-format stylecheck.
# Features:
# - abort commit when commit does not comply with the style guidelines
# - create a patch of the proposed style changes
# Modifications for clang-format by rene.milk@wwu.de
# This file is part of a set of unofficial pre-commit hooks available
# at github.
# Link: https://github.com/githubbrowser/Pre-commit-hooks
# Contact: David Martin, david.martin.mailbox@googlemail.com
# Some quality of life modifications made for Godot Engine.
##################################################################
# SETTINGS
# Set path to clang-format binary.
CLANG_FORMAT=`which clang-format 2>/dev/null`
# Remove any older patches from previous commits. Set to true or false.
DELETE_OLD_PATCHES=false
# Only parse files with the extensions in FILE_EXTS. Set to true or false.
# If false every changed file in the commit will be parsed with clang-format.
# If true only files matching one of the extensions are parsed with clang-format.
PARSE_EXTS=true
# File types to parse. Only effective when PARSE_EXTS is true.
FILE_EXTS=".c .h .cpp .hpp .cc .hh .cxx .m .mm .inc .java .glsl"
# Use pygmentize instead of cat to parse diff with highlighting.
# Install it with `pip install pygments` (Linux) or `easy_install Pygments` (Mac)
PYGMENTIZE=`which pygmentize 2>/dev/null`
if [ ! -z "$PYGMENTIZE" ]; then
READER="pygmentize -l diff"
else
READER=cat
fi
# Path to zenity
ZENITY=`which zenity 2>/dev/null`
# Path to xmessage
XMSG=`which xmessage 2>/dev/null`
# Path to powershell (Windows only)
PWSH=`which powershell 2>/dev/null`
##################################################################
# There should be no need to change anything below this line.
. "$(dirname -- "$0")/canonicalize_filename.sh"
# exit on error
set -e
# check whether the given file matches any of the set extensions
matches_extension() {
local filename=$(basename "$1")
local extension=".${filename##*.}"
local ext
for ext in $FILE_EXTS; do [[ "$ext" == "$extension" ]] && return 0; done
return 1
}
# necessary check for initial commit
if git rev-parse --verify HEAD >/dev/null 2>&1 ; then
against=HEAD
else
# Initial commit: diff against an empty tree object
against=4b825dc642cb6eb9a060e54bf8d69288fbee4904
fi
# To get consistent formatting, we recommend contributors to use the same
# clang-format version as CI.
RECOMMENDED_CLANG_FORMAT_MAJOR_MIN="12"
RECOMMENDED_CLANG_FORMAT_MAJOR_MAX="13"
if [ ! -x "$CLANG_FORMAT" ] ; then
message="Error: clang-format executable not found. Please install clang-format $RECOMMENDED_CLANG_FORMAT_MAJOR_MAX."
if [ ! -t 1 ] ; then
if [ -x "$ZENITY" ] ; then
$ZENITY --error --title="Error" --text="$message"
exit 1
elif [ -x "$XMSG" ] ; then
$XMSG -center -title "Error" "$message"
exit 1
elif [ \( \( "$OSTYPE" = "msys" \) -o \( "$OSTYPE" = "win32" \) \) -a \( -x "$PWSH" \) ]; then
winmessage="$(canonicalize_filename "./.git/hooks/winmessage.ps1")"
$PWSH -noprofile -executionpolicy bypass -file "$winmessage" -center -title "Error" --text "$message"
exit 1
fi
fi
printf "$message\n"
printf "Set the correct path in $(canonicalize_filename "$0").\n"
exit 1
fi
# The returned string can be inconsistent depending on where clang-format comes from.
# Example output strings reported by `clang-format --version`:
# - Ubuntu: "Ubuntu clang-format version 11.0.0-2"
# - Fedora: "clang-format version 11.0.0 (Fedora 11.0.0-2.fc33)"
CLANG_FORMAT_VERSION="$(clang-format --version | sed "s/[^0-9\.]*\([0-9\.]*\).*/\1/")"
CLANG_FORMAT_MAJOR="$(echo "$CLANG_FORMAT_VERSION" | cut -d. -f1)"
if [[ "$CLANG_FORMAT_MAJOR" -lt "$RECOMMENDED_CLANG_FORMAT_MAJOR_MIN" || "$CLANG_FORMAT_MAJOR" -gt "$RECOMMENDED_CLANG_FORMAT_MAJOR_MAX" ]]; then
echo "Warning: Your clang-format binary is the wrong version ($CLANG_FORMAT_VERSION, expected between $RECOMMENDED_CLANG_FORMAT_MAJOR_MIN and $RECOMMENDED_CLANG_FORMAT_MAJOR_MAX)."
echo " Consider upgrading or downgrading clang-format as formatting may not be applied correctly."
fi
# create a random filename to store our generated patch
prefix="pre-commit-clang-format"
suffix="$(date +%s)"
patch="/tmp/$prefix-$suffix.patch"
# clean up any older clang-format patches
$DELETE_OLD_PATCHES && rm -f /tmp/$prefix*.patch
# create one patch containing all changes to the files
git diff-index --cached --diff-filter=ACMR --name-only $against -- | while read file;
do
# ignore thirdparty files
if grep -q "thirdparty" <<< $file; then
continue;
fi
if grep -q "platform/android/java/lib/src/com" <<< $file; then
continue;
fi
if grep -q "\-so_wrap." <<< $file; then
continue;
fi
# ignore file if we do check for file extensions and the file
# does not match any of the extensions specified in $FILE_EXTS
if $PARSE_EXTS && ! matches_extension "$file"; then
continue;
fi
# clang-format our sourcefile, create a patch with diff and append it to our $patch
# The sed call is necessary to transform the patch from
# --- $file timestamp
# +++ - timestamp
# to both lines working on the same file and having a/ and b/ prefix.
# Else it can not be applied with 'git apply'.
"$CLANG_FORMAT" -style=file "$file" --Wno-error=unknown | \
diff -u "$file" - | \
sed -e "1s|--- |--- a/|" -e "2s|+++ -|+++ b/$file|" >> "$patch"
done
# if no patch has been generated all is ok, clean up the file stub and exit
if [ ! -s "$patch" ] ; then
printf "Files in this commit comply with the clang-format rules.\n"
rm -f "$patch"
exit 0
fi
# a patch has been created, notify the user and exit
printf "\nThe following differences were found between the code to commit "
printf "and the clang-format rules:\n\n"
if [ -t 1 ] ; then
$READER "$patch"
printf "\n"
# Allows us to read user input below, assigns stdin to keyboard
exec < /dev/tty
terminal="1"
else
cat "$patch"
printf "\n"
# Allows non zero zenity/powershell output
set +e
terminal="0"
fi
while true; do
if [ $terminal = "0" ] ; then
if [ -x "$ZENITY" ] ; then
choice=$($ZENITY --text-info --filename="$patch" --width=800 --height=600 --title="Do you want to apply that patch?" --ok-label="Apply" --cancel-label="Do not apply" --extra-button="Apply and stage")
if [ "$?" = "0" ] ; then
yn="Y"
else
if [ "$choice" = "Apply and stage" ] ; then
yn="S"
else
yn="N"
fi
fi
elif [ -x "$XMSG" ] ; then
$XMSG -file "$patch" -buttons "Apply":100,"Apply and stage":200,"Do not apply":0 -center -default "Do not apply" -geometry 800x600 -title "Do you want to apply that patch?"
choice=$?
if [ "$choice" = "100" ] ; then
yn="Y"
elif [ "$choice" = "200" ] ; then
yn="S"
else
yn="N"
fi
elif [ \( \( "$OSTYPE" = "msys" \) -o \( "$OSTYPE" = "win32" \) \) -a \( -x "$PWSH" \) ]; then
winmessage="$(canonicalize_filename "./.git/hooks/winmessage.ps1")"
$PWSH -noprofile -executionpolicy bypass -file "$winmessage" -file "$patch" -buttons "Apply":100,"Apply and stage":200,"Do not apply":0 -center -default "Do not apply" -geometry 800x600 -title "Do you want to apply that patch?"
choice=$?
if [ "$choice" = "100" ] ; then
yn="Y"
elif [ "$choice" = "200" ] ; then
yn="S"
else
yn="N"
fi
else
printf "Error: zenity, xmessage, or powershell executable not found.\n"
exit 1
fi
else
read -p "Do you want to apply that patch (Y - Apply, N - Do not apply, S - Apply and stage files)? [Y/N/S] " yn
fi
case $yn in
[Yy] ) git apply $patch;
printf "The patch was applied. You can now stage the changes and commit again.\n\n";
break
;;
[Nn] ) printf "\nYou can apply these changes with:\n git apply $patch\n";
printf "(may need to be called from the root directory of your repository)\n";
printf "Aborting commit. Apply changes and commit again or skip checking with";
printf " --no-verify (not recommended).\n\n";
break
;;
[Ss] ) git apply $patch;
git diff-index --cached --diff-filter=ACMR --name-only $against -- | while read file;
do git add $file;
done
printf "The patch was applied and the changed files staged. You can now commit.\n\n";
break
;;
* ) echo "Please answer yes or no."
;;
esac
done
exit 1 # we don't commit in any case

103
misc/hooks/winmessage.ps1 Normal file
View File

@@ -0,0 +1,103 @@
Param (
[string]$file = "",
[string]$text = "",
[string]$buttons = "OK:0",
[string]$default = "",
[switch]$nearmouse = $false,
[switch]$center = $false,
[string]$geometry = "",
[int32]$timeout = 0,
[string]$title = "Message"
)
Add-Type -assembly System.Windows.Forms
$global:Result = 0
$main_form = New-Object System.Windows.Forms.Form
$main_form.Text = $title
$geometry_data = $geometry.Split("+")
if ($geometry_data.Length -ge 1) {
$size_data = $geometry_data[0].Split("x")
if ($size_data.Length -eq 2) {
$main_form.Width = $size_data[0]
$main_form.Height = $size_data[1]
}
}
if ($geometry_data.Length -eq 3) {
$main_form.StartPosition = [System.Windows.Forms.FormStartPosition]::Manual
$main_form.Location = New-Object System.Drawing.Point($geometry_data[1], $geometry_data[2])
}
if ($nearmouse) {
$main_form.StartPosition = [System.Windows.Forms.FormStartPosition]::Manual
$main_form.Location = System.Windows.Forms.Cursor.Position
}
if ($center) {
$main_form.StartPosition = [System.Windows.Forms.FormStartPosition]::CenterScreen
}
$main_form.SuspendLayout()
$button_panel = New-Object System.Windows.Forms.FlowLayoutPanel
$button_panel.SuspendLayout()
$button_panel.FlowDirection = [System.Windows.Forms.FlowDirection]::RightToLeft
$button_panel.Dock = [System.Windows.Forms.DockStyle]::Bottom
$button_panel.Autosize = $true
if ($file -ne "") {
$text = [IO.File]::ReadAllText($file).replace("`n", "`r`n")
}
if ($text -ne "") {
$text_box = New-Object System.Windows.Forms.TextBox
$text_box.Multiline = $true
$text_box.ReadOnly = $true
$text_box.Autosize = $true
$text_box.Text = $text
$text_box.Select(0,0)
$text_box.Dock = [System.Windows.Forms.DockStyle]::Fill
$main_form.Controls.Add($text_box)
}
$buttons_array = $buttons.Split(",")
foreach ($button in $buttons_array) {
$button_data = $button.Split(":")
$button_ctl = New-Object System.Windows.Forms.Button
if ($button_data.Length -eq 2) {
$button_ctl.Tag = $button_data[1]
} else {
$button_ctl.Tag = 100 + $buttons_array.IndexOf($button)
}
if ($default -eq $button_data[0]) {
$main_form.AcceptButton = $button_ctl
}
$button_ctl.Autosize = $true
$button_ctl.Text = $button_data[0]
$button_ctl.Add_Click(
{
Param($sender)
$global:Result = $sender.Tag
$main_form.Close()
}
)
$button_panel.Controls.Add($button_ctl)
}
$main_form.Controls.Add($button_panel)
$button_panel.ResumeLayout($false)
$main_form.ResumeLayout($false)
if ($timeout -gt 0) {
$timer = New-Object System.Windows.Forms.Timer
$timer.Add_Tick(
{
$global:Result = 0
$main_form.Close()
}
)
$timer.Interval = $timeout
$timer.Start()
}
$dlg_res = $main_form.ShowDialog()
[Environment]::Exit($global:Result)

Some files were not shown because too many files have changed in this diff Show More