mirror of
https://github.com/godotengine/godot-cpp.git
synced 2026-01-01 05:48:37 +03:00
Compare commits
91 Commits
master
...
godot-4.1.
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4b0ee13327 | ||
|
|
e4978558e6 | ||
|
|
30ebe5fdf9 | ||
|
|
e897dbe58a | ||
|
|
28a6609c0b | ||
|
|
7f3e725a8a | ||
|
|
8e5d7c9268 | ||
|
|
974e6c6f86 | ||
|
|
c8fa4c0fd0 | ||
|
|
594a93f8ac | ||
|
|
9e48c45bfc | ||
|
|
76d6ce7136 | ||
|
|
e99d7b3b7e | ||
|
|
07e245e3e4 | ||
|
|
ed576f8318 | ||
|
|
f7a9d32f32 | ||
|
|
08da55cd0b | ||
|
|
670c4d0eac | ||
|
|
bab62a4d72 | ||
|
|
1ac8627b2e | ||
|
|
6202bf141e | ||
|
|
4b63d795e4 | ||
|
|
2cc967787a | ||
|
|
6884ca9be0 | ||
|
|
dde0bbb93d | ||
|
|
1c03aa7746 | ||
|
|
82475b215b | ||
|
|
49098fbdc7 | ||
|
|
756190705e | ||
|
|
2e42c7020e | ||
|
|
e9273e8528 | ||
|
|
b1bd58d7da | ||
|
|
d5a2e8e797 | ||
|
|
6bb4b1d321 | ||
|
|
51aeda7437 | ||
|
|
cd904155a8 | ||
|
|
b622b11df3 | ||
|
|
92449b46e1 | ||
|
|
e8b6887b36 | ||
|
|
631cd5fe37 | ||
|
|
731a10a4ea | ||
|
|
a1ae58448c | ||
|
|
805cdde0b7 | ||
|
|
29335d8f5c | ||
|
|
c5f47b2a4e | ||
|
|
df5b1a9a69 | ||
|
|
04b34077d8 | ||
|
|
9d813310bb | ||
|
|
ef8a499eac | ||
|
|
698da13d66 | ||
|
|
8295486fdb | ||
|
|
7704a9d054 | ||
|
|
f7ffc4fe4d | ||
|
|
62cb5eac47 | ||
|
|
03ea717742 | ||
|
|
e389f7a50c | ||
|
|
0b1c8bcac3 | ||
|
|
857d8e3a56 | ||
|
|
ec6e51b3a4 | ||
|
|
f8054cca80 | ||
|
|
59ebcfd744 | ||
|
|
205beacc5b | ||
|
|
3b3f357de9 | ||
|
|
48b92acf8c | ||
|
|
4eed2d7be0 | ||
|
|
bc82ae8b0b | ||
|
|
590e267902 | ||
|
|
3be7ec4162 | ||
|
|
dd8e1def67 | ||
|
|
dcd7a69512 | ||
|
|
354ed1e79d | ||
|
|
014132d4c0 | ||
|
|
bc980b59ff | ||
|
|
c3771fb065 | ||
|
|
63755b2a32 | ||
|
|
ce5dd378d9 | ||
|
|
c6fe6533f9 | ||
|
|
170a691a7e | ||
|
|
738ef9baf8 | ||
|
|
c7afd0f89a | ||
|
|
6789b29b72 | ||
|
|
960c906da1 | ||
|
|
0f2d3652e5 | ||
|
|
28494f0bd5 | ||
|
|
4fb9af7fb2 | ||
|
|
6fa6b8b178 | ||
|
|
784c3dc012 | ||
|
|
7a9b323931 | ||
|
|
e75ec636db | ||
|
|
5dda0212f6 | ||
|
|
011965d864 |
60
.github/workflows/ci.yml
vendored
60
.github/workflows/ci.yml
vendored
@@ -65,7 +65,7 @@ jobs:
|
||||
platform: android
|
||||
artifact-name: godot-cpp-android-arm64-release
|
||||
artifact-path: bin/libgodot-cpp.android.template_release.arm64.a
|
||||
flags: ANDROID_NDK_ROOT=$ANDROID_NDK_LATEST_HOME arch=arm64
|
||||
flags: arch=arm64
|
||||
run-tests: false
|
||||
cache-name: android-arm64
|
||||
|
||||
@@ -78,12 +78,22 @@ jobs:
|
||||
run-tests: false
|
||||
cache-name: ios-arm64
|
||||
|
||||
- name: 🌐 Web (wasm32)
|
||||
os: ubuntu-20.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
|
||||
EM_CACHE_FOLDER: "emsdk-cache"
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: recursive
|
||||
|
||||
@@ -94,42 +104,52 @@ jobs:
|
||||
continue-on-error: true
|
||||
|
||||
- name: Set up Python (for SCons)
|
||||
uses: actions/setup-python@v4
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
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: Android dependencies
|
||||
if: ${{ matrix.platform == 'android' }}
|
||||
uses: nttld/setup-ndk@v1
|
||||
with:
|
||||
ndk-version: r23c
|
||||
link-to-sdk: true
|
||||
|
||||
- name: Web dependencies
|
||||
if: ${{ matrix.platform == 'web' }}
|
||||
uses: mymindstorm/setup-emsdk@v14
|
||||
with:
|
||||
version: ${{env.EM_VERSION}}
|
||||
actions-cache-folder: ${{env.EM_CACHE_FOLDER}}
|
||||
|
||||
- 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: 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
|
||||
|
||||
- name: Generate godot-cpp sources only
|
||||
run: |
|
||||
scons platform=${{ matrix.platform }} build_library=no ${{ matrix.flags }}
|
||||
scons platform=${{ matrix.platform }} verbose=yes build_library=no ${{ matrix.flags }}
|
||||
scons -c
|
||||
|
||||
- name: Build godot-cpp (debug)
|
||||
run: |
|
||||
scons platform=${{ matrix.platform }} target=template_debug ${{ matrix.flags }}
|
||||
scons platform=${{ matrix.platform }} verbose=yes target=template_debug ${{ matrix.flags }}
|
||||
|
||||
- name: Build test without rebuilding godot-cpp (debug)
|
||||
run: |
|
||||
cd test
|
||||
scons platform=${{ matrix.platform }} target=template_debug ${{ matrix.flags }} build_library=no
|
||||
scons platform=${{ matrix.platform }} verbose=yes target=template_debug ${{ matrix.flags }} build_library=no
|
||||
|
||||
- name: Build test and godot-cpp (release)
|
||||
run: |
|
||||
cd test
|
||||
scons platform=${{ matrix.platform }} target=template_release ${{ matrix.flags }}
|
||||
scons platform=${{ matrix.platform }} verbose=yes target=template_release ${{ matrix.flags }}
|
||||
|
||||
- name: Download latest Godot artifacts
|
||||
uses: dsnopek/action-download-artifact@1322f74e2dac9feed2ee76a32d9ae1ca3b4cf4e9
|
||||
@@ -153,7 +173,7 @@ jobs:
|
||||
./godot-artifacts/godot.linuxbsd.editor.x86_64.mono --headless --version
|
||||
cd test
|
||||
# Need to run the editor so .godot is generated... but it crashes! Ignore that :-)
|
||||
(cd project && (../../godot-artifacts/godot.linuxbsd.editor.x86_64.mono --editor --headless --quit >/dev/null 2>&1 || true))
|
||||
(cd project && (timeout 10 ../../godot-artifacts/godot.linuxbsd.editor.x86_64.mono --editor --headless --quit >/dev/null 2>&1 || true))
|
||||
GODOT=../godot-artifacts/godot.linuxbsd.editor.x86_64.mono ./run-tests.sh
|
||||
|
||||
- name: Upload artifact
|
||||
@@ -168,7 +188,7 @@ jobs:
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: recursive
|
||||
|
||||
@@ -192,7 +212,7 @@ jobs:
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: recursive
|
||||
|
||||
@@ -216,7 +236,7 @@ jobs:
|
||||
runs-on: windows-2019
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: recursive
|
||||
|
||||
|
||||
2
.github/workflows/static_checks.yml
vendored
2
.github/workflows/static_checks.yml
vendored
@@ -11,7 +11,7 @@ jobs:
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
|
||||
# Azure repositories are not reliable, we need to prevent Azure giving us packages.
|
||||
- name: Make apt sources.list use the default Ubuntu repositories
|
||||
|
||||
4
.gitignore
vendored
4
.gitignore
vendored
@@ -191,3 +191,7 @@ godot.creator.*
|
||||
|
||||
# compile commands (https://clang.llvm.org/docs/JSONCompilationDatabase.html)
|
||||
compile_commands.json
|
||||
|
||||
# Python development
|
||||
.venv
|
||||
venv
|
||||
|
||||
@@ -37,7 +37,7 @@
|
||||
# Todo
|
||||
# Test build for Windows, Mac and mingw.
|
||||
|
||||
cmake_minimum_required(VERSION 3.12)
|
||||
cmake_minimum_required(VERSION 3.13)
|
||||
project(godot-cpp LANGUAGES CXX)
|
||||
|
||||
option(GENERATE_TEMPLATE_GET_NODE "Generate a template version of the Node class's get_node." ON)
|
||||
@@ -47,11 +47,6 @@ option(GODOT_CPP_WARNING_AS_ERROR "Treat warnings as errors" OFF)
|
||||
# Add path to modules
|
||||
list( APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake/" )
|
||||
|
||||
# Check if we are building ourself or being included
|
||||
if(${PROJECT_NAME} STREQUAL ${CMAKE_PROJECT_NAME})
|
||||
set(GODOT_CPP_BUILDING_SELF ON)
|
||||
endif()
|
||||
|
||||
# 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>" )
|
||||
@@ -72,21 +67,22 @@ 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(FLOAT_PRECISION "single" CACHE STRING "")
|
||||
if ("${FLOAT_PRECISION}" STREQUAL "double")
|
||||
add_definitions(-DREAL_T_IS_DOUBLE)
|
||||
endif()
|
||||
|
||||
set(GODOT_COMPILE_FLAGS )
|
||||
|
||||
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
|
||||
# using Visual Studio C++
|
||||
set(GODOT_COMPILE_FLAGS "/EHsc /utf-8") # /GF /MP
|
||||
set(GODOT_COMPILE_FLAGS "/utf-8") # /GF /MP
|
||||
|
||||
if(CMAKE_BUILD_TYPE MATCHES Debug)
|
||||
set(GODOT_COMPILE_FLAGS "${GODOT_COMPILE_FLAGS} /MDd") # /Od /RTC1 /Zi
|
||||
@@ -98,15 +94,28 @@ if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
|
||||
|
||||
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")
|
||||
set(GODOT_COMPILE_FLAGS "${GODOT_COMPILE_FLAGS} -fno-omit-frame-pointer -O0 -g")
|
||||
else()
|
||||
set(GODOT_COMPILE_FLAGS "${GODOT_COMPILE_FLAGS} -O3")
|
||||
endif(CMAKE_BUILD_TYPE MATCHES Debug)
|
||||
endif()
|
||||
|
||||
# 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(GODOT_DISABLE_EXCEPTIONS OFF "Force disabling exception handling code")
|
||||
if (GODOT_DISABLE_EXCEPTIONS)
|
||||
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
|
||||
set(GODOT_COMPILE_FLAGS "${GODOT_COMPILE_FLAGS} -D_HAS_EXCEPTIONS=0")
|
||||
else()
|
||||
set(GODOT_COMPILE_FLAGS "${GODOT_COMPILE_FLAGS} -fno-exceptions")
|
||||
endif()
|
||||
else()
|
||||
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
|
||||
set(GODOT_COMPILE_FLAGS "${GODOT_COMPILE_FLAGS} /EHsc")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Generate source from the bindings file
|
||||
find_package(Python3 3.4 REQUIRED) # pathlib should be present
|
||||
if(GENERATE_TEMPLATE_GET_NODE)
|
||||
@@ -118,6 +127,7 @@ 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
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
)
|
||||
|
||||
add_custom_command(OUTPUT ${GENERATED_FILES_LIST}
|
||||
@@ -143,12 +153,6 @@ 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
|
||||
|
||||
50
README.md
50
README.md
@@ -2,11 +2,15 @@
|
||||
|
||||
> **Warning**
|
||||
>
|
||||
> This repository's `master` branch is only usable with the latest version of
|
||||
> Godot's ([GDExtension](https://godotengine.org/article/introducing-gd-extensions))
|
||||
> API (Godot 4.1 and later).
|
||||
> 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 Godot 4.0.x, switch to the [`4.0`](https://github.com/godotengine/godot-cpp/tree/4.0) branch.
|
||||
> For users of stable branches, switch to the branch matching your target Godot version:
|
||||
> - [`4.0`](https://github.com/godotengine/godot-cpp/tree/4.0)
|
||||
> - [`4.1`](https://github.com/godotengine/godot-cpp/tree/4.1)
|
||||
>
|
||||
> Or check out the Git tag matching your Godot version (e.g. `godot-4.1.1-stable`).
|
||||
>
|
||||
> 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.
|
||||
@@ -52,9 +56,10 @@ 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
|
||||
[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.
|
||||
[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.
|
||||
|
||||
## Contributing
|
||||
|
||||
@@ -68,7 +73,10 @@ so formatting is done before your changes are submitted.
|
||||
|
||||
## Getting started
|
||||
|
||||
It's a bit similar to what it was for 3.x but also a bit different.
|
||||
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.
|
||||
|
||||
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,
|
||||
@@ -76,22 +84,22 @@ 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.
|
||||
Follow [the example](test/demo/example.gdextension):
|
||||
See [example.gdextension](test/project/example.gdextension) used in the test project:
|
||||
|
||||
```ini
|
||||
[configuration]
|
||||
|
||||
entry_symbol = "example_library_init"
|
||||
compatibility_minimum = 4.1
|
||||
compatibility_minimum = "4.1"
|
||||
|
||||
[libraries]
|
||||
|
||||
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"
|
||||
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"
|
||||
# Repeat for other architectures to support arm64, rv64, etc.
|
||||
```
|
||||
|
||||
@@ -123,12 +131,16 @@ void initialize_example_module(ModuleInitializationLevel p_level) {
|
||||
if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
|
||||
return;
|
||||
}
|
||||
ClassDB::register_class<Example>();
|
||||
GDREGISTER_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.
|
||||
|
||||
## Included example
|
||||
## Examples and templates
|
||||
|
||||
Check the project in the `test` folder for an example on how to use and register different things.
|
||||
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).
|
||||
|
||||
260
SConstruct
260
SConstruct
@@ -5,52 +5,11 @@ import platform
|
||||
import sys
|
||||
import subprocess
|
||||
from binding_generator import scons_generate_bindings, scons_emit_files
|
||||
from SCons.Errors import UserError
|
||||
|
||||
|
||||
EnsureSConsVersion(4, 0)
|
||||
|
||||
|
||||
def add_sources(sources, dir, extension):
|
||||
for f in os.listdir(dir):
|
||||
if f.endswith("." + extension):
|
||||
sources.append(dir + "/" + f)
|
||||
|
||||
|
||||
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>")
|
||||
|
||||
try:
|
||||
Import("env")
|
||||
except:
|
||||
@@ -60,26 +19,12 @@ except:
|
||||
|
||||
env.PrependENVPath("PATH", os.getenv("PATH"))
|
||||
|
||||
# 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:
|
||||
pass
|
||||
profile = ARGUMENTS.get("profile", "")
|
||||
if profile:
|
||||
if os.path.isfile(profile):
|
||||
@@ -87,143 +32,12 @@ if profile:
|
||||
elif os.path.isfile(profile + ".py"):
|
||||
customs.append(profile + ".py")
|
||||
opts = Variables(customs, ARGUMENTS)
|
||||
|
||||
platforms = ("linux", "macos", "windows", "android", "ios", "javascript")
|
||||
opts.Add(
|
||||
EnumVariable(
|
||||
key="platform",
|
||||
help="Target platform",
|
||||
default=env.get("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(
|
||||
key="target",
|
||||
help="Compilation target",
|
||||
default=env.get("target", "template_debug"),
|
||||
allowed_values=("editor", "template_release", "template_debug"),
|
||||
)
|
||||
)
|
||||
opts.Add(
|
||||
PathVariable(
|
||||
key="gdextension_dir",
|
||||
help="Path to a custom directory containing GDExtension interface header and API JSON file",
|
||||
default=env.get("gdextension_dir", None),
|
||||
validator=validate_gdextension_dir,
|
||||
)
|
||||
)
|
||||
opts.Add(
|
||||
PathVariable(
|
||||
key="custom_api_file",
|
||||
help="Path to a custom GDExtension API JSON file (takes precedence over `gdextension_dir`)",
|
||||
default=env.get("custom_api_file", None),
|
||||
validator=validate_api_file,
|
||||
)
|
||||
)
|
||||
opts.Add(
|
||||
BoolVariable(
|
||||
key="generate_bindings",
|
||||
help="Force GDExtension API bindings generation. Auto-detected by default.",
|
||||
default=env.get("generate_bindings", False),
|
||||
)
|
||||
)
|
||||
opts.Add(
|
||||
BoolVariable(
|
||||
key="generate_template_get_node",
|
||||
help="Generate a template version of the Node class's get_node.",
|
||||
default=env.get("generate_template_get_node", True),
|
||||
)
|
||||
)
|
||||
|
||||
opts.Add(BoolVariable(key="build_library", help="Build the godot-cpp library.", default=env.get("build_library", True)))
|
||||
opts.Add(
|
||||
EnumVariable(
|
||||
key="precision",
|
||||
help="Set the floating-point precision level",
|
||||
default=env.get("precision", "single"),
|
||||
allowed_values=("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(
|
||||
key="arch",
|
||||
help="CPU architecture",
|
||||
default=env.get("arch", ""),
|
||||
allowed_values=architecture_array,
|
||||
map=architecture_aliases,
|
||||
)
|
||||
)
|
||||
|
||||
# Targets flags tool (optimizations, debug symbols)
|
||||
target_tool = Tool("targets", toolpath=["tools"])
|
||||
target_tool.options(opts)
|
||||
|
||||
cpp_tool = Tool("godotcpp", toolpath=["tools"])
|
||||
cpp_tool.options(opts, env)
|
||||
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:
|
||||
@@ -231,66 +45,12 @@ 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")
|
||||
|
||||
# Forces bindings regeneration.
|
||||
if env["generate_bindings"]:
|
||||
AlwaysBuild(bindings)
|
||||
NoCache(bindings)
|
||||
cpp_tool.generate(env)
|
||||
library = env.GodotCPP()
|
||||
|
||||
# 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")
|
||||
|
||||
@@ -97,9 +97,10 @@ def get_file_list(api_filepath, output_dir, headers=False, sources=False):
|
||||
files.append(str(source_filename.as_posix()))
|
||||
|
||||
for engine_class in api["classes"]:
|
||||
# TODO: Properly setup this singleton since it conflicts with ClassDB in the bindings.
|
||||
# Generate code for the ClassDB singleton under a different name.
|
||||
if engine_class["name"] == "ClassDB":
|
||||
continue
|
||||
engine_class["name"] = "ClassDBSingleton"
|
||||
engine_class["alias_for"] = "ClassDB"
|
||||
header_filename = include_gen_folder / "classes" / (camel_to_snake(engine_class["name"]) + ".hpp")
|
||||
source_filename = source_gen_folder / "classes" / (camel_to_snake(engine_class["name"]) + ".cpp")
|
||||
if headers:
|
||||
@@ -123,21 +124,18 @@ def get_file_list(api_filepath, output_dir, headers=False, sources=False):
|
||||
include_gen_folder / "variant" / "variant_size.hpp",
|
||||
include_gen_folder / "classes" / "global_constants.hpp",
|
||||
include_gen_folder / "classes" / "global_constants_binds.hpp",
|
||||
include_gen_folder / "core" / "version.hpp",
|
||||
]:
|
||||
files.append(str(path.as_posix()))
|
||||
if sources:
|
||||
utility_functions_source_path = source_gen_folder / "variant" / "utility_functions.cpp"
|
||||
files.append(str(utility_functions_source_path.as_posix()))
|
||||
register_engine_classes_source_path = source_gen_folder / "register_engine_classes.cpp"
|
||||
files.append(str(register_engine_classes_source_path.as_posix()))
|
||||
|
||||
return files
|
||||
|
||||
|
||||
def print_file_list(api_filepath, output_dir, headers=False, sources=False):
|
||||
end = ";"
|
||||
for f in get_file_list(api_filepath, output_dir, headers, sources):
|
||||
print(f, end=end)
|
||||
print(*get_file_list(api_filepath, output_dir, headers, sources), sep=";", end=None)
|
||||
|
||||
|
||||
def scons_emit_files(target, source, env):
|
||||
@@ -173,6 +171,7 @@ def generate_bindings(api_filepath, use_template_get_node, bits="64", precision=
|
||||
print("Built-in type config: " + real_t + "_" + bits)
|
||||
|
||||
generate_global_constants(api, target_dir)
|
||||
generate_version_header(api, target_dir)
|
||||
generate_global_constant_binds(api, target_dir)
|
||||
generate_builtin_bindings(api, target_dir, real_t + "_" + bits)
|
||||
generate_engine_classes_bindings(api, target_dir, use_template_get_node)
|
||||
@@ -376,6 +375,10 @@ def generate_builtin_class_header(builtin_api, size, used_classes, fully_used_cl
|
||||
if class_name == "PackedVector3Array":
|
||||
result.append("#include <godot_cpp/variant/vector3.hpp>")
|
||||
|
||||
if is_packed_array(class_name):
|
||||
result.append("#include <godot_cpp/core/error_macros.hpp>")
|
||||
result.append("#include <initializer_list>")
|
||||
|
||||
if class_name == "Array":
|
||||
result.append("#include <godot_cpp/variant/array_helpers.hpp>")
|
||||
|
||||
@@ -414,6 +417,8 @@ def generate_builtin_class_header(builtin_api, size, used_classes, fully_used_cl
|
||||
result.append("")
|
||||
result.append("\tstatic struct _MethodBindings {")
|
||||
|
||||
result.append("\t\tGDExtensionTypeFromVariantConstructorFunc from_variant_constructor;")
|
||||
|
||||
if "constructors" in builtin_api:
|
||||
for constructor in builtin_api["constructors"]:
|
||||
result.append(f'\t\tGDExtensionPtrConstructor constructor_{constructor["index"]};')
|
||||
@@ -454,6 +459,9 @@ def generate_builtin_class_header(builtin_api, size, used_classes, fully_used_cl
|
||||
result.append("\tstatic void init_bindings();")
|
||||
result.append("\tstatic void _init_bindings_constructors_destructor();")
|
||||
|
||||
result.append("")
|
||||
result.append(f"\t{class_name}(const Variant *p_variant);")
|
||||
|
||||
result.append("")
|
||||
result.append("public:")
|
||||
|
||||
@@ -512,7 +520,7 @@ def generate_builtin_class_header(builtin_api, size, used_classes, fully_used_cl
|
||||
|
||||
vararg = method["is_vararg"]
|
||||
if vararg:
|
||||
result.append("\ttemplate<class... Args>")
|
||||
result.append("\ttemplate<typename... Args>")
|
||||
|
||||
method_signature = "\t"
|
||||
if "is_static" in method and method["is_static"]:
|
||||
@@ -542,10 +550,10 @@ def generate_builtin_class_header(builtin_api, size, used_classes, fully_used_cl
|
||||
|
||||
# Special cases.
|
||||
if class_name == "String":
|
||||
result.append("\tstatic String utf8(const char *from, int len = -1);")
|
||||
result.append("\tvoid parse_utf8(const char *from, int len = -1);")
|
||||
result.append("\tstatic String utf16(const char16_t *from, int len = -1);")
|
||||
result.append("\tvoid parse_utf16(const char16_t *from, int len = -1);")
|
||||
result.append("\tstatic String utf8(const char *from, int64_t len = -1);")
|
||||
result.append("\tvoid parse_utf8(const char *from, int64_t len = -1);")
|
||||
result.append("\tstatic String utf16(const char16_t *from, int64_t len = -1);")
|
||||
result.append("\tvoid parse_utf16(const char16_t *from, int64_t len = -1);")
|
||||
result.append("\tCharString utf8() const;")
|
||||
result.append("\tCharString ascii() const;")
|
||||
result.append("\tChar16String utf16() const;")
|
||||
@@ -604,13 +612,13 @@ def generate_builtin_class_header(builtin_api, size, used_classes, fully_used_cl
|
||||
result.append("\tString &operator+=(const wchar_t *p_str);")
|
||||
result.append("\tString &operator+=(const char32_t *p_str);")
|
||||
|
||||
result.append("\tconst char32_t &operator[](int p_index) const;")
|
||||
result.append("\tchar32_t &operator[](int p_index);")
|
||||
result.append("\tconst char32_t &operator[](int64_t p_index) const;")
|
||||
result.append("\tchar32_t &operator[](int64_t p_index);")
|
||||
result.append("\tconst char32_t *ptr() const;")
|
||||
result.append("\tchar32_t *ptrw();")
|
||||
|
||||
if class_name == "Array":
|
||||
result.append("\ttemplate <class... Args>")
|
||||
result.append("\ttemplate <typename... Args>")
|
||||
result.append("\tstatic Array make(Args... args) {")
|
||||
result.append("\t\treturn helpers::append_all(Array(), args...);")
|
||||
result.append("\t}")
|
||||
@@ -623,8 +631,8 @@ def generate_builtin_class_header(builtin_api, size, used_classes, fully_used_cl
|
||||
return_type = "int32_t"
|
||||
elif class_name == "PackedFloat32Array":
|
||||
return_type = "float"
|
||||
result.append(f"\tconst {return_type} &operator[](int p_index) const;")
|
||||
result.append(f"\t{return_type} &operator[](int p_index);")
|
||||
result.append(f"\tconst {return_type} &operator[](int64_t p_index) const;")
|
||||
result.append(f"\t{return_type} &operator[](int64_t p_index);")
|
||||
result.append(f"\tconst {return_type} *ptr() const;")
|
||||
result.append(f"\t{return_type} *ptrw();")
|
||||
iterators = """
|
||||
@@ -693,10 +701,21 @@ def generate_builtin_class_header(builtin_api, size, used_classes, fully_used_cl
|
||||
}
|
||||
"""
|
||||
result.append(iterators.replace("$TYPE", return_type))
|
||||
init_list = """
|
||||
_FORCE_INLINE_ $CLASS(std::initializer_list<$TYPE> p_init) {
|
||||
ERR_FAIL_COND(resize(p_init.size()) != 0);
|
||||
|
||||
size_t i = 0;
|
||||
for (const $TYPE &element : p_init) {
|
||||
set(i++, element);
|
||||
}
|
||||
}
|
||||
"""
|
||||
result.append(init_list.replace("$TYPE", return_type).replace("$CLASS", class_name))
|
||||
|
||||
if class_name == "Array":
|
||||
result.append("\tconst Variant &operator[](int p_index) const;")
|
||||
result.append("\tVariant &operator[](int p_index);")
|
||||
result.append("\tconst Variant &operator[](int64_t p_index) const;")
|
||||
result.append("\tVariant &operator[](int64_t p_index);")
|
||||
result.append("\tvoid set_typed(uint32_t p_type, const StringName &p_class_name, const Variant &p_script);")
|
||||
result.append("\tvoid _ref(const Array &p_from) const;")
|
||||
|
||||
@@ -771,6 +790,10 @@ def generate_builtin_class_source(builtin_api, size, used_classes, fully_used_cl
|
||||
|
||||
result.append(f"void {class_name}::_init_bindings_constructors_destructor() {{")
|
||||
|
||||
result.append(
|
||||
f"\t_method_bindings.from_variant_constructor = internal::gdextension_interface_get_variant_to_type_constructor({enum_type_name});"
|
||||
)
|
||||
|
||||
if "constructors" in builtin_api:
|
||||
for constructor in builtin_api["constructors"]:
|
||||
result.append(
|
||||
@@ -852,6 +875,11 @@ def generate_builtin_class_source(builtin_api, size, used_classes, fully_used_cl
|
||||
|
||||
copy_constructor_index = -1
|
||||
|
||||
result.append(f"{class_name}::{class_name}(const Variant *p_variant) {{")
|
||||
result.append("\t_method_bindings.from_variant_constructor(&opaque, p_variant->_native_ptr());")
|
||||
result.append("}")
|
||||
result.append("")
|
||||
|
||||
if "constructors" in builtin_api:
|
||||
for constructor in builtin_api["constructors"]:
|
||||
method_signature = f"{class_name}::{class_name}("
|
||||
@@ -917,8 +945,19 @@ def generate_builtin_class_source(builtin_api, size, used_classes, fully_used_cl
|
||||
result.append(method_signature + "{")
|
||||
|
||||
method_call = "\t"
|
||||
is_ref = False
|
||||
|
||||
if "return_type" in method:
|
||||
method_call += f'return internal::_call_builtin_method_ptr_ret<{correct_type(method["return_type"])}>('
|
||||
return_type = method["return_type"]
|
||||
if is_enum(return_type):
|
||||
method_call += f"return ({get_gdextension_type(correct_type(return_type))})internal::_call_builtin_method_ptr_ret<int64_t>("
|
||||
elif is_pod_type(return_type) or is_variant(return_type):
|
||||
method_call += f"return internal::_call_builtin_method_ptr_ret<{get_gdextension_type(correct_type(return_type))}>("
|
||||
elif is_refcounted(return_type):
|
||||
method_call += f"return Ref<{return_type}>::_gde_internal_constructor(internal::_call_builtin_method_ptr_ret_obj<{return_type}>("
|
||||
is_ref = True
|
||||
else:
|
||||
method_call += f"return internal::_call_builtin_method_ptr_ret_obj<{return_type}>("
|
||||
else:
|
||||
method_call += "internal::_call_builtin_method_ptr_no_ret("
|
||||
method_call += f'_method_bindings.method_{method["name"]}, '
|
||||
@@ -939,6 +978,9 @@ def generate_builtin_class_source(builtin_api, size, used_classes, fully_used_cl
|
||||
result += encode
|
||||
arguments.append(arg_name)
|
||||
method_call += ", ".join(arguments)
|
||||
|
||||
if is_ref:
|
||||
method_call += ")" # Close Ref<> constructor.
|
||||
method_call += ");"
|
||||
|
||||
result.append(method_call)
|
||||
@@ -1036,21 +1078,23 @@ def generate_engine_classes_bindings(api, output_dir, use_template_get_node):
|
||||
|
||||
# First create map of classes and singletons.
|
||||
for class_api in api["classes"]:
|
||||
# TODO: Properly setup this singleton since it conflicts with ClassDB in the bindings.
|
||||
# Generate code for the ClassDB singleton under a different name.
|
||||
if class_api["name"] == "ClassDB":
|
||||
continue
|
||||
class_api["name"] = "ClassDBSingleton"
|
||||
class_api["alias_for"] = "ClassDB"
|
||||
engine_classes[class_api["name"]] = class_api["is_refcounted"]
|
||||
for native_struct in api["native_structures"]:
|
||||
engine_classes[native_struct["name"]] = False
|
||||
native_structures.append(native_struct["name"])
|
||||
|
||||
for singleton in api["singletons"]:
|
||||
# Generate code for the ClassDB singleton under a different name.
|
||||
if singleton["name"] == "ClassDB":
|
||||
singleton["name"] = "ClassDBSingleton"
|
||||
singleton["alias_for"] = "ClassDB"
|
||||
singletons.append(singleton["name"])
|
||||
|
||||
for class_api in api["classes"]:
|
||||
# TODO: Properly setup this singleton since it conflicts with ClassDB in the bindings.
|
||||
if class_api["name"] == "ClassDB":
|
||||
continue
|
||||
# Check used classes for header include.
|
||||
used_classes = set()
|
||||
fully_used_classes = set()
|
||||
@@ -1140,6 +1184,12 @@ def generate_engine_classes_bindings(api, output_dir, use_template_get_node):
|
||||
else:
|
||||
fully_used_classes.add("Wrapped")
|
||||
|
||||
# In order to ensure that PtrToArg specializations for native structs are
|
||||
# always used, let's move any of them into 'fully_used_classes'.
|
||||
for type_name in used_classes:
|
||||
if is_struct_type(type_name) and not is_included_struct_type(type_name):
|
||||
fully_used_classes.add(type_name)
|
||||
|
||||
for type_name in fully_used_classes:
|
||||
if type_name in used_classes:
|
||||
used_classes.remove(type_name)
|
||||
@@ -1159,10 +1209,6 @@ def generate_engine_classes_bindings(api, output_dir, use_template_get_node):
|
||||
generate_engine_class_source(class_api, used_classes, fully_used_classes, use_template_get_node)
|
||||
)
|
||||
|
||||
register_engine_classes_filename = Path(output_dir) / "src" / "register_engine_classes.cpp"
|
||||
with register_engine_classes_filename.open("w+", encoding="utf-8") as source_file:
|
||||
source_file.write(generate_register_engine_classes_source(api))
|
||||
|
||||
for native_struct in api["native_structures"]:
|
||||
struct_name = native_struct["name"]
|
||||
snake_struct_name = camel_to_snake(struct_name)
|
||||
@@ -1237,12 +1283,12 @@ def generate_engine_class_header(class_api, used_classes, fully_used_classes, us
|
||||
result.append(f"#include <godot_cpp/{get_include_path(included)}>")
|
||||
|
||||
if class_name == "EditorPlugin":
|
||||
result.append("#include <godot_cpp/templates/vector.hpp>")
|
||||
result.append("#include <godot_cpp/classes/editor_plugin_registration.hpp>")
|
||||
|
||||
if len(fully_used_classes) > 0:
|
||||
result.append("")
|
||||
|
||||
if class_name != "Object":
|
||||
if class_name != "Object" and class_name != "ClassDBSingleton":
|
||||
result.append("#include <godot_cpp/core/class_db.hpp>")
|
||||
result.append("")
|
||||
result.append("#include <type_traits>")
|
||||
@@ -1263,7 +1309,10 @@ def generate_engine_class_header(class_api, used_classes, fully_used_classes, us
|
||||
inherits = class_api["inherits"] if "inherits" in class_api else "Wrapped"
|
||||
result.append(f"class {class_name} : public {inherits} {{")
|
||||
|
||||
result.append(f"\tGDEXTENSION_CLASS({class_name}, {inherits})")
|
||||
if "alias_for" in class_api:
|
||||
result.append(f"\tGDEXTENSION_CLASS_ALIAS({class_name}, {class_api['alias_for']}, {inherits})")
|
||||
else:
|
||||
result.append(f"\tGDEXTENSION_CLASS({class_name}, {inherits})")
|
||||
result.append("")
|
||||
|
||||
result.append("public:")
|
||||
@@ -1322,7 +1371,7 @@ def generate_engine_class_header(class_api, used_classes, fully_used_classes, us
|
||||
result.append("protected:")
|
||||
# T is the custom class we want to register (from which the call initiates, going up the inheritance chain),
|
||||
# B is its base class (can be a custom class too, that's why we pass it).
|
||||
result.append("\ttemplate <class T, class B>")
|
||||
result.append("\ttemplate <typename T, typename B>")
|
||||
result.append("\tstatic void register_virtuals() {")
|
||||
if class_name != "Object":
|
||||
result.append(f"\t\t{inherits}::register_virtuals<T, B>();")
|
||||
@@ -1368,16 +1417,16 @@ def generate_engine_class_header(class_api, used_classes, fully_used_classes, us
|
||||
if class_name == "Object":
|
||||
result.append("")
|
||||
|
||||
result.append("\ttemplate<class T>")
|
||||
result.append("\ttemplate<typename T>")
|
||||
result.append("\tstatic T *cast_to(Object *p_object);")
|
||||
|
||||
result.append("\ttemplate<class T>")
|
||||
result.append("\ttemplate<typename T>")
|
||||
result.append("\tstatic const T *cast_to(const Object *p_object);")
|
||||
|
||||
result.append("\tvirtual ~Object() = default;")
|
||||
|
||||
elif use_template_get_node and class_name == "Node":
|
||||
result.append("\ttemplate<class T>")
|
||||
result.append("\ttemplate<typename T>")
|
||||
result.append(
|
||||
"\tT *get_node(const NodePath &p_path) const { return Object::cast_to<T>(get_node_internal(p_path)); }"
|
||||
)
|
||||
@@ -1386,30 +1435,6 @@ def generate_engine_class_header(class_api, used_classes, fully_used_classes, us
|
||||
result.append("};")
|
||||
result.append("")
|
||||
|
||||
if class_name == "EditorPlugin":
|
||||
result.append("class EditorPlugins {")
|
||||
result.append("private:")
|
||||
result.append("\tstatic Vector<StringName> plugin_classes;")
|
||||
result.append("")
|
||||
result.append("public:")
|
||||
result.append("\tstatic void add_plugin_class(const StringName &p_class_name);")
|
||||
result.append("\tstatic void remove_plugin_class(const StringName &p_class_name);")
|
||||
result.append("\tstatic void deinitialize(GDExtensionInitializationLevel p_level);")
|
||||
result.append("")
|
||||
|
||||
result.append("\ttemplate <class T>")
|
||||
result.append("\tstatic void add_by_type() {")
|
||||
result.append("\t\tadd_plugin_class(T::get_class_static());")
|
||||
result.append("\t}")
|
||||
|
||||
result.append("\ttemplate <class T>")
|
||||
result.append("\tstatic void remove_by_type() {")
|
||||
result.append("\t\tremove_plugin_class(T::get_class_static());")
|
||||
result.append("\t}")
|
||||
|
||||
result.append("};")
|
||||
result.append("")
|
||||
|
||||
result.append("} // namespace godot")
|
||||
result.append("")
|
||||
|
||||
@@ -1421,6 +1446,51 @@ def generate_engine_class_header(class_api, used_classes, fully_used_classes, us
|
||||
result.append(f'VARIANT_ENUM_CAST({class_name}::{enum_api["name"]});')
|
||||
result.append("")
|
||||
|
||||
if class_name == "ClassDBSingleton":
|
||||
result.append("#define CLASSDB_SINGLETON_FORWARD_METHODS \\")
|
||||
for method in class_api["methods"]:
|
||||
# ClassDBSingleton shouldn't have any static or vararg methods, but if some appear later, lets skip them.
|
||||
if vararg:
|
||||
continue
|
||||
if "is_static" in method and method["is_static"]:
|
||||
continue
|
||||
|
||||
method_signature = "\tstatic "
|
||||
if "return_type" in method:
|
||||
method_signature += f'{correct_type(method["return_type"])} '
|
||||
elif "return_value" in method:
|
||||
method_signature += (
|
||||
correct_type(method["return_value"]["type"], method["return_value"].get("meta", None)) + " "
|
||||
)
|
||||
else:
|
||||
method_signature += "void "
|
||||
|
||||
method_signature += f'{method["name"]}('
|
||||
|
||||
method_arguments = []
|
||||
if "arguments" in method:
|
||||
method_arguments = method["arguments"]
|
||||
|
||||
method_signature += make_function_parameters(
|
||||
method_arguments, include_default=True, for_builtin=True, is_vararg=False
|
||||
)
|
||||
|
||||
method_signature += ") { \\"
|
||||
|
||||
result.append(method_signature)
|
||||
|
||||
method_body = "\t\t"
|
||||
if "return_type" in method or "return_value" in method:
|
||||
method_body += "return "
|
||||
method_body += f'ClassDBSingleton::get_singleton()->{method["name"]}('
|
||||
method_body += ", ".join(map(lambda x: escape_identifier(x["name"]), method_arguments))
|
||||
method_body += "); \\"
|
||||
|
||||
result.append(method_body)
|
||||
result.append("\t} \\")
|
||||
result.append("\t;")
|
||||
result.append("")
|
||||
|
||||
result.append(f"#endif // ! {header_guard}")
|
||||
|
||||
return "\n".join(result)
|
||||
@@ -1453,16 +1523,22 @@ def generate_engine_class_source(class_api, used_classes, fully_used_classes, us
|
||||
|
||||
if is_singleton:
|
||||
result.append(f"{class_name} *{class_name}::get_singleton() {{")
|
||||
result.append(f"\tconst StringName _gde_class_name = {class_name}::get_class_static();")
|
||||
# We assume multi-threaded access is OK because each assignment will assign the same value every time
|
||||
result.append(f"\tstatic {class_name} *singleton = nullptr;")
|
||||
result.append("\tif (unlikely(singleton == nullptr)) {")
|
||||
result.append(
|
||||
"\tstatic GDExtensionObjectPtr singleton_obj = internal::gdextension_interface_global_get_singleton(_gde_class_name._native_ptr());"
|
||||
f"\t\tGDExtensionObjectPtr singleton_obj = internal::gdextension_interface_global_get_singleton({class_name}::get_class_static()._native_ptr());"
|
||||
)
|
||||
result.append("#ifdef DEBUG_ENABLED")
|
||||
result.append("\tERR_FAIL_COND_V(singleton_obj == nullptr, nullptr);")
|
||||
result.append("\t\tERR_FAIL_NULL_V(singleton_obj, nullptr);")
|
||||
result.append("#endif // DEBUG_ENABLED")
|
||||
result.append(
|
||||
f"\tstatic {class_name} *singleton = reinterpret_cast<{class_name} *>(internal::gdextension_interface_object_get_instance_binding(singleton_obj, internal::token, &{class_name}::_gde_binding_callbacks));"
|
||||
f"\t\tsingleton = reinterpret_cast<{class_name} *>(internal::gdextension_interface_object_get_instance_binding(singleton_obj, internal::token, &{class_name}::_gde_binding_callbacks));"
|
||||
)
|
||||
result.append("#ifdef DEBUG_ENABLED")
|
||||
result.append("\t\tERR_FAIL_NULL_V(singleton, nullptr);")
|
||||
result.append("#endif // DEBUG_ENABLED")
|
||||
result.append("\t}")
|
||||
result.append("\treturn singleton;")
|
||||
result.append("}")
|
||||
result.append("")
|
||||
@@ -1480,10 +1556,8 @@ def generate_engine_class_source(class_api, used_classes, fully_used_classes, us
|
||||
result.append(method_signature + " {")
|
||||
|
||||
# Method body.
|
||||
result.append(f"\tconst StringName _gde_class_name = {class_name}::get_class_static();")
|
||||
result.append(f'\tconst StringName _gde_method_name = "{method["name"]}";')
|
||||
result.append(
|
||||
f'\tstatic GDExtensionMethodBindPtr _gde_method_bind = internal::gdextension_interface_classdb_get_method_bind(_gde_class_name._native_ptr(), _gde_method_name._native_ptr(), {method["hash"]});'
|
||||
f'\tstatic GDExtensionMethodBindPtr _gde_method_bind = internal::gdextension_interface_classdb_get_method_bind({class_name}::get_class_static()._native_ptr(), StringName("{method["name"]}")._native_ptr(), {method["hash"]});'
|
||||
)
|
||||
method_call = "\t"
|
||||
has_return = "return_value" in method and method["return_value"]["type"] != "void"
|
||||
@@ -1585,38 +1659,6 @@ def generate_engine_class_source(class_api, used_classes, fully_used_classes, us
|
||||
return "\n".join(result)
|
||||
|
||||
|
||||
def generate_register_engine_classes_source(api):
|
||||
includes = []
|
||||
registrations = []
|
||||
|
||||
for class_api in api["classes"]:
|
||||
if class_api["name"] == "ClassDB":
|
||||
continue
|
||||
|
||||
class_name = class_api["name"]
|
||||
snake_class_name = camel_to_snake(class_name)
|
||||
|
||||
includes.append(f"#include <godot_cpp/classes/{snake_class_name}.hpp>")
|
||||
registrations.append(f"\tClassDB::register_engine_class<{class_name}>();")
|
||||
|
||||
result = []
|
||||
add_header(f"register_engine_classes.cpp", result)
|
||||
|
||||
result.append("#include <godot_cpp/godot.hpp>")
|
||||
result.append("")
|
||||
result = result + includes
|
||||
result.append("")
|
||||
result.append("namespace godot {")
|
||||
result.append("")
|
||||
result.append("void GDExtensionBinding::register_engine_classes() {")
|
||||
result = result + registrations
|
||||
result.append("}")
|
||||
result.append("")
|
||||
result.append("} // namespace godot ")
|
||||
|
||||
return "\n".join(result)
|
||||
|
||||
|
||||
def generate_global_constants(api, output_dir):
|
||||
include_gen_folder = Path(output_dir) / "include" / "godot_cpp" / "classes"
|
||||
source_gen_folder = Path(output_dir) / "src" / "classes"
|
||||
@@ -1639,7 +1681,7 @@ def generate_global_constants(api, output_dir):
|
||||
header.append("")
|
||||
|
||||
for constant in api["global_constants"]:
|
||||
header.append(f'\tconst int {escape_identifier(constant["name"])} = {constant["value"]};')
|
||||
header.append(f'\tconst int64_t {escape_identifier(constant["name"])} = {constant["value"]};')
|
||||
|
||||
header.append("")
|
||||
|
||||
@@ -1662,6 +1704,35 @@ def generate_global_constants(api, output_dir):
|
||||
header_file.write("\n".join(header))
|
||||
|
||||
|
||||
def generate_version_header(api, output_dir):
|
||||
header = []
|
||||
header_filename = "version.hpp"
|
||||
add_header(header_filename, header)
|
||||
|
||||
include_gen_folder = Path(output_dir) / "include" / "godot_cpp" / "core"
|
||||
include_gen_folder.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
header_file_path = include_gen_folder / header_filename
|
||||
|
||||
header_guard = "GODOT_CPP_VERSION_HPP"
|
||||
header.append(f"#ifndef {header_guard}")
|
||||
header.append(f"#define {header_guard}")
|
||||
header.append("")
|
||||
|
||||
header.append(f"#define GODOT_VERSION_MAJOR {api['header']['version_major']}")
|
||||
header.append(f"#define GODOT_VERSION_MINOR {api['header']['version_minor']}")
|
||||
header.append(f"#define GODOT_VERSION_PATCH {api['header']['version_patch']}")
|
||||
header.append(f"#define GODOT_VERSION_STATUS \"{api['header']['version_status']}\"")
|
||||
header.append(f"#define GODOT_VERSION_BUILD \"{api['header']['version_build']}\"")
|
||||
|
||||
header.append("")
|
||||
header.append(f"#endif // {header_guard}")
|
||||
header.append("")
|
||||
|
||||
with header_file_path.open("w+", encoding="utf-8") as header_file:
|
||||
header_file.write("\n".join(header))
|
||||
|
||||
|
||||
def generate_global_constant_binds(api, output_dir):
|
||||
include_gen_folder = Path(output_dir) / "include" / "godot_cpp" / "classes"
|
||||
source_gen_folder = Path(output_dir) / "src" / "classes"
|
||||
@@ -1688,9 +1759,9 @@ def generate_global_constant_binds(api, output_dir):
|
||||
continue
|
||||
|
||||
if enum_def["is_bitfield"]:
|
||||
header.append(f'VARIANT_BITFIELD_CAST(godot::{enum_def["name"]});')
|
||||
header.append(f'VARIANT_BITFIELD_CAST({enum_def["name"]});')
|
||||
else:
|
||||
header.append(f'VARIANT_ENUM_CAST(godot::{enum_def["name"]});')
|
||||
header.append(f'VARIANT_ENUM_CAST({enum_def["name"]});')
|
||||
|
||||
# Variant::Type is not a global enum, but only one line, it is worth to place in this file instead of creating new file.
|
||||
header.append(f"VARIANT_ENUM_CAST(godot::Variant::Type);")
|
||||
@@ -1773,9 +1844,8 @@ def generate_utility_functions(api, output_dir):
|
||||
|
||||
# Function body.
|
||||
|
||||
source.append(f'\tconst StringName _gde_function_name = "{function["name"]}";')
|
||||
source.append(
|
||||
f'\tstatic GDExtensionPtrUtilityFunction _gde_function = internal::gdextension_interface_variant_get_ptr_utility_function(_gde_function_name._native_ptr(), {function["hash"]});'
|
||||
f'\tstatic GDExtensionPtrUtilityFunction _gde_function = internal::gdextension_interface_variant_get_ptr_utility_function(StringName("{function["name"]}")._native_ptr(), {function["hash"]});'
|
||||
)
|
||||
has_return = "return_type" in function and function["return_type"] != "void"
|
||||
if has_return:
|
||||
@@ -1972,7 +2042,7 @@ def make_signature(
|
||||
def make_varargs_template(function_data, static=False):
|
||||
result = []
|
||||
|
||||
function_signature = "\tpublic: template<class... Args> "
|
||||
function_signature = "\tpublic: template<typename... Args> "
|
||||
|
||||
if static:
|
||||
function_signature += "static "
|
||||
@@ -2285,6 +2355,7 @@ def escape_identifier(id):
|
||||
"operator": "_operator",
|
||||
"typeof": "type_of",
|
||||
"typename": "type_name",
|
||||
"enum": "_enum",
|
||||
}
|
||||
if id in cpp_keywords_map:
|
||||
return cpp_keywords_map[id]
|
||||
@@ -2306,6 +2377,7 @@ def get_operator_id_name(op):
|
||||
"unary-": "negate",
|
||||
"unary+": "positive",
|
||||
"%": "module",
|
||||
"**": "power",
|
||||
"<<": "shift_left",
|
||||
">>": "shift_right",
|
||||
"&": "bit_and",
|
||||
|
||||
@@ -2,10 +2,10 @@
|
||||
"header": {
|
||||
"version_major": 4,
|
||||
"version_minor": 1,
|
||||
"version_patch": 1,
|
||||
"version_patch": 4,
|
||||
"version_status": "stable",
|
||||
"version_build": "official",
|
||||
"version_full_name": "Godot Engine v4.1.1.stable.official"
|
||||
"version_full_name": "Godot Engine v4.1.4.stable.official"
|
||||
},
|
||||
"builtin_class_sizes": [
|
||||
{
|
||||
@@ -2593,6 +2593,22 @@
|
||||
"name": "KEY_LAUNCHF",
|
||||
"value": 4194415
|
||||
},
|
||||
{
|
||||
"name": "KEY_GLOBE",
|
||||
"value": 4194416
|
||||
},
|
||||
{
|
||||
"name": "KEY_KEYBOARD",
|
||||
"value": 4194417
|
||||
},
|
||||
{
|
||||
"name": "KEY_JIS_EISU",
|
||||
"value": 4194418
|
||||
},
|
||||
{
|
||||
"name": "KEY_JIS_KANA",
|
||||
"value": 4194419
|
||||
},
|
||||
{
|
||||
"name": "KEY_UNKNOWN",
|
||||
"value": 8388607
|
||||
@@ -2880,22 +2896,6 @@
|
||||
{
|
||||
"name": "KEY_SECTION",
|
||||
"value": 167
|
||||
},
|
||||
{
|
||||
"name": "KEY_GLOBE",
|
||||
"value": 4194416
|
||||
},
|
||||
{
|
||||
"name": "KEY_KEYBOARD",
|
||||
"value": 4194417
|
||||
},
|
||||
{
|
||||
"name": "KEY_JIS_EISU",
|
||||
"value": 4194418
|
||||
},
|
||||
{
|
||||
"name": "KEY_JIS_KANA",
|
||||
"value": 4194419
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -95246,13 +95246,6 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "FramebufferCacheRD",
|
||||
"is_refcounted": false,
|
||||
"is_instantiable": false,
|
||||
"inherits": "Object",
|
||||
"api_type": "core"
|
||||
},
|
||||
{
|
||||
"name": "GDExtension",
|
||||
"is_refcounted": true,
|
||||
@@ -113089,6 +113082,29 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "should_ignore_device",
|
||||
"is_const": true,
|
||||
"is_vararg": false,
|
||||
"is_static": false,
|
||||
"is_virtual": false,
|
||||
"hash": 2522259332,
|
||||
"return_value": {
|
||||
"type": "bool"
|
||||
},
|
||||
"arguments": [
|
||||
{
|
||||
"name": "vendor_id",
|
||||
"type": "int",
|
||||
"meta": "int32"
|
||||
},
|
||||
{
|
||||
"name": "product_id",
|
||||
"type": "int",
|
||||
"meta": "int32"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "get_connected_joypads",
|
||||
"is_const": false,
|
||||
@@ -122009,6 +122025,10 @@
|
||||
{
|
||||
"name": "BAKE_ERROR_USER_ABORTED",
|
||||
"value": 8
|
||||
},
|
||||
{
|
||||
"name": "BAKE_ERROR_TEXTURE_SIZE_TOO_SMALL",
|
||||
"value": 9
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -149258,6 +149278,93 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "OpenXRInteractionProfileMetadata",
|
||||
"is_refcounted": false,
|
||||
"is_instantiable": true,
|
||||
"inherits": "Object",
|
||||
"api_type": "core",
|
||||
"methods": [
|
||||
{
|
||||
"name": "register_top_level_path",
|
||||
"is_const": false,
|
||||
"is_vararg": false,
|
||||
"is_static": false,
|
||||
"is_virtual": false,
|
||||
"hash": 254767734,
|
||||
"arguments": [
|
||||
{
|
||||
"name": "display_name",
|
||||
"type": "String"
|
||||
},
|
||||
{
|
||||
"name": "openxr_path",
|
||||
"type": "String"
|
||||
},
|
||||
{
|
||||
"name": "openxr_extension_name",
|
||||
"type": "String"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "register_interaction_profile",
|
||||
"is_const": false,
|
||||
"is_vararg": false,
|
||||
"is_static": false,
|
||||
"is_virtual": false,
|
||||
"hash": 254767734,
|
||||
"arguments": [
|
||||
{
|
||||
"name": "display_name",
|
||||
"type": "String"
|
||||
},
|
||||
{
|
||||
"name": "openxr_path",
|
||||
"type": "String"
|
||||
},
|
||||
{
|
||||
"name": "openxr_extension_name",
|
||||
"type": "String"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "register_io_path",
|
||||
"is_const": false,
|
||||
"is_vararg": false,
|
||||
"is_static": false,
|
||||
"is_virtual": false,
|
||||
"hash": 3443511926,
|
||||
"arguments": [
|
||||
{
|
||||
"name": "interaction_profile",
|
||||
"type": "String"
|
||||
},
|
||||
{
|
||||
"name": "display_name",
|
||||
"type": "String"
|
||||
},
|
||||
{
|
||||
"name": "toplevel_path",
|
||||
"type": "String"
|
||||
},
|
||||
{
|
||||
"name": "openxr_path",
|
||||
"type": "String"
|
||||
},
|
||||
{
|
||||
"name": "openxr_extension_name",
|
||||
"type": "String"
|
||||
},
|
||||
{
|
||||
"name": "action_type",
|
||||
"type": "enum::OpenXRAction.ActionType"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "OpenXRInterface",
|
||||
"is_refcounted": true,
|
||||
@@ -198879,6 +198986,23 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "debug_canvas_item_get_rect",
|
||||
"is_const": false,
|
||||
"is_vararg": false,
|
||||
"is_static": false,
|
||||
"is_virtual": false,
|
||||
"hash": 624227424,
|
||||
"return_value": {
|
||||
"type": "Rect2"
|
||||
},
|
||||
"arguments": [
|
||||
{
|
||||
"name": "item",
|
||||
"type": "RID"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "canvas_light_create",
|
||||
"is_const": false,
|
||||
@@ -251426,6 +251550,43 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "set_text_overrun_behavior",
|
||||
"is_const": false,
|
||||
"is_vararg": false,
|
||||
"is_static": false,
|
||||
"is_virtual": false,
|
||||
"hash": 1940772195,
|
||||
"arguments": [
|
||||
{
|
||||
"name": "column",
|
||||
"type": "int",
|
||||
"meta": "int32"
|
||||
},
|
||||
{
|
||||
"name": "overrun_behavior",
|
||||
"type": "enum::TextServer.OverrunBehavior"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "get_text_overrun_behavior",
|
||||
"is_const": true,
|
||||
"is_vararg": false,
|
||||
"is_static": false,
|
||||
"is_virtual": false,
|
||||
"hash": 3782727860,
|
||||
"return_value": {
|
||||
"type": "enum::TextServer.OverrunBehavior"
|
||||
},
|
||||
"arguments": [
|
||||
{
|
||||
"name": "column",
|
||||
"type": "int",
|
||||
"meta": "int32"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "set_structured_text_bidi_override",
|
||||
"is_const": false,
|
||||
@@ -255076,13 +255237,6 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "UniformSetCacheRD",
|
||||
"is_refcounted": false,
|
||||
"is_instantiable": false,
|
||||
"inherits": "Object",
|
||||
"api_type": "core"
|
||||
},
|
||||
{
|
||||
"name": "VBoxContainer",
|
||||
"is_refcounted": false,
|
||||
|
||||
62
include/godot_cpp/classes/editor_plugin_registration.hpp
Normal file
62
include/godot_cpp/classes/editor_plugin_registration.hpp
Normal file
@@ -0,0 +1,62 @@
|
||||
/**************************************************************************/
|
||||
/* 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
|
||||
@@ -45,7 +45,7 @@ namespace godot {
|
||||
|
||||
class RefCounted;
|
||||
|
||||
template <class T>
|
||||
template <typename T>
|
||||
class Ref {
|
||||
T *reference = nullptr;
|
||||
|
||||
@@ -63,7 +63,7 @@ class Ref {
|
||||
}
|
||||
|
||||
void ref_pointer(T *p_ref) {
|
||||
ERR_FAIL_COND(!p_ref);
|
||||
ERR_FAIL_NULL(p_ref);
|
||||
|
||||
if (p_ref->init_ref()) {
|
||||
reference = p_ref;
|
||||
@@ -108,7 +108,7 @@ public:
|
||||
ref(p_from);
|
||||
}
|
||||
|
||||
template <class T_Other>
|
||||
template <typename 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 +144,7 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
template <class T_Other>
|
||||
template <typename T_Other>
|
||||
void reference_ptr(T_Other *p_ptr) {
|
||||
if (reference == p_ptr) {
|
||||
return;
|
||||
@@ -161,7 +161,7 @@ public:
|
||||
ref(p_from);
|
||||
}
|
||||
|
||||
template <class T_Other>
|
||||
template <typename T_Other>
|
||||
Ref(const Ref<T_Other> &p_from) {
|
||||
RefCounted *refb = const_cast<RefCounted *>(static_cast<const RefCounted *>(p_from.ptr()));
|
||||
if (!refb) {
|
||||
@@ -226,7 +226,7 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
template <typename T>
|
||||
struct PtrToArg<Ref<T>> {
|
||||
_FORCE_INLINE_ static Ref<T> convert(const void *p_ptr) {
|
||||
GDExtensionRefPtr ref = (GDExtensionRefPtr)p_ptr;
|
||||
@@ -248,7 +248,7 @@ struct PtrToArg<Ref<T>> {
|
||||
}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
template <typename T>
|
||||
struct PtrToArg<const Ref<T> &> {
|
||||
typedef Ref<T> EncodeT;
|
||||
|
||||
@@ -259,7 +259,7 @@ struct PtrToArg<const Ref<T> &> {
|
||||
}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
template <typename T>
|
||||
struct GetTypeInfo<Ref<T>, typename EnableIf<TypeInherits<RefCounted, T>::value>::type> {
|
||||
static const GDExtensionVariantType VARIANT_TYPE = GDEXTENSION_VARIANT_TYPE_OBJECT;
|
||||
static const GDExtensionClassMethodArgumentMetadata METADATA = GDEXTENSION_METHOD_ARGUMENT_METADATA_NONE;
|
||||
@@ -269,7 +269,7 @@ struct GetTypeInfo<Ref<T>, typename EnableIf<TypeInherits<RefCounted, T>::value>
|
||||
}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
template <typename T>
|
||||
struct GetTypeInfo<const Ref<T> &, typename EnableIf<TypeInherits<RefCounted, T>::value>::type> {
|
||||
static const GDExtensionVariantType VARIANT_TYPE = GDEXTENSION_VARIANT_TYPE_OBJECT;
|
||||
static const GDExtensionClassMethodArgumentMetadata METADATA = GDEXTENSION_METHOD_ARGUMENT_METADATA_NONE;
|
||||
|
||||
@@ -95,6 +95,26 @@ public:
|
||||
GodotObject *_owner = nullptr;
|
||||
};
|
||||
|
||||
namespace internal {
|
||||
|
||||
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
|
||||
|
||||
#define GDCLASS(m_class, m_inherits) \
|
||||
@@ -132,24 +152,26 @@ 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) { \
|
||||
return (bool(::godot::Wrapped::*)(const ::godot::StringName &p_name)) & m_class::_property_can_revert; \
|
||||
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_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 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 ::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 <class T, class B> \
|
||||
template <typename T, typename B> \
|
||||
static void register_virtuals() { \
|
||||
m_inherits::register_virtuals<T, B>(); \
|
||||
} \
|
||||
\
|
||||
public: \
|
||||
typedef m_class self_type; \
|
||||
\
|
||||
static void initialize_class() { \
|
||||
static bool initialized = false; \
|
||||
if (initialized) { \
|
||||
@@ -179,11 +201,11 @@ public:
|
||||
\
|
||||
static void notification_bind(GDExtensionClassInstancePtr p_instance, int32_t p_what) { \
|
||||
if (p_instance && m_class::_get_notification()) { \
|
||||
m_inherits::notification_bind(p_instance, p_what); \
|
||||
if (m_class::_get_notification() != m_inherits::_get_notification()) { \
|
||||
m_class *cls = reinterpret_cast<m_class *>(p_instance); \
|
||||
return cls->_notification(p_what); \
|
||||
cls->_notification(p_what); \
|
||||
} \
|
||||
m_inherits::notification_bind(p_instance, p_what); \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
@@ -303,82 +325,107 @@ public:
|
||||
_gde_binding_create_callback, \
|
||||
_gde_binding_free_callback, \
|
||||
_gde_binding_reference_callback, \
|
||||
};
|
||||
}; \
|
||||
\
|
||||
private:
|
||||
|
||||
// Don't use this for your classes, use GDCLASS() instead.
|
||||
#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 &_gde_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 *_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_class) {}
|
||||
#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) {} \
|
||||
\
|
||||
protected: \
|
||||
virtual const GDExtensionInstanceBindingCallbacks *_get_bindings_callbacks() const override { \
|
||||
return &_gde_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 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; \
|
||||
\
|
||||
static void initialize_class() {} \
|
||||
\
|
||||
static ::godot::StringName &get_class_static() { \
|
||||
static ::godot::StringName string_name = ::godot::StringName(#m_alias_for); \
|
||||
return string_name; \
|
||||
} \
|
||||
\
|
||||
static ::godot::StringName &get_parent_class_static() { \
|
||||
return m_inherits::get_class_static(); \
|
||||
} \
|
||||
\
|
||||
static GDExtensionObjectPtr create(void *data) { \
|
||||
return nullptr; \
|
||||
} \
|
||||
\
|
||||
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)
|
||||
|
||||
#endif // GODOT_WRAPPED_HPP
|
||||
|
||||
@@ -83,7 +83,7 @@ namespace godot {
|
||||
}; \
|
||||
}
|
||||
|
||||
template <class T>
|
||||
template <typename 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 <class T>
|
||||
template <typename 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 <class T>
|
||||
template <typename T>
|
||||
struct VariantCaster<const T &> {
|
||||
static _FORCE_INLINE_ T cast(const Variant &p_variant) {
|
||||
using TStripped = std::remove_pointer_t<T>;
|
||||
@@ -144,7 +144,7 @@ struct VariantObjectClassChecker<const Ref<T> &> {
|
||||
}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
template <typename 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);
|
||||
@@ -159,7 +159,7 @@ struct VariantCasterAndValidate {
|
||||
}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
template <typename 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);
|
||||
@@ -174,7 +174,7 @@ struct VariantCasterAndValidate<T &> {
|
||||
}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
template <typename 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);
|
||||
@@ -189,47 +189,47 @@ struct VariantCasterAndValidate<const T &> {
|
||||
}
|
||||
};
|
||||
|
||||
template <class T, class... P, size_t... Is>
|
||||
template <typename T, typename... 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 <class T, class... P, size_t... Is>
|
||||
template <typename T, typename... 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 <class T, class R, class... P, size_t... Is>
|
||||
template <typename T, typename R, typename... 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 <class T, class R, class... P, size_t... Is>
|
||||
template <typename T, typename R, typename... 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 <class T, class... P>
|
||||
template <typename T, typename... 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 <class T, class... P>
|
||||
template <typename T, typename... 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 <class T, class R, class... P>
|
||||
template <typename T, typename R, typename... 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 <class T, class R, class... P>
|
||||
template <typename T, typename R, typename... 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 <class T, class... P, size_t... Is>
|
||||
template <typename T, typename... 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 <class T, class... P, size_t... Is>
|
||||
template <typename T, typename... 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 <class T, class R, class... P, size_t... Is>
|
||||
template <typename T, typename R, typename... 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 <class T, class R, class... P, size_t... Is>
|
||||
template <typename T, typename R, typename... 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,7 +276,7 @@ void call_with_variant_args_retc_helper(T *p_instance, R (T::*p_method)(P...) co
|
||||
(void)p_args;
|
||||
}
|
||||
|
||||
template <class T, class... P>
|
||||
template <typename T, typename... 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)) {
|
||||
@@ -311,7 +311,7 @@ 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 <class T, class... P>
|
||||
template <typename T, typename... 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)) {
|
||||
@@ -346,7 +346,7 @@ 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 <class T, class R, class... P>
|
||||
template <typename T, typename R, typename... 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)) {
|
||||
@@ -381,7 +381,7 @@ 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 <class T, class R, class... P>
|
||||
template <typename T, typename R, typename... 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)) {
|
||||
@@ -423,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 <class Q>
|
||||
template <typename Q>
|
||||
void call_get_argument_type_helper(int p_arg, int &index, GDExtensionVariantType &type) {
|
||||
if (p_arg == index) {
|
||||
type = GDExtensionVariantType(GetTypeInfo<Q>::VARIANT_TYPE);
|
||||
@@ -431,7 +431,7 @@ void call_get_argument_type_helper(int p_arg, int &index, GDExtensionVariantType
|
||||
index++;
|
||||
}
|
||||
|
||||
template <class... P>
|
||||
template <typename... P>
|
||||
GDExtensionVariantType call_get_argument_type(int p_arg) {
|
||||
GDExtensionVariantType type = GDEXTENSION_VARIANT_TYPE_NIL;
|
||||
int index = 0;
|
||||
@@ -443,7 +443,7 @@ GDExtensionVariantType call_get_argument_type(int p_arg) {
|
||||
return type;
|
||||
}
|
||||
|
||||
template <class Q>
|
||||
template <typename 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();
|
||||
@@ -451,7 +451,7 @@ void call_get_argument_type_info_helper(int p_arg, int &index, PropertyInfo &inf
|
||||
index++;
|
||||
}
|
||||
|
||||
template <class... P>
|
||||
template <typename... P>
|
||||
void call_get_argument_type_info(int p_arg, PropertyInfo &info) {
|
||||
int index = 0;
|
||||
// I think rocket science is simpler than modern C++.
|
||||
@@ -461,7 +461,7 @@ void call_get_argument_type_info(int p_arg, PropertyInfo &info) {
|
||||
(void)index; // Suppress GCC warning.
|
||||
}
|
||||
|
||||
template <class Q>
|
||||
template <typename Q>
|
||||
void call_get_argument_metadata_helper(int p_arg, int &index, GDExtensionClassMethodArgumentMetadata &md) {
|
||||
if (p_arg == index) {
|
||||
md = GetTypeInfo<Q>::METADATA;
|
||||
@@ -469,7 +469,7 @@ void call_get_argument_metadata_helper(int p_arg, int &index, GDExtensionClassMe
|
||||
index++;
|
||||
}
|
||||
|
||||
template <class... P>
|
||||
template <typename... P>
|
||||
GDExtensionClassMethodArgumentMetadata call_get_argument_metadata(int p_arg) {
|
||||
GDExtensionClassMethodArgumentMetadata md = GDEXTENSION_METHOD_ARGUMENT_METADATA_NONE;
|
||||
|
||||
@@ -482,7 +482,7 @@ GDExtensionClassMethodArgumentMetadata call_get_argument_metadata(int p_arg) {
|
||||
return md;
|
||||
}
|
||||
|
||||
template <class... P, size_t... Is>
|
||||
template <typename... 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;
|
||||
|
||||
@@ -493,7 +493,7 @@ void call_with_variant_args_static(void (*p_method)(P...), const Variant **p_arg
|
||||
#endif
|
||||
}
|
||||
|
||||
template <class... P>
|
||||
template <typename... 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)) {
|
||||
@@ -528,17 +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 <class... P, size_t... Is>
|
||||
template <typename... 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 <class... P>
|
||||
template <typename... 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 <class R, class... P, size_t... Is>
|
||||
template <typename R, typename... 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;
|
||||
|
||||
@@ -549,7 +549,7 @@ void call_with_variant_args_static_ret(R (*p_method)(P...), const Variant **p_ar
|
||||
#endif
|
||||
}
|
||||
|
||||
template <class R, class... P>
|
||||
template <typename R, typename... 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)) {
|
||||
@@ -584,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 <class R, class... P, size_t... Is>
|
||||
template <typename R, typename... 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 <class R, class... P>
|
||||
template <typename R, typename... 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)>{});
|
||||
}
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
#define GODOT_BUILTIN_PTRCALL_HPP
|
||||
|
||||
#include <gdextension_interface.h>
|
||||
#include <godot_cpp/core/object.hpp>
|
||||
|
||||
#include <array>
|
||||
|
||||
@@ -39,13 +40,24 @@ namespace godot {
|
||||
|
||||
namespace internal {
|
||||
|
||||
template <class... Args>
|
||||
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>
|
||||
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 <class T, class... Args>
|
||||
template <typename T, typename... 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... } };
|
||||
@@ -53,20 +65,20 @@ T _call_builtin_method_ptr_ret(const GDExtensionPtrBuiltInMethod method, GDExten
|
||||
return ret;
|
||||
}
|
||||
|
||||
template <class... Args>
|
||||
template <typename... 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 <class T>
|
||||
template <typename T>
|
||||
T _call_builtin_operator_ptr(const GDExtensionPtrOperatorEvaluator op, GDExtensionConstTypePtr left, GDExtensionConstTypePtr right) {
|
||||
T ret;
|
||||
op(left, right, &ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
template <typename T>
|
||||
T _call_builtin_ptr_getter(const GDExtensionPtrGetter getter, GDExtensionConstTypePtr base) {
|
||||
T ret;
|
||||
getter(base, &ret);
|
||||
|
||||
@@ -38,6 +38,8 @@
|
||||
#include <godot_cpp/core/method_bind.hpp>
|
||||
#include <godot_cpp/core/object.hpp>
|
||||
|
||||
#include <godot_cpp/classes/class_db_singleton.hpp>
|
||||
|
||||
#include <list>
|
||||
#include <set>
|
||||
#include <string>
|
||||
@@ -112,24 +114,26 @@ private:
|
||||
static void initialize_class(const ClassInfo &cl);
|
||||
static void bind_method_godot(const StringName &p_class_name, MethodBind *p_method);
|
||||
|
||||
template <class T, bool is_abstract>
|
||||
template <typename T, bool is_abstract>
|
||||
static void _register_class(bool p_virtual = false);
|
||||
|
||||
public:
|
||||
template <class T>
|
||||
template <typename T>
|
||||
static void register_class(bool p_virtual = false);
|
||||
template <class T>
|
||||
template <typename T>
|
||||
static void register_abstract_class();
|
||||
template <class T>
|
||||
static void register_engine_class();
|
||||
|
||||
template <class N, class M, typename... VarArgs>
|
||||
_FORCE_INLINE_ static void _register_engine_class(const StringName &p_name, const GDExtensionInstanceBindingCallbacks *p_callbacks) {
|
||||
instance_binding_callbacks[p_name] = p_callbacks;
|
||||
}
|
||||
|
||||
template <typename N, typename M, typename... VarArgs>
|
||||
static MethodBind *bind_method(N p_method_name, M p_method, VarArgs... p_args);
|
||||
|
||||
template <class N, class M, typename... VarArgs>
|
||||
template <typename N, typename M, typename... VarArgs>
|
||||
static MethodBind *bind_static_method(StringName p_class, N p_method_name, M p_method, VarArgs... p_args);
|
||||
|
||||
template <class M>
|
||||
template <typename 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);
|
||||
@@ -146,27 +150,30 @@ public:
|
||||
|
||||
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::_gde_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::_gde_constant_get_bitfield_name(m_constant, #m_constant), #m_constant, m_constant, true);
|
||||
|
||||
#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); \
|
||||
::godot::ClassDB::bind_virtual_method(m_class::get_class_static(), #m_method, _call##m_method); \
|
||||
}
|
||||
|
||||
template <class T, bool is_abstract>
|
||||
template <typename T, bool is_abstract>
|
||||
void ClassDB::_register_class(bool p_virtual) {
|
||||
static_assert(TypesAreSame<typename T::self_type, T>::value, "Class not declared properly, please use GDCLASS.");
|
||||
instance_binding_callbacks[T::get_class_static()] = &T::_gde_binding_callbacks;
|
||||
|
||||
// Register this class within our plugin
|
||||
@@ -212,22 +219,17 @@ void ClassDB::_register_class(bool p_virtual) {
|
||||
initialize_class(classes[cl.name]);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
template <typename T>
|
||||
void ClassDB::register_class(bool p_virtual) {
|
||||
ClassDB::_register_class<T, false>(p_virtual);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
template <typename T>
|
||||
void ClassDB::register_abstract_class() {
|
||||
ClassDB::_register_class<T, true>();
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void ClassDB::register_engine_class() {
|
||||
instance_binding_callbacks[T::get_class_static()] = &T::_gde_binding_callbacks;
|
||||
}
|
||||
|
||||
template <class N, class M, typename... VarArgs>
|
||||
template <typename N, typename 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];
|
||||
@@ -238,7 +240,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 <class N, class M, typename... VarArgs>
|
||||
template <typename N, typename 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];
|
||||
@@ -250,10 +252,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 <class M>
|
||||
template <typename 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_COND_V(!bind, nullptr);
|
||||
ERR_FAIL_NULL_V(bind, nullptr);
|
||||
|
||||
bind->set_name(p_name);
|
||||
bind->set_default_arguments(p_default_args);
|
||||
|
||||
@@ -108,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 <class T>
|
||||
template <typename T>
|
||||
inline void __swap_tmpl(T &x, T &y) {
|
||||
T aux = x;
|
||||
x = y;
|
||||
|
||||
@@ -43,7 +43,7 @@ namespace godot {
|
||||
|
||||
namespace internal {
|
||||
|
||||
template <class O, class... Args>
|
||||
template <typename O, typename... 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... } };
|
||||
@@ -54,7 +54,7 @@ O *_call_native_mb_ret_obj(const GDExtensionMethodBindPtr mb, void *instance, co
|
||||
return reinterpret_cast<O *>(internal::get_object_instance_binding(ret));
|
||||
}
|
||||
|
||||
template <class R, class... Args>
|
||||
template <typename R, typename... 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... } };
|
||||
@@ -62,13 +62,13 @@ R _call_native_mb_ret(const GDExtensionMethodBindPtr mb, void *instance, const A
|
||||
return ret;
|
||||
}
|
||||
|
||||
template <class... Args>
|
||||
template <typename... 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);
|
||||
}
|
||||
|
||||
template <class R, class... Args>
|
||||
template <typename R, typename... 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 <class... Args>
|
||||
Object *_call_utility_ret_obj(const GDExtensionPtrUtilityFunction func, void *instance, const Args &...args) {
|
||||
template <typename... Args>
|
||||
Object *_call_utility_ret_obj(const GDExtensionPtrUtilityFunction func, 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);
|
||||
}
|
||||
|
||||
template <class... Args>
|
||||
template <typename... 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());
|
||||
|
||||
@@ -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 <class T>
|
||||
template <typename 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 <class T>
|
||||
template <typename T>
|
||||
static _FORCE_INLINE_ T nearest_power_of_2_templated(T x) {
|
||||
--x;
|
||||
|
||||
|
||||
@@ -40,10 +40,6 @@
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
#ifndef PAD_ALIGN
|
||||
#define PAD_ALIGN 16 //must always be greater than this at much
|
||||
#endif
|
||||
|
||||
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
|
||||
@@ -68,6 +64,18 @@ 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);
|
||||
@@ -75,7 +83,7 @@ public:
|
||||
|
||||
_ALWAYS_INLINE_ void postinitialize_handler(void *) {}
|
||||
|
||||
template <class T>
|
||||
template <typename T>
|
||||
_ALWAYS_INLINE_ T *_post_initialize(T *p_obj) {
|
||||
postinitialize_handler(p_obj);
|
||||
return p_obj;
|
||||
@@ -91,28 +99,28 @@ _ALWAYS_INLINE_ T *_post_initialize(T *p_obj) {
|
||||
#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 <class T>
|
||||
template <typename T>
|
||||
struct Comparator {
|
||||
_ALWAYS_INLINE_ bool operator()(const T &p_a, const T &p_b) const { return (p_a < p_b); }
|
||||
};
|
||||
|
||||
template <class T>
|
||||
template <typename T>
|
||||
void memdelete(T *p_class, typename std::enable_if<!std::is_base_of_v<godot::Wrapped, T>>::type * = nullptr) {
|
||||
if (!std::is_trivially_destructible<T>::value) {
|
||||
if constexpr (!std::is_trivially_destructible_v<T>) {
|
||||
p_class->~T();
|
||||
}
|
||||
|
||||
Memory::free_static(p_class);
|
||||
}
|
||||
|
||||
template <class T, std::enable_if_t<std::is_base_of_v<godot::Wrapped, T>, bool> = true>
|
||||
template <typename 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);
|
||||
}
|
||||
|
||||
template <class T, class A>
|
||||
template <typename T, typename A>
|
||||
void memdelete_allocator(T *p_class) {
|
||||
if (!std::is_trivially_destructible<T>::value) {
|
||||
if constexpr (!std::is_trivially_destructible_v<T>) {
|
||||
p_class->~T();
|
||||
}
|
||||
|
||||
@@ -125,16 +133,20 @@ public:
|
||||
_ALWAYS_INLINE_ static void free(void *p_ptr) { Memory::free_static(p_ptr); }
|
||||
};
|
||||
|
||||
template <class T>
|
||||
template <typename T>
|
||||
class DefaultTypedAllocator {
|
||||
public:
|
||||
template <class... Args>
|
||||
template <typename... 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) {
|
||||
@@ -144,12 +156,14 @@ 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;
|
||||
uint64_t *mem = (uint64_t *)Memory::alloc_static(len, true);
|
||||
uint8_t *mem = (uint8_t *)Memory::alloc_static(len, true);
|
||||
T *failptr = nullptr; // Get rid of a warning.
|
||||
ERR_FAIL_COND_V(!mem, failptr);
|
||||
*(mem - 1) = p_elements;
|
||||
ERR_FAIL_NULL_V(mem, failptr);
|
||||
|
||||
if (!std::is_trivially_destructible<T>::value) {
|
||||
uint64_t *_elem_count_ptr = _get_element_count_ptr(mem);
|
||||
*(_elem_count_ptr) = p_elements;
|
||||
|
||||
if constexpr (!std::is_trivially_destructible_v<T>) {
|
||||
T *elems = (T *)mem;
|
||||
|
||||
/* call operator new */
|
||||
@@ -162,11 +176,19 @@ T *memnew_arr_template(size_t p_elements, const char *p_descr = "") {
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void memdelete_arr(T *p_class) {
|
||||
uint64_t *ptr = (uint64_t *)p_class;
|
||||
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);
|
||||
}
|
||||
|
||||
if (!std::is_trivially_destructible<T>::value) {
|
||||
uint64_t elem_count = *(ptr - 1);
|
||||
template <typename T>
|
||||
void memdelete_arr(T *p_class) {
|
||||
uint8_t *ptr = (uint8_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);
|
||||
|
||||
for (uint64_t i = 0; i < elem_count; i++) {
|
||||
p_class[i].~T();
|
||||
|
||||
@@ -147,7 +147,7 @@ public:
|
||||
virtual ~MethodBind();
|
||||
};
|
||||
|
||||
template <class Derived, class T, class R, bool should_returns>
|
||||
template <typename Derived, typename T, typename R, bool should_returns>
|
||||
class MethodBindVarArgBase : public MethodBind {
|
||||
protected:
|
||||
R(T::*method)
|
||||
@@ -208,7 +208,7 @@ private:
|
||||
}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
template <typename T>
|
||||
class MethodBindVarArgT : public MethodBindVarArgBase<MethodBindVarArgT<T>, T, void, false> {
|
||||
friend class MethodBindVarArgBase<MethodBindVarArgT<T>, T, void, false>;
|
||||
|
||||
@@ -231,14 +231,14 @@ private:
|
||||
}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
template <typename 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 <class T, class R>
|
||||
template <typename T, typename 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 <class T, class R>
|
||||
template <typename T, typename 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());
|
||||
@@ -277,9 +277,9 @@ class _gde_UnexistingClass;
|
||||
// No return, not const.
|
||||
|
||||
#ifdef TYPED_METHOD_BIND
|
||||
template <class T, class... P>
|
||||
template <typename T, typename... P>
|
||||
#else
|
||||
template <class... P>
|
||||
template <typename... P>
|
||||
#endif // TYPED_METHOD_BIND
|
||||
class MethodBindT : public MethodBind {
|
||||
void (MB_T::*method)(P...);
|
||||
@@ -339,7 +339,7 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
template <class T, class... P>
|
||||
template <typename T, typename... 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 <class T, class... P>
|
||||
template <typename T, typename... P>
|
||||
#else
|
||||
template <class... P>
|
||||
template <typename... P>
|
||||
#endif // TYPED_METHOD_BIND
|
||||
class MethodBindTC : public MethodBind {
|
||||
void (MB_T::*method)(P...) const;
|
||||
@@ -415,7 +415,7 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
template <class T, class... P>
|
||||
template <typename T, typename... P>
|
||||
MethodBind *create_method_bind(void (T::*p_method)(P...) const) {
|
||||
#ifdef TYPED_METHOD_BIND
|
||||
MethodBind *a = memnew((MethodBindTC<T, P...>)(p_method));
|
||||
@@ -429,9 +429,9 @@ MethodBind *create_method_bind(void (T::*p_method)(P...) const) {
|
||||
// Return, not const.
|
||||
|
||||
#ifdef TYPED_METHOD_BIND
|
||||
template <class T, class R, class... P>
|
||||
template <typename T, typename R, typename... P>
|
||||
#else
|
||||
template <class R, class... P>
|
||||
template <typename R, typename... P>
|
||||
#endif // TYPED_METHOD_BIND
|
||||
class MethodBindTR : public MethodBind {
|
||||
R(MB_T::*method)
|
||||
@@ -498,7 +498,7 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
template <class T, class R, class... P>
|
||||
template <typename T, typename R, typename... P>
|
||||
MethodBind *create_method_bind(R (T::*p_method)(P...)) {
|
||||
#ifdef TYPED_METHOD_BIND
|
||||
MethodBind *a = memnew((MethodBindTR<T, R, P...>)(p_method));
|
||||
@@ -512,9 +512,9 @@ MethodBind *create_method_bind(R (T::*p_method)(P...)) {
|
||||
// Return, const.
|
||||
|
||||
#ifdef TYPED_METHOD_BIND
|
||||
template <class T, class R, class... P>
|
||||
template <typename T, typename R, typename... P>
|
||||
#else
|
||||
template <class R, class... P>
|
||||
template <typename R, typename... P>
|
||||
#endif // TYPED_METHOD_BIND
|
||||
class MethodBindTRC : public MethodBind {
|
||||
R(MB_T::*method)
|
||||
@@ -581,7 +581,7 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
template <class T, class R, class... P>
|
||||
template <typename T, typename R, typename... P>
|
||||
MethodBind *create_method_bind(R (T::*p_method)(P...) const) {
|
||||
#ifdef TYPED_METHOD_BIND
|
||||
MethodBind *a = memnew((MethodBindTRC<T, R, P...>)(p_method));
|
||||
@@ -596,7 +596,7 @@ MethodBind *create_method_bind(R (T::*p_method)(P...) const) {
|
||||
|
||||
// no return
|
||||
|
||||
template <class... P>
|
||||
template <typename... P>
|
||||
class MethodBindTS : public MethodBind {
|
||||
void (*function)(P...);
|
||||
|
||||
@@ -652,7 +652,7 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
template <class... P>
|
||||
template <typename... P>
|
||||
MethodBind *create_static_method_bind(void (*p_method)(P...)) {
|
||||
MethodBind *a = memnew((MethodBindTS<P...>)(p_method));
|
||||
return a;
|
||||
@@ -660,7 +660,7 @@ MethodBind *create_static_method_bind(void (*p_method)(P...)) {
|
||||
|
||||
// return
|
||||
|
||||
template <class R, class... P>
|
||||
template <typename R, typename... P>
|
||||
class MethodBindTRS : public MethodBind {
|
||||
R(*function)
|
||||
(P...);
|
||||
@@ -722,7 +722,7 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
template <class R, class... P>
|
||||
template <typename R, typename... P>
|
||||
MethodBind *create_static_method_bind(R (*p_method)(P...)) {
|
||||
MethodBind *a = memnew((MethodBindTRS<R, P...>)(p_method));
|
||||
return a;
|
||||
|
||||
@@ -39,7 +39,7 @@
|
||||
|
||||
namespace godot {
|
||||
|
||||
template <class T>
|
||||
template <typename T>
|
||||
struct PtrToArg {};
|
||||
|
||||
#define MAKE_PTRARG(m_type) \
|
||||
@@ -166,8 +166,9 @@ MAKE_PTRARG_BY_REFERENCE(Variant);
|
||||
|
||||
// This is for Object.
|
||||
|
||||
template <class T>
|
||||
template <typename 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 reinterpret_cast<T *>(godot::internal::get_object_instance_binding(*reinterpret_cast<GDExtensionObjectPtr *>(const_cast<void *>(p_ptr))));
|
||||
}
|
||||
@@ -177,8 +178,9 @@ struct PtrToArg<T *> {
|
||||
}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
template <typename 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 reinterpret_cast<const T *>(godot::internal::get_object_instance_binding(*reinterpret_cast<GDExtensionObjectPtr *>(const_cast<void *>(p_ptr))));
|
||||
}
|
||||
|
||||
@@ -45,10 +45,10 @@
|
||||
|
||||
#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_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 {
|
||||
|
||||
@@ -75,31 +75,31 @@ struct MethodInfo {
|
||||
|
||||
MethodInfo();
|
||||
MethodInfo(StringName p_name);
|
||||
template <class... Args>
|
||||
template <typename... Args>
|
||||
MethodInfo(StringName p_name, const Args &...args);
|
||||
MethodInfo(Variant::Type ret);
|
||||
MethodInfo(Variant::Type ret, StringName p_name);
|
||||
template <class... Args>
|
||||
template <typename... Args>
|
||||
MethodInfo(Variant::Type ret, StringName p_name, const Args &...args);
|
||||
MethodInfo(const PropertyInfo &p_ret, StringName p_name);
|
||||
template <class... Args>
|
||||
template <typename... Args>
|
||||
MethodInfo(const PropertyInfo &p_ret, StringName p_name, const Args &...);
|
||||
};
|
||||
|
||||
template <class... Args>
|
||||
template <typename... Args>
|
||||
MethodInfo::MethodInfo(StringName p_name, const Args &...args) :
|
||||
name(p_name), flags(GDEXTENSION_METHOD_FLAG_NORMAL) {
|
||||
arguments = { args... };
|
||||
}
|
||||
|
||||
template <class... Args>
|
||||
template <typename... 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 <class... Args>
|
||||
template <typename... 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... };
|
||||
@@ -138,7 +138,7 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
template <typename T>
|
||||
T *Object::cast_to(Object *p_object) {
|
||||
if (p_object == nullptr) {
|
||||
return nullptr;
|
||||
@@ -151,7 +151,7 @@ T *Object::cast_to(Object *p_object) {
|
||||
return dynamic_cast<T *>(internal::get_object_instance_binding(casted));
|
||||
}
|
||||
|
||||
template <class T>
|
||||
template <typename T>
|
||||
const T *Object::cast_to(const Object *p_object) {
|
||||
if (p_object == nullptr) {
|
||||
return nullptr;
|
||||
|
||||
@@ -47,9 +47,9 @@ struct PropertyInfo {
|
||||
Variant::Type type = Variant::NIL;
|
||||
StringName name;
|
||||
StringName class_name;
|
||||
uint32_t hint = 0;
|
||||
uint32_t hint = PROPERTY_HINT_NONE;
|
||||
String hint_string;
|
||||
uint32_t usage = 7;
|
||||
uint32_t usage = PROPERTY_USAGE_DEFAULT;
|
||||
|
||||
PropertyInfo() = default;
|
||||
|
||||
|
||||
@@ -90,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 <class T, typename = void>
|
||||
template <typename T, typename = void>
|
||||
struct GetTypeInfo;
|
||||
|
||||
#define MAKE_TYPE_INFO(m_type, m_var_type) \
|
||||
@@ -248,14 +248,14 @@ inline StringName _gde_constant_get_enum_name(T param, StringName p_constant) {
|
||||
return GetTypeInfo<T>::get_class_info().class_name;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
template <typename 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) { return value &= ~p_flag; }
|
||||
_FORCE_INLINE_ void clear_flag(T p_flag) { 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; }
|
||||
@@ -295,7 +295,7 @@ inline StringName _gde_constant_get_bitfield_name(T param, StringName p_constant
|
||||
return GetTypeInfo<BitField<T>>::get_class_info().class_name;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
template <typename T>
|
||||
struct PtrToArg<TypedArray<T>> {
|
||||
_FORCE_INLINE_ static TypedArray<T> convert(const void *p_ptr) {
|
||||
return TypedArray<T>(*reinterpret_cast<const Array *>(p_ptr));
|
||||
@@ -306,7 +306,7 @@ struct PtrToArg<TypedArray<T>> {
|
||||
}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
template <typename T>
|
||||
struct PtrToArg<const TypedArray<T> &> {
|
||||
typedef Array EncodeT;
|
||||
_FORCE_INLINE_ static TypedArray<T>
|
||||
|
||||
@@ -187,29 +187,44 @@ 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_EDITOR = GDEXTENSION_INITIALIZATION_EDITOR,
|
||||
MODULE_INITIALIZATION_LEVEL_MAX
|
||||
};
|
||||
|
||||
class GDExtensionBinding {
|
||||
private:
|
||||
static void register_engine_classes();
|
||||
|
||||
public:
|
||||
using Callback = void (*)(ModuleInitializationLevel p_level);
|
||||
|
||||
static Callback init_callback;
|
||||
static Callback terminate_callback;
|
||||
static GDExtensionInitializationLevel minimum_initialization_level;
|
||||
static GDExtensionBool init(GDExtensionInterfaceGetProcAddress p_get_proc_address, GDExtensionClassLibraryPtr p_library, GDExtensionInitialization *r_initialization);
|
||||
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);
|
||||
|
||||
public:
|
||||
static void initialize_level(void *userdata, GDExtensionInitializationLevel p_level);
|
||||
static void deinitialize_level(void *userdata, GDExtensionInitializationLevel p_level);
|
||||
static void initialize_level(void *p_userdata, GDExtensionInitializationLevel p_level);
|
||||
static void deinitialize_level(void *p_userdata, GDExtensionInitializationLevel p_level);
|
||||
|
||||
class InitObject {
|
||||
GDExtensionInterfaceGetProcAddress get_proc_address;
|
||||
GDExtensionClassLibraryPtr library;
|
||||
GDExtensionInitialization *initialization;
|
||||
mutable InitData *init_data = nullptr;
|
||||
|
||||
public:
|
||||
InitObject(GDExtensionInterfaceGetProcAddress p_get_proc_address, GDExtensionClassLibraryPtr p_library, GDExtensionInitialization *r_initialization);
|
||||
|
||||
@@ -32,108 +32,160 @@
|
||||
#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 <class T>
|
||||
template <typename T>
|
||||
class Vector;
|
||||
|
||||
template <class T, class V>
|
||||
template <typename T, typename 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 <class T>
|
||||
template <typename T>
|
||||
class CowData {
|
||||
template <class TV>
|
||||
template <typename TV>
|
||||
friend class Vector;
|
||||
|
||||
template <class TV, class VV>
|
||||
template <typename TV, typename 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
|
||||
|
||||
_FORCE_INLINE_ SafeNumeric<uint32_t> *_get_refcount() const {
|
||||
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 {
|
||||
if (!_ptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return reinterpret_cast<SafeNumeric<uint32_t> *>(_ptr) - 2;
|
||||
return (SafeNumeric<USize> *)((uint8_t *)_ptr - DATA_OFFSET + REF_COUNT_OFFSET);
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ uint32_t *_get_size() const {
|
||||
_FORCE_INLINE_ USize *_get_size() const {
|
||||
if (!_ptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return reinterpret_cast<uint32_t *>(_ptr) - 1;
|
||||
return (USize *)((uint8_t *)_ptr - DATA_OFFSET + SIZE_OFFSET);
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ T *_get_data() const {
|
||||
if (!_ptr) {
|
||||
return nullptr;
|
||||
_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;
|
||||
}
|
||||
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 defined(__GNUC__) && defined(IS_32_BIT)
|
||||
USize o;
|
||||
USize p;
|
||||
if (__builtin_mul_overflow(p_elements, sizeof(T), &o)) {
|
||||
*out = 0;
|
||||
return false;
|
||||
}
|
||||
*out = next_power_of_2(o);
|
||||
if (__builtin_add_overflow(o, static_cast<size_t>(32), &p)) {
|
||||
*out = next_po2(o);
|
||||
if (__builtin_add_overflow(o, static_cast<USize>(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);
|
||||
uint32_t _copy_on_write();
|
||||
USize _copy_on_write();
|
||||
|
||||
public:
|
||||
void operator=(const CowData<T> &p_from) { _ref(p_from); }
|
||||
|
||||
_FORCE_INLINE_ T *ptrw() {
|
||||
_copy_on_write();
|
||||
return (T *)_get_data();
|
||||
return _ptr;
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ const T *ptr() const {
|
||||
return _get_data();
|
||||
return _ptr;
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ int size() const {
|
||||
uint32_t *size = (uint32_t *)_get_size();
|
||||
_FORCE_INLINE_ Size size() const {
|
||||
USize *size = (USize *)_get_size();
|
||||
if (size) {
|
||||
return *size;
|
||||
} else {
|
||||
@@ -144,41 +196,42 @@ public:
|
||||
_FORCE_INLINE_ void clear() { resize(0); }
|
||||
_FORCE_INLINE_ bool is_empty() const { return _ptr == nullptr; }
|
||||
|
||||
_FORCE_INLINE_ void set(int p_index, const T &p_elem) {
|
||||
_FORCE_INLINE_ void set(Size p_index, const T &p_elem) {
|
||||
ERR_FAIL_INDEX(p_index, size());
|
||||
_copy_on_write();
|
||||
_get_data()[p_index] = p_elem;
|
||||
_ptr[p_index] = p_elem;
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ T &get_m(int p_index) {
|
||||
_FORCE_INLINE_ T &get_m(Size p_index) {
|
||||
CRASH_BAD_INDEX(p_index, size());
|
||||
_copy_on_write();
|
||||
return _get_data()[p_index];
|
||||
return _ptr[p_index];
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ const T &get(int p_index) const {
|
||||
_FORCE_INLINE_ const T &get(Size p_index) const {
|
||||
CRASH_BAD_INDEX(p_index, size());
|
||||
|
||||
return _get_data()[p_index];
|
||||
return _ptr[p_index];
|
||||
}
|
||||
|
||||
Error resize(int p_size);
|
||||
template <bool p_ensure_zero = false>
|
||||
Error resize(Size p_size);
|
||||
|
||||
_FORCE_INLINE_ void remove_at(int p_index) {
|
||||
_FORCE_INLINE_ void remove_at(Size p_index) {
|
||||
ERR_FAIL_INDEX(p_index, size());
|
||||
T *p = ptrw();
|
||||
int len = size();
|
||||
for (int i = p_index; i < len - 1; i++) {
|
||||
Size len = size();
|
||||
for (Size i = p_index; i < len - 1; i++) {
|
||||
p[i] = p[i + 1];
|
||||
}
|
||||
|
||||
resize(len - 1);
|
||||
}
|
||||
|
||||
Error insert(int p_pos, const T &p_val) {
|
||||
Error insert(Size p_pos, const T &p_val) {
|
||||
ERR_FAIL_INDEX_V(p_pos, size() + 1, ERR_INVALID_PARAMETER);
|
||||
resize(size() + 1);
|
||||
for (int i = (size() - 1); i > p_pos; i--) {
|
||||
for (Size i = (size() - 1); i > p_pos; i--) {
|
||||
set(i, get(i - 1));
|
||||
}
|
||||
set(p_pos, p_val);
|
||||
@@ -186,83 +239,88 @@ public:
|
||||
return OK;
|
||||
}
|
||||
|
||||
int find(const T &p_val, int p_from = 0) const;
|
||||
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;
|
||||
|
||||
_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 <class T>
|
||||
template <typename T>
|
||||
void CowData<T>::_unref(void *p_data) {
|
||||
if (!p_data) {
|
||||
return;
|
||||
}
|
||||
|
||||
SafeNumeric<uint32_t> *refc = _get_refcount();
|
||||
SafeNumeric<USize> *refc = _get_refcount();
|
||||
|
||||
if (refc->decrement() > 0) {
|
||||
return; // still in use
|
||||
}
|
||||
// clean up
|
||||
|
||||
if (!__has_trivial_destructor(T)) {
|
||||
uint32_t *count = _get_size();
|
||||
if constexpr (!std::is_trivially_destructible_v<T>) {
|
||||
USize *count = _get_size();
|
||||
T *data = (T *)(count + 1);
|
||||
|
||||
for (uint32_t i = 0; i < *count; ++i) {
|
||||
for (USize i = 0; i < *count; ++i) {
|
||||
// call destructors
|
||||
data[i].~T();
|
||||
}
|
||||
}
|
||||
|
||||
// free mem
|
||||
Memory::free_static((uint8_t *)p_data, true);
|
||||
Memory::free_static(((uint8_t *)p_data) - DATA_OFFSET, false);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
uint32_t CowData<T>::_copy_on_write() {
|
||||
template <typename T>
|
||||
typename CowData<T>::USize CowData<T>::_copy_on_write() {
|
||||
if (!_ptr) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
SafeNumeric<uint32_t> *refc = _get_refcount();
|
||||
SafeNumeric<USize> *refc = _get_refcount();
|
||||
|
||||
uint32_t rc = refc->get();
|
||||
USize rc = refc->get();
|
||||
if (unlikely(rc > 1)) {
|
||||
/* in use by more than me */
|
||||
uint32_t current_size = *_get_size();
|
||||
USize current_size = *_get_size();
|
||||
|
||||
uint32_t *mem_new = (uint32_t *)Memory::alloc_static(_get_alloc_size(current_size), true);
|
||||
uint8_t *mem_new = (uint8_t *)Memory::alloc_static(_get_alloc_size(current_size) + DATA_OFFSET, false);
|
||||
ERR_FAIL_NULL_V(mem_new, 0);
|
||||
|
||||
new (mem_new - 2) SafeNumeric<uint32_t>(1); // refcount
|
||||
*(mem_new - 1) = current_size; // size
|
||||
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);
|
||||
|
||||
T *_data = (T *)(mem_new);
|
||||
new (_refc_ptr) SafeNumeric<USize>(1); //refcount
|
||||
*(_size_ptr) = current_size; //size
|
||||
|
||||
// initialize new elements
|
||||
if (__has_trivial_copy(T)) {
|
||||
memcpy(mem_new, _ptr, current_size * sizeof(T));
|
||||
|
||||
if constexpr (std::is_trivially_copyable_v<T>) {
|
||||
memcpy((uint8_t *)_data_ptr, _ptr, current_size * sizeof(T));
|
||||
} else {
|
||||
for (uint32_t i = 0; i < current_size; i++) {
|
||||
memnew_placement(&_data[i], T(_get_data()[i]));
|
||||
for (USize i = 0; i < current_size; i++) {
|
||||
memnew_placement(&_data_ptr[i], T(_ptr[i]));
|
||||
}
|
||||
}
|
||||
|
||||
_unref(_ptr);
|
||||
_ptr = _data;
|
||||
_ptr = _data_ptr;
|
||||
|
||||
rc = 1;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
Error CowData<T>::resize(int p_size) {
|
||||
template <typename T>
|
||||
template <bool p_ensure_zero>
|
||||
Error CowData<T>::resize(Size p_size) {
|
||||
ERR_FAIL_COND_V(p_size < 0, ERR_INVALID_PARAMETER);
|
||||
|
||||
int current_size = size();
|
||||
Size current_size = size();
|
||||
|
||||
if (p_size == current_size) {
|
||||
return OK;
|
||||
@@ -276,59 +334,71 @@ Error CowData<T>::resize(int p_size) {
|
||||
}
|
||||
|
||||
// possibly changing size, copy on write
|
||||
uint32_t rc = _copy_on_write();
|
||||
USize rc = _copy_on_write();
|
||||
|
||||
size_t current_alloc_size = _get_alloc_size(current_size);
|
||||
size_t alloc_size;
|
||||
USize current_alloc_size = _get_alloc_size(current_size);
|
||||
USize 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
|
||||
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
|
||||
uint8_t *mem_new = (uint8_t *)Memory::alloc_static(alloc_size + DATA_OFFSET, false);
|
||||
ERR_FAIL_NULL_V(mem_new, ERR_OUT_OF_MEMORY);
|
||||
|
||||
_ptr = (T *)ptr;
|
||||
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 (_refc_ptr) SafeNumeric<USize>(1); //refcount
|
||||
*(_size_ptr) = 0; //size, currently none
|
||||
|
||||
_ptr = _data_ptr;
|
||||
} else {
|
||||
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
|
||||
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);
|
||||
|
||||
_ptr = (T *)(_ptrnew);
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
// construct the newly created elements
|
||||
|
||||
if (!__has_trivial_constructor(T)) {
|
||||
T *elems = _get_data();
|
||||
|
||||
for (int i = *_get_size(); i < p_size; i++) {
|
||||
memnew_placement(&elems[i], T);
|
||||
if constexpr (!std::is_trivially_constructible_v<T>) {
|
||||
for (Size i = *_get_size(); i < p_size; i++) {
|
||||
memnew_placement(&_ptr[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 (!__has_trivial_destructor(T)) {
|
||||
if constexpr (!std::is_trivially_destructible_v<T>) {
|
||||
// deinitialize no longer needed elements
|
||||
for (uint32_t i = p_size; i < *_get_size(); i++) {
|
||||
T *t = &_get_data()[i];
|
||||
for (USize i = p_size; i < *_get_size(); i++) {
|
||||
T *t = &_ptr[i];
|
||||
t->~T();
|
||||
}
|
||||
}
|
||||
|
||||
if (alloc_size != current_alloc_size) {
|
||||
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
|
||||
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);
|
||||
|
||||
_ptr = (T *)(_ptrnew);
|
||||
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;
|
||||
}
|
||||
|
||||
*_get_size() = p_size;
|
||||
@@ -337,15 +407,15 @@ Error CowData<T>::resize(int p_size) {
|
||||
return OK;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
int CowData<T>::find(const T &p_val, int p_from) const {
|
||||
int ret = -1;
|
||||
template <typename T>
|
||||
typename CowData<T>::Size CowData<T>::find(const T &p_val, Size p_from) const {
|
||||
Size ret = -1;
|
||||
|
||||
if (p_from < 0 || size() == 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
for (int i = p_from; i < size(); i++) {
|
||||
for (Size i = p_from; i < size(); i++) {
|
||||
if (get(i) == p_val) {
|
||||
ret = i;
|
||||
break;
|
||||
@@ -355,12 +425,42 @@ int CowData<T>::find(const T &p_val, int p_from) const {
|
||||
return ret;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
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>
|
||||
void CowData<T>::_ref(const CowData *p_from) {
|
||||
_ref(*p_from);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
template <typename T>
|
||||
void CowData<T>::_ref(const CowData &p_from) {
|
||||
if (_ptr == p_from._ptr) {
|
||||
return; // self assign, do nothing.
|
||||
@@ -378,7 +478,7 @@ void CowData<T>::_ref(const CowData &p_from) {
|
||||
}
|
||||
}
|
||||
|
||||
template <class T>
|
||||
template <typename T>
|
||||
CowData<T>::~CowData() {
|
||||
_unref(_ptr);
|
||||
}
|
||||
|
||||
@@ -52,7 +52,7 @@ namespace godot {
|
||||
* The assignment operator copy the pairs from one map to the other.
|
||||
*/
|
||||
|
||||
template <class TKey, class TValue>
|
||||
template <typename TKey, typename TValue>
|
||||
struct HashMapElement {
|
||||
HashMapElement *next = nullptr;
|
||||
HashMapElement *prev = nullptr;
|
||||
@@ -62,10 +62,10 @@ struct HashMapElement {
|
||||
data(p_key, p_value) {}
|
||||
};
|
||||
|
||||
template <class TKey, class TValue,
|
||||
class Hasher = HashMapHasherDefault,
|
||||
class Comparator = HashMapComparatorDefault<TKey>,
|
||||
class Allocator = DefaultTypedAllocator<HashMapElement<TKey, TValue>>>
|
||||
template <typename TKey, typename TValue,
|
||||
typename Hasher = HashMapHasherDefault,
|
||||
typename Comparator = HashMapComparatorDefault<TKey>,
|
||||
typename Allocator = DefaultTypedAllocator<HashMapElement<TKey, TValue>>>
|
||||
class HashMap {
|
||||
public:
|
||||
const uint32_t MIN_CAPACITY_INDEX = 2; // Use a prime.
|
||||
|
||||
@@ -48,9 +48,9 @@ namespace godot {
|
||||
*
|
||||
*/
|
||||
|
||||
template <class TKey,
|
||||
class Hasher = HashMapHasherDefault,
|
||||
class Comparator = HashMapComparatorDefault<TKey>>
|
||||
template <typename TKey,
|
||||
typename Hasher = HashMapHasherDefault,
|
||||
typename Comparator = HashMapComparatorDefault<TKey>>
|
||||
class HashSet {
|
||||
public:
|
||||
static constexpr uint32_t MIN_CAPACITY_INDEX = 2; // Use a prime.
|
||||
|
||||
@@ -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 <class T>
|
||||
template <typename 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 <class T>
|
||||
template <typename 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 <class T>
|
||||
template <typename T>
|
||||
class Ref;
|
||||
|
||||
struct HashMapHasherDefault {
|
||||
// Generic hash function for any type.
|
||||
template <class T>
|
||||
template <typename T>
|
||||
static _FORCE_INLINE_ uint32_t hash(const T *p_pointer) { return hash_one_uint64((uint64_t)p_pointer); }
|
||||
|
||||
template <class T>
|
||||
template <typename 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(); }
|
||||
|
||||
@@ -45,7 +45,7 @@
|
||||
|
||||
namespace godot {
|
||||
|
||||
template <class T, class A = DefaultAllocator>
|
||||
template <typename T, typename A = DefaultAllocator>
|
||||
class List {
|
||||
struct _Data;
|
||||
|
||||
@@ -221,7 +221,7 @@ private:
|
||||
int size_cache = 0;
|
||||
|
||||
bool erase(const Element *p_I) {
|
||||
ERR_FAIL_COND_V(!p_I, false);
|
||||
ERR_FAIL_NULL_V(p_I, false);
|
||||
ERR_FAIL_COND_V(p_I->data != this, false);
|
||||
|
||||
if (first == p_I) {
|
||||
@@ -410,7 +410,7 @@ public:
|
||||
/**
|
||||
* find an element in the list,
|
||||
*/
|
||||
template <class T_v>
|
||||
template <typename T_v>
|
||||
Element *find(const T_v &p_val) {
|
||||
Element *it = front();
|
||||
while (it) {
|
||||
@@ -646,7 +646,7 @@ public:
|
||||
sort_custom<Comparator<T>>();
|
||||
}
|
||||
|
||||
template <class C>
|
||||
template <typename C>
|
||||
void sort_custom_inplace() {
|
||||
if (size() < 2) {
|
||||
return;
|
||||
@@ -693,7 +693,7 @@ public:
|
||||
_data->last = to;
|
||||
}
|
||||
|
||||
template <class C>
|
||||
template <typename C>
|
||||
struct AuxiliaryComparator {
|
||||
C compare;
|
||||
_FORCE_INLINE_ bool operator()(const Element *a, const Element *b) const {
|
||||
@@ -701,7 +701,7 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
template <class C>
|
||||
template <typename 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
|
||||
|
||||
@@ -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 <class T, class U = uint32_t, bool force_trivial = false, bool tight = false>
|
||||
template <typename T, typename U = uint32_t, bool force_trivial = false, bool tight = false>
|
||||
class LocalVector {
|
||||
private:
|
||||
U count = 0;
|
||||
@@ -257,7 +257,7 @@ public:
|
||||
return -1;
|
||||
}
|
||||
|
||||
template <class C>
|
||||
template <typename C>
|
||||
void sort_custom() {
|
||||
U len = count;
|
||||
if (len == 0) {
|
||||
@@ -331,7 +331,7 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
template <class T, class U = uint32_t, bool force_trivial = false>
|
||||
template <typename T, typename U = uint32_t, bool force_trivial = false>
|
||||
using TightLocalVector = LocalVector<T, U, force_trivial, true>;
|
||||
|
||||
} // namespace godot
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
|
||||
namespace godot {
|
||||
|
||||
template <class F, class S>
|
||||
template <typename F, typename S>
|
||||
struct Pair {
|
||||
F first;
|
||||
S second;
|
||||
@@ -49,17 +49,17 @@ struct Pair {
|
||||
}
|
||||
};
|
||||
|
||||
template <class F, class S>
|
||||
template <typename F, typename S>
|
||||
bool operator==(const Pair<F, S> &pair, const Pair<F, S> &other) {
|
||||
return (pair.first == other.first) && (pair.second == other.second);
|
||||
}
|
||||
|
||||
template <class F, class S>
|
||||
template <typename F, typename S>
|
||||
bool operator!=(const Pair<F, S> &pair, const Pair<F, S> &other) {
|
||||
return (pair.first != other.first) || (pair.second != other.second);
|
||||
}
|
||||
|
||||
template <class F, class S>
|
||||
template <typename F, typename 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 <class K, class V>
|
||||
template <typename K, typename V>
|
||||
struct KeyValue {
|
||||
const K key;
|
||||
V value;
|
||||
@@ -85,17 +85,17 @@ struct KeyValue {
|
||||
}
|
||||
};
|
||||
|
||||
template <class K, class V>
|
||||
template <typename K, typename V>
|
||||
bool operator==(const KeyValue<K, V> &pair, const KeyValue<K, V> &other) {
|
||||
return (pair.key == other.key) && (pair.value == other.value);
|
||||
}
|
||||
|
||||
template <class K, class V>
|
||||
template <typename K, typename V>
|
||||
bool operator!=(const KeyValue<K, V> &pair, const KeyValue<K, V> &other) {
|
||||
return (pair.key != other.key) || (pair.value != other.value);
|
||||
}
|
||||
|
||||
template <class K, class V>
|
||||
template <typename K, typename V>
|
||||
struct KeyValueSort {
|
||||
bool operator()(const KeyValue<K, V> &A, const KeyValue<K, V> &B) const {
|
||||
return A.key < B.key;
|
||||
|
||||
@@ -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 <class K, class V, class C = Comparator<K>, class A = DefaultAllocator>
|
||||
template <typename K, typename V, typename C = Comparator<K>, typename A = DefaultAllocator>
|
||||
class RBMap {
|
||||
enum Color {
|
||||
RED,
|
||||
|
||||
@@ -38,7 +38,7 @@
|
||||
|
||||
namespace godot {
|
||||
|
||||
template <class T, class C = Comparator<T>, class A = DefaultAllocator>
|
||||
template <typename T, typename C = Comparator<T>, typename A = DefaultAllocator>
|
||||
class RBSet {
|
||||
enum Color {
|
||||
RED,
|
||||
|
||||
@@ -42,7 +42,7 @@
|
||||
|
||||
namespace godot {
|
||||
|
||||
template <class T, bool THREAD_SAFE = false>
|
||||
template <typename 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_COND(!mem);
|
||||
ERR_FAIL_NULL(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_COND(!mem);
|
||||
ERR_FAIL_NULL(mem);
|
||||
memnew_placement(mem, T(p_value));
|
||||
}
|
||||
|
||||
@@ -347,7 +347,7 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
template <class T, bool THREAD_SAFE = false>
|
||||
template <typename 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_COND(!ptr);
|
||||
ERR_FAIL_NULL(ptr);
|
||||
*ptr = p_new_ptr;
|
||||
}
|
||||
|
||||
@@ -406,7 +406,7 @@ public:
|
||||
alloc(p_target_chunk_byte_size) {}
|
||||
};
|
||||
|
||||
template <class T, bool THREAD_SAFE = false>
|
||||
template <typename T, bool THREAD_SAFE = false>
|
||||
class RID_Owner {
|
||||
RID_Alloc<T, THREAD_SAFE> alloc;
|
||||
|
||||
|
||||
@@ -48,7 +48,16 @@ namespace godot {
|
||||
// value and, as an important benefit, you can be sure the value is properly synchronized
|
||||
// even with threads that are already running.
|
||||
|
||||
template <class T>
|
||||
// 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>
|
||||
class SafeNumeric {
|
||||
std::atomic<T> value;
|
||||
|
||||
@@ -186,7 +195,7 @@ public:
|
||||
|
||||
#else
|
||||
|
||||
template <class T>
|
||||
template <typename T>
|
||||
class SafeNumeric {
|
||||
protected:
|
||||
T value;
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
|
||||
namespace godot {
|
||||
|
||||
template <class T, class Comparator = _DefaultComparator<T>>
|
||||
template <typename T, typename Comparator = _DefaultComparator<T>>
|
||||
class SearchArray {
|
||||
public:
|
||||
Comparator compare;
|
||||
|
||||
@@ -36,7 +36,7 @@
|
||||
|
||||
namespace godot {
|
||||
|
||||
template <class T>
|
||||
template <typename T>
|
||||
class SelfList {
|
||||
public:
|
||||
class List {
|
||||
|
||||
@@ -41,7 +41,7 @@ namespace godot {
|
||||
break; \
|
||||
}
|
||||
|
||||
template <class T>
|
||||
template <typename 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 <class T, class Comparator = _DefaultComparator<T>, bool Validate = SORT_ARRAY_VALIDATE_ENABLED>
|
||||
template <typename T, typename Comparator = _DefaultComparator<T>, bool Validate = SORT_ARRAY_VALIDATE_ENABLED>
|
||||
class SortArray {
|
||||
enum {
|
||||
INTROSORT_THRESHOLD = 16
|
||||
|
||||
@@ -52,7 +52,7 @@ class ThreadWorkPool {
|
||||
virtual ~BaseWork() = default;
|
||||
};
|
||||
|
||||
template <class C, class M, class U>
|
||||
template <typename C, typename M, typename U>
|
||||
struct Work : public BaseWork {
|
||||
C *instance;
|
||||
M method;
|
||||
@@ -94,9 +94,9 @@ class ThreadWorkPool {
|
||||
}
|
||||
|
||||
public:
|
||||
template <class C, class M, class U>
|
||||
template <typename C, typename M, typename U>
|
||||
void begin_work(uint32_t p_elements, C *p_instance, M p_method, U p_userdata) {
|
||||
ERR_FAIL_COND(!threads); // never initialized
|
||||
ERR_FAIL_NULL(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_COND_V(current_work == nullptr, true);
|
||||
ERR_FAIL_NULL_V(current_work, true);
|
||||
return index.load(std::memory_order_acquire) >= current_work->max_elements;
|
||||
}
|
||||
|
||||
uint32_t get_work_index() const {
|
||||
ERR_FAIL_COND_V(current_work == nullptr, 0);
|
||||
ERR_FAIL_NULL_V(current_work, 0);
|
||||
uint32_t idx = index.load(std::memory_order_acquire);
|
||||
return Math::min(idx, current_work->max_elements);
|
||||
}
|
||||
|
||||
void end_work() {
|
||||
ERR_FAIL_COND(current_work == nullptr);
|
||||
ERR_FAIL_NULL(current_work);
|
||||
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 <class C, class M, class U>
|
||||
template <typename C, typename M, typename U>
|
||||
void do_work(uint32_t p_elements, C *p_instance, M p_method, U p_userdata) {
|
||||
switch (p_elements) {
|
||||
case 0:
|
||||
|
||||
@@ -47,38 +47,42 @@
|
||||
|
||||
namespace godot {
|
||||
|
||||
template <class T>
|
||||
template <typename T>
|
||||
class VectorWriteProxy {
|
||||
public:
|
||||
_FORCE_INLINE_ T &operator[](int p_index) {
|
||||
_FORCE_INLINE_ T &operator[](typename CowData<T>::Size p_index) {
|
||||
CRASH_BAD_INDEX(p_index, ((Vector<T> *)(this))->_cowdata.size());
|
||||
|
||||
return ((Vector<T> *)(this))->_cowdata.ptrw()[p_index];
|
||||
}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
template <typename 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(int p_index) { _cowdata.remove_at(p_index); }
|
||||
void erase(const T &p_val) {
|
||||
int idx = find(p_val);
|
||||
void remove_at(Size p_index) { _cowdata.remove_at(p_index); }
|
||||
_FORCE_INLINE_ bool erase(const T &p_val) {
|
||||
Size idx = find(p_val);
|
||||
if (idx >= 0) {
|
||||
remove_at(idx);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void reverse();
|
||||
|
||||
_FORCE_INLINE_ T *ptrw() { return _cowdata.ptrw(); }
|
||||
@@ -86,37 +90,45 @@ public:
|
||||
_FORCE_INLINE_ void clear() { resize(0); }
|
||||
_FORCE_INLINE_ bool is_empty() const { return _cowdata.is_empty(); }
|
||||
|
||||
_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); }
|
||||
_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); }
|
||||
|
||||
void append_array(Vector<T> p_other);
|
||||
|
||||
_FORCE_INLINE_ bool has(const T &p_val) const { return find(p_val) != -1; }
|
||||
|
||||
template <class C>
|
||||
void sort_custom() {
|
||||
int len = _cowdata.size();
|
||||
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();
|
||||
if (len == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
T *data = ptrw();
|
||||
SortArray<T, C> sorter;
|
||||
SortArray<T, Comparator, Validate> sorter{ args... };
|
||||
sorter.sort(data, len);
|
||||
}
|
||||
|
||||
void sort() {
|
||||
sort_custom<_DefaultComparator<T>>();
|
||||
Size bsearch(const T &p_value, bool p_before) {
|
||||
return bsearch_custom<_DefaultComparator<T>>(p_value, p_before);
|
||||
}
|
||||
|
||||
int bsearch(const T &p_value, bool p_before) {
|
||||
SearchArray<T> search;
|
||||
template <typename Comparator, typename Value, typename... Args>
|
||||
Size bsearch_custom(const Value &p_value, bool p_before, Args &&...args) {
|
||||
SearchArray<T, Comparator> search{ args... };
|
||||
return search.bisect(ptrw(), size(), p_value, p_before);
|
||||
}
|
||||
|
||||
@@ -125,7 +137,7 @@ public:
|
||||
}
|
||||
|
||||
void ordered_insert(const T &p_val) {
|
||||
int i;
|
||||
Size i;
|
||||
for (i = 0; i < _cowdata.size(); i++) {
|
||||
if (p_val < operator[](i)) {
|
||||
break;
|
||||
@@ -140,33 +152,36 @@ 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(int p_begin, int p_end = INT_MAX) const {
|
||||
Vector<T> slice(Size p_begin, Size p_end = CowData<T>::MAX_INT) const {
|
||||
Vector<T> result;
|
||||
|
||||
const int s = size();
|
||||
const Size s = size();
|
||||
|
||||
int begin = Math::clamp(p_begin, -s, s);
|
||||
Size begin = CLAMP(p_begin, -s, s);
|
||||
if (begin < 0) {
|
||||
begin += s;
|
||||
}
|
||||
int end = Math::clamp(p_end, -s, s);
|
||||
Size end = CLAMP(p_end, -s, s);
|
||||
if (end < 0) {
|
||||
end += s;
|
||||
}
|
||||
|
||||
ERR_FAIL_COND_V(begin > end, result);
|
||||
|
||||
int result_size = end - begin;
|
||||
Size result_size = end - begin;
|
||||
result.resize(result_size);
|
||||
|
||||
const T *const r = ptr();
|
||||
T *const w = result.ptrw();
|
||||
for (int i = 0; i < result_size; ++i) {
|
||||
for (Size i = 0; i < result_size; ++i) {
|
||||
w[i] = r[begin + i];
|
||||
}
|
||||
|
||||
@@ -174,11 +189,11 @@ public:
|
||||
}
|
||||
|
||||
bool operator==(const Vector<T> &p_arr) const {
|
||||
int s = size();
|
||||
Size s = size();
|
||||
if (s != p_arr.size()) {
|
||||
return false;
|
||||
}
|
||||
for (int i = 0; i < s; i++) {
|
||||
for (Size i = 0; i < s; i++) {
|
||||
if (operator[](i) != p_arr[i]) {
|
||||
return false;
|
||||
}
|
||||
@@ -187,11 +202,11 @@ public:
|
||||
}
|
||||
|
||||
bool operator!=(const Vector<T> &p_arr) const {
|
||||
int s = size();
|
||||
Size s = size();
|
||||
if (s != p_arr.size()) {
|
||||
return true;
|
||||
}
|
||||
for (int i = 0; i < s; i++) {
|
||||
for (Size i = 0; i < s; i++) {
|
||||
if (operator[](i) != p_arr[i]) {
|
||||
return true;
|
||||
}
|
||||
@@ -268,7 +283,7 @@ public:
|
||||
Error err = _cowdata.resize(p_init.size());
|
||||
ERR_FAIL_COND(err);
|
||||
|
||||
int i = 0;
|
||||
Size i = 0;
|
||||
for (const T &element : p_init) {
|
||||
_cowdata.set(i++, element);
|
||||
}
|
||||
@@ -278,28 +293,28 @@ public:
|
||||
_FORCE_INLINE_ ~Vector() {}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
template <typename T>
|
||||
void Vector<T>::reverse() {
|
||||
for (int i = 0; i < size() / 2; i++) {
|
||||
for (Size i = 0; i < size() / 2; i++) {
|
||||
T *p = ptrw();
|
||||
SWAP(p[i], p[size() - i - 1]);
|
||||
}
|
||||
}
|
||||
|
||||
template <class T>
|
||||
template <typename T>
|
||||
void Vector<T>::append_array(Vector<T> p_other) {
|
||||
const int ds = p_other.size();
|
||||
const Size ds = p_other.size();
|
||||
if (ds == 0) {
|
||||
return;
|
||||
}
|
||||
const int bs = size();
|
||||
const Size bs = size();
|
||||
resize(bs + ds);
|
||||
for (int i = 0; i < ds; ++i) {
|
||||
for (Size i = 0; i < ds; ++i) {
|
||||
ptrw()[bs + i] = p_other[i];
|
||||
}
|
||||
}
|
||||
|
||||
template <class T>
|
||||
template <typename T>
|
||||
bool Vector<T>::push_back(T p_elem) {
|
||||
Error err = resize(size() + 1);
|
||||
ERR_FAIL_COND_V(err, true);
|
||||
@@ -308,10 +323,10 @@ bool Vector<T>::push_back(T p_elem) {
|
||||
return false;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
template <typename T>
|
||||
void Vector<T>::fill(T p_elem) {
|
||||
T *p = ptrw();
|
||||
for (int i = 0; i < size(); i++) {
|
||||
for (Size i = 0; i < size(); i++) {
|
||||
p[i] = p_elem;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
|
||||
namespace godot {
|
||||
|
||||
template <class T, class V>
|
||||
template <typename T, typename V>
|
||||
class VMap {
|
||||
public:
|
||||
struct Pair {
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
|
||||
namespace godot {
|
||||
|
||||
template <class T>
|
||||
template <typename T>
|
||||
class VSet {
|
||||
Vector<T> _data;
|
||||
|
||||
|
||||
@@ -31,82 +31,111 @@
|
||||
#ifndef GODOT_CHAR_STRING_HPP
|
||||
#define GODOT_CHAR_STRING_HPP
|
||||
|
||||
#include <godot_cpp/templates/cowdata.hpp>
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
|
||||
namespace godot {
|
||||
|
||||
class CharString {
|
||||
friend class String;
|
||||
template <typename T>
|
||||
class CharStringT;
|
||||
|
||||
const char *_data = nullptr;
|
||||
int _length = 0;
|
||||
template <typename T>
|
||||
class CharProxy {
|
||||
template <typename TS>
|
||||
friend class CharStringT;
|
||||
|
||||
CharString(const char *str, int length);
|
||||
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:
|
||||
int length() const;
|
||||
const char *get_data() const;
|
||||
_FORCE_INLINE_ CharProxy(const CharProxy<T> &p_other) :
|
||||
_index(p_other._index),
|
||||
_cowdata(p_other._cowdata) {}
|
||||
|
||||
CharString(CharString &&p_str);
|
||||
void operator=(CharString &&p_str);
|
||||
CharString() {}
|
||||
~CharString();
|
||||
_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());
|
||||
}
|
||||
};
|
||||
|
||||
class Char16String {
|
||||
template <typename T>
|
||||
class CharStringT {
|
||||
friend class String;
|
||||
|
||||
const char16_t *_data = nullptr;
|
||||
int _length = 0;
|
||||
|
||||
Char16String(const char16_t *str, int length);
|
||||
CowData<T> _cowdata;
|
||||
static inline const T _null = 0;
|
||||
|
||||
public:
|
||||
int length() const;
|
||||
const char16_t *get_data() const;
|
||||
_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); }
|
||||
|
||||
Char16String(Char16String &&p_str);
|
||||
void operator=(Char16String &&p_str);
|
||||
Char16String() {}
|
||||
~Char16String();
|
||||
_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);
|
||||
};
|
||||
|
||||
class Char32String {
|
||||
friend class String;
|
||||
template <>
|
||||
const char *CharStringT<char>::get_data() const;
|
||||
|
||||
const char32_t *_data = nullptr;
|
||||
int _length = 0;
|
||||
template <>
|
||||
const char16_t *CharStringT<char16_t>::get_data() const;
|
||||
|
||||
Char32String(const char32_t *str, int length);
|
||||
template <>
|
||||
const char32_t *CharStringT<char32_t>::get_data() const;
|
||||
|
||||
public:
|
||||
int length() const;
|
||||
const char32_t *get_data() const;
|
||||
template <>
|
||||
const wchar_t *CharStringT<wchar_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();
|
||||
};
|
||||
typedef CharStringT<char> CharString;
|
||||
typedef CharStringT<char16_t> Char16String;
|
||||
typedef CharStringT<char32_t> Char32String;
|
||||
typedef CharStringT<wchar_t> CharWideString;
|
||||
|
||||
} // namespace godot
|
||||
|
||||
|
||||
@@ -36,7 +36,7 @@
|
||||
|
||||
namespace godot {
|
||||
|
||||
template <class T>
|
||||
template <typename T>
|
||||
class TypedArray : public Array {
|
||||
public:
|
||||
_FORCE_INLINE_ void operator=(const Array &p_array) {
|
||||
|
||||
@@ -47,8 +47,6 @@ 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;
|
||||
|
||||
@@ -122,6 +120,7 @@ public:
|
||||
OP_NEGATE,
|
||||
OP_POSITIVE,
|
||||
OP_MODULE,
|
||||
OP_POWER,
|
||||
// bitwise
|
||||
OP_SHIFT_LEFT,
|
||||
OP_SHIFT_RIGHT,
|
||||
@@ -144,6 +143,7 @@ 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() {}
|
||||
@@ -154,10 +154,18 @@ public:
|
||||
Variant(int64_t v);
|
||||
Variant(int32_t v) :
|
||||
Variant(static_cast<int64_t>(v)) {}
|
||||
Variant(uint32_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(static_cast<int64_t>(v)) {}
|
||||
Variant(double v);
|
||||
Variant(float v) :
|
||||
Variant((double)v) {}
|
||||
@@ -209,8 +217,12 @@ public:
|
||||
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;
|
||||
@@ -255,25 +267,33 @@ public:
|
||||
bool operator!=(const Variant &other) const;
|
||||
bool operator<(const Variant &other) const;
|
||||
|
||||
void call(const StringName &method, const Variant **args, int argcount, Variant &r_ret, GDExtensionCallError &r_error);
|
||||
void callp(const StringName &method, const Variant **args, int argcount, Variant &r_ret, GDExtensionCallError &r_error);
|
||||
|
||||
template <class... Args>
|
||||
template <typename... 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;
|
||||
std::array<GDExtensionConstVariantPtr, sizeof...(Args)> call_args = { Variant(args)... };
|
||||
call(method, call_args.data(), call_args.size(), result, error);
|
||||
callp(method, argptrs.data(), argptrs.size(), result, error);
|
||||
return result;
|
||||
}
|
||||
|
||||
static void call_static(Variant::Type type, const StringName &method, const Variant **args, int argcount, Variant &r_ret, GDExtensionCallError &r_error);
|
||||
static void callp_static(Variant::Type type, const StringName &method, const Variant **args, int argcount, Variant &r_ret, GDExtensionCallError &r_error);
|
||||
|
||||
template <class... Args>
|
||||
template <typename... 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;
|
||||
std::array<GDExtensionConstVariantPtr, sizeof...(Args)> call_args = { Variant(args)... };
|
||||
call_static(type, method, call_args.data(), call_args.size(), result, error);
|
||||
callp_static(type, method, argptrs.data(), argptrs.size(), sizeof...(args), result, error);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
@@ -78,6 +78,14 @@ struct _NO_DISCARD_ 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 max(const Vector3 &p_vector3) const {
|
||||
return Vector3(MAX(x, p_vector3.x), MAX(y, p_vector3.y), MAX(z, p_vector3.z));
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ real_t length() const;
|
||||
_FORCE_INLINE_ real_t length_squared() const;
|
||||
|
||||
|
||||
@@ -71,6 +71,14 @@ struct _NO_DISCARD_ 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 max(const Vector3i &p_vector3i) const {
|
||||
return Vector3i(MAX(x, p_vector3i.x), MAX(y, p_vector3i.y), MAX(z, p_vector3i.z));
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ int64_t length_squared() const;
|
||||
_FORCE_INLINE_ double length() const;
|
||||
|
||||
|
||||
@@ -70,6 +70,14 @@ struct _NO_DISCARD_ Vector4 {
|
||||
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 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));
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ real_t length_squared() const;
|
||||
bool is_equal_approx(const Vector4 &p_vec4) const;
|
||||
bool is_zero_approx() const;
|
||||
|
||||
@@ -73,6 +73,14 @@ struct _NO_DISCARD_ 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 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));
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ int64_t length_squared() const;
|
||||
_FORCE_INLINE_ double length() const;
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**************************************************************************/
|
||||
/* editor_plugin.cpp */
|
||||
/* editor_plugin_registration.cpp */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
@@ -28,9 +28,9 @@
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#include <godot_cpp/classes/editor_plugin.hpp>
|
||||
#include <godot_cpp/classes/editor_plugin_registration.hpp>
|
||||
|
||||
#include <godot_cpp/variant/string_name.hpp>
|
||||
#include <godot_cpp/variant/variant.hpp>
|
||||
|
||||
namespace godot {
|
||||
|
||||
@@ -28,12 +28,16 @@
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include <godot_cpp/classes/wrapped.hpp>
|
||||
|
||||
#include <godot_cpp/variant/builtin_types.hpp>
|
||||
|
||||
#include <godot_cpp/classes/object.hpp>
|
||||
|
||||
#include <godot_cpp/core/class_db.hpp>
|
||||
|
||||
namespace godot {
|
||||
|
||||
const StringName *Wrapped::_get_extension_class_name() const {
|
||||
@@ -46,6 +50,12 @@ void Wrapped::_postinitialize() {
|
||||
godot::internal::gdextension_interface_object_set_instance(_owner, reinterpret_cast<GDExtensionConstStringNamePtr>(extension_class), this);
|
||||
}
|
||||
godot::internal::gdextension_interface_object_set_instance_binding(_owner, godot::internal::token, this, _get_bindings_callbacks());
|
||||
if (extension_class) {
|
||||
Object *obj = dynamic_cast<Object *>(this);
|
||||
if (obj) {
|
||||
obj->notification(Object::NOTIFICATION_POSTINITIALIZE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Wrapped::Wrapped(const StringName p_godot_class) {
|
||||
@@ -60,4 +70,29 @@ void postinitialize_handler(Wrapped *p_wrapped) {
|
||||
p_wrapped->_postinitialize();
|
||||
}
|
||||
|
||||
namespace internal {
|
||||
|
||||
std::vector<EngineClassRegistrationCallback> &get_engine_class_registration_callbacks() {
|
||||
static std::vector<EngineClassRegistrationCallback> engine_class_registration_callbacks;
|
||||
return engine_class_registration_callbacks;
|
||||
}
|
||||
|
||||
void add_engine_class_registration_callback(EngineClassRegistrationCallback p_callback) {
|
||||
get_engine_class_registration_callbacks().push_back(p_callback);
|
||||
}
|
||||
|
||||
void register_engine_class(const StringName &p_name, const GDExtensionInstanceBindingCallbacks *p_callbacks) {
|
||||
ClassDB::_register_engine_class(p_name, p_callbacks);
|
||||
}
|
||||
|
||||
void register_engine_classes() {
|
||||
std::vector<EngineClassRegistrationCallback> &engine_class_registration_callbacks = get_engine_class_registration_callbacks();
|
||||
for (EngineClassRegistrationCallback cb : engine_class_registration_callbacks) {
|
||||
cb();
|
||||
}
|
||||
engine_class_registration_callbacks.clear();
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
|
||||
} // namespace godot
|
||||
|
||||
@@ -77,7 +77,7 @@ void ClassDB::add_property(const StringName &p_class, const PropertyInfo &p_pinf
|
||||
if (p_setter != String("")) {
|
||||
setter = get_method(p_class, p_setter);
|
||||
|
||||
ERR_FAIL_COND_MSG(!setter, String("Setter method '{0}::{1}()' not found for property '{2}::{3}'.").format(Array::make(p_class, p_setter, p_class, p_pinfo.name)));
|
||||
ERR_FAIL_NULL_MSG(setter, String("Setter method '{0}::{1}()' not found for property '{2}::{3}'.").format(Array::make(p_class, p_setter, p_class, p_pinfo.name)));
|
||||
|
||||
size_t exp_args = 1 + (p_index >= 0 ? 1 : 0);
|
||||
ERR_FAIL_COND_MSG((int)exp_args != setter->get_argument_count(), String("Setter method '{0}::{1}()' must take a single argument.").format(Array::make(p_class, p_setter)));
|
||||
@@ -86,7 +86,7 @@ void ClassDB::add_property(const StringName &p_class, const PropertyInfo &p_pinf
|
||||
ERR_FAIL_COND_MSG(p_getter == String(""), String("Getter method must be specified for '{0}::{1}'.").format(Array::make(p_class, p_pinfo.name)));
|
||||
|
||||
MethodBind *getter = get_method(p_class, p_getter);
|
||||
ERR_FAIL_COND_MSG(!getter, String("Getter method '{0}::{1}()' not found for property '{2}::{3}'.").format(Array::make(p_class, p_getter, p_class, p_pinfo.name)));
|
||||
ERR_FAIL_NULL_MSG(getter, String("Getter method '{0}::{1}()' not found for property '{2}::{3}'.").format(Array::make(p_class, p_getter, p_class, p_pinfo.name)));
|
||||
{
|
||||
size_t exp_args = 0 + (p_index >= 0 ? 1 : 0);
|
||||
ERR_FAIL_COND_MSG((int)exp_args != getter->get_argument_count(), String("Getter method '{0}::{1}()' must not take any argument.").format(Array::make(p_class, p_getter)));
|
||||
@@ -318,7 +318,18 @@ GDExtensionClassCallVirtual ClassDB::get_virtual_func(void *p_userdata, GDExtens
|
||||
|
||||
const GDExtensionInstanceBindingCallbacks *ClassDB::get_instance_binding_callbacks(const StringName &p_class) {
|
||||
std::unordered_map<StringName, const GDExtensionInstanceBindingCallbacks *>::iterator callbacks_it = instance_binding_callbacks.find(p_class);
|
||||
ERR_FAIL_COND_V_MSG(callbacks_it == instance_binding_callbacks.end(), nullptr, String("Cannot find instance binding callbacks for class '{0}'.").format(Array::make(p_class)));
|
||||
if (likely(callbacks_it != instance_binding_callbacks.end())) {
|
||||
return callbacks_it->second;
|
||||
}
|
||||
|
||||
// If we don't have an instance binding callback for the given class, find the closest parent where we do.
|
||||
StringName class_name = p_class;
|
||||
do {
|
||||
class_name = get_parent_class(class_name);
|
||||
ERR_FAIL_COND_V_MSG(class_name == StringName(), nullptr, String("Cannot find instance binding callbacks for class '{0}'.").format(Array::make(p_class)));
|
||||
callbacks_it = instance_binding_callbacks.find(class_name);
|
||||
} while (callbacks_it == instance_binding_callbacks.end());
|
||||
|
||||
return callbacks_it->second;
|
||||
}
|
||||
|
||||
|
||||
@@ -41,12 +41,12 @@ void *Memory::alloc_static(size_t p_bytes, bool p_pad_align) {
|
||||
bool prepad = p_pad_align;
|
||||
#endif
|
||||
|
||||
void *mem = internal::gdextension_interface_mem_alloc(p_bytes + (prepad ? PAD_ALIGN : 0));
|
||||
ERR_FAIL_COND_V(!mem, nullptr);
|
||||
void *mem = internal::gdextension_interface_mem_alloc(p_bytes + (prepad ? DATA_OFFSET : 0));
|
||||
ERR_FAIL_NULL_V(mem, nullptr);
|
||||
|
||||
if (prepad) {
|
||||
uint8_t *s8 = (uint8_t *)mem;
|
||||
return s8 + PAD_ALIGN;
|
||||
return s8 + DATA_OFFSET;
|
||||
} else {
|
||||
return mem;
|
||||
}
|
||||
@@ -69,10 +69,10 @@ void *Memory::realloc_static(void *p_memory, size_t p_bytes, bool p_pad_align) {
|
||||
#endif
|
||||
|
||||
if (prepad) {
|
||||
mem -= PAD_ALIGN;
|
||||
mem = (uint8_t *)internal::gdextension_interface_mem_realloc(mem, p_bytes + PAD_ALIGN);
|
||||
ERR_FAIL_COND_V(!mem, nullptr);
|
||||
return mem + PAD_ALIGN;
|
||||
mem -= DATA_OFFSET;
|
||||
mem = (uint8_t *)internal::gdextension_interface_mem_realloc(mem, p_bytes + DATA_OFFSET);
|
||||
ERR_FAIL_NULL_V(mem, nullptr);
|
||||
return mem + DATA_OFFSET;
|
||||
} else {
|
||||
return (uint8_t *)internal::gdextension_interface_mem_realloc(mem, p_bytes);
|
||||
}
|
||||
@@ -88,7 +88,7 @@ void Memory::free_static(void *p_ptr, bool p_pad_align) {
|
||||
#endif
|
||||
|
||||
if (prepad) {
|
||||
mem -= PAD_ALIGN;
|
||||
mem -= DATA_OFFSET;
|
||||
}
|
||||
internal::gdextension_interface_mem_free(mem);
|
||||
}
|
||||
|
||||
154
src/godot.cpp
154
src/godot.cpp
@@ -30,10 +30,11 @@
|
||||
|
||||
#include <godot_cpp/godot.hpp>
|
||||
|
||||
#include <godot_cpp/classes/editor_plugin.hpp>
|
||||
#include <godot_cpp/classes/editor_plugin_registration.hpp>
|
||||
#include <godot_cpp/classes/wrapped.hpp>
|
||||
#include <godot_cpp/core/class_db.hpp>
|
||||
#include <godot_cpp/core/memory.hpp>
|
||||
#include <godot_cpp/core/version.hpp>
|
||||
#include <godot_cpp/variant/variant.hpp>
|
||||
|
||||
#include <godot_cpp/core/error_macros.hpp>
|
||||
@@ -188,13 +189,19 @@ GDExtensionInterfaceEditorRemovePlugin gdextension_interface_editor_remove_plugi
|
||||
|
||||
} // namespace internal
|
||||
|
||||
GDExtensionBinding::Callback GDExtensionBinding::init_callback = nullptr;
|
||||
GDExtensionBinding::Callback GDExtensionBinding::terminate_callback = nullptr;
|
||||
GDExtensionInitializationLevel GDExtensionBinding::minimum_initialization_level = GDEXTENSION_INITIALIZATION_CORE;
|
||||
bool GDExtensionBinding::api_initialized = false;
|
||||
int GDExtensionBinding::level_initialized[MODULE_INITIALIZATION_LEVEL_MAX] = { 0 };
|
||||
GDExtensionBinding::InitDataList GDExtensionBinding::initdata;
|
||||
|
||||
#define LOAD_PROC_ADDRESS(m_name, m_type) \
|
||||
internal::gdextension_interface_##m_name = (m_type)p_get_proc_address(#m_name); \
|
||||
ERR_FAIL_NULL_V_MSG(internal::gdextension_interface_##m_name, false, "Unable to load GDExtension interface function " #m_name "()")
|
||||
#define ERR_PRINT_EARLY(m_msg) \
|
||||
internal::gdextension_interface_print_error(m_msg, FUNCTION_STR, __FILE__, __LINE__, false)
|
||||
|
||||
#define LOAD_PROC_ADDRESS(m_name, m_type) \
|
||||
internal::gdextension_interface_##m_name = (m_type)p_get_proc_address(#m_name); \
|
||||
if (!internal::gdextension_interface_##m_name) { \
|
||||
ERR_PRINT_EARLY("Unable to load GDExtension interface function " #m_name "()"); \
|
||||
return false; \
|
||||
}
|
||||
|
||||
// Partial definition of the legacy interface so we can detect it and show an error.
|
||||
typedef struct {
|
||||
@@ -211,20 +218,34 @@ typedef struct {
|
||||
GDExtensionInterfacePrintErrorWithMessage print_error_with_message;
|
||||
} LegacyGDExtensionInterface;
|
||||
|
||||
GDExtensionBool GDExtensionBinding::init(GDExtensionInterfaceGetProcAddress p_get_proc_address, GDExtensionClassLibraryPtr p_library, GDExtensionInitialization *r_initialization) {
|
||||
GDExtensionBool GDExtensionBinding::init(GDExtensionInterfaceGetProcAddress p_get_proc_address, GDExtensionClassLibraryPtr p_library, InitData *p_init_data, GDExtensionInitialization *r_initialization) {
|
||||
if (!p_init_data || !p_init_data->init_callback) {
|
||||
ERR_FAIL_V_MSG(false, "Initialization callback must be defined.");
|
||||
}
|
||||
|
||||
if (api_initialized) {
|
||||
r_initialization->initialize = initialize_level;
|
||||
r_initialization->deinitialize = deinitialize_level;
|
||||
r_initialization->userdata = p_init_data;
|
||||
r_initialization->minimum_initialization_level = p_init_data->minimum_initialization_level;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Make sure we weren't passed the legacy struct.
|
||||
uint32_t *raw_interface = (uint32_t *)(void *)p_get_proc_address;
|
||||
if (raw_interface[0] == 4 && raw_interface[1] == 0) {
|
||||
// Use the legacy interface only to give a nice error.
|
||||
LegacyGDExtensionInterface *legacy_interface = (LegacyGDExtensionInterface *)p_get_proc_address;
|
||||
internal::gdextension_interface_print_error_with_message = (GDExtensionInterfacePrintErrorWithMessage)legacy_interface->print_error_with_message;
|
||||
ERR_FAIL_V_MSG(false, "Cannot load a GDExtension built for Godot 4.1+ in Godot 4.0.");
|
||||
internal::gdextension_interface_print_error = (GDExtensionInterfacePrintError)legacy_interface->print_error;
|
||||
ERR_PRINT_EARLY("Cannot load a GDExtension built for Godot 4.1+ in Godot 4.0.");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Load the "print_error_with_message" function first (needed by the ERR_FAIL_NULL_V_MSG() macro).
|
||||
internal::gdextension_interface_print_error_with_message = (GDExtensionInterfacePrintErrorWithMessage)p_get_proc_address("print_error_with_message");
|
||||
if (!internal::gdextension_interface_print_error_with_message) {
|
||||
printf("ERROR: Unable to load GDExtension interface function print_error_with_message().\n");
|
||||
// Load the "print_error" function first (needed by the ERR_PRINT_EARLY() macro).
|
||||
internal::gdextension_interface_print_error = (GDExtensionInterfacePrintError)p_get_proc_address("print_error");
|
||||
if (!internal::gdextension_interface_print_error) {
|
||||
printf("ERROR: Unable to load GDExtension interface function print_error().\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -233,10 +254,38 @@ GDExtensionBool GDExtensionBinding::init(GDExtensionInterfaceGetProcAddress p_ge
|
||||
internal::token = p_library;
|
||||
|
||||
LOAD_PROC_ADDRESS(get_godot_version, GDExtensionInterfaceGetGodotVersion);
|
||||
internal::gdextension_interface_get_godot_version(&internal::godot_version);
|
||||
|
||||
// Check that godot-cpp was compiled using an extension_api.json older or at the
|
||||
// same version as the Godot that is loading it.
|
||||
bool compatible;
|
||||
if (internal::godot_version.major != GODOT_VERSION_MAJOR) {
|
||||
compatible = internal::godot_version.major > GODOT_VERSION_MAJOR;
|
||||
} else if (internal::godot_version.minor != GODOT_VERSION_MINOR) {
|
||||
compatible = internal::godot_version.minor > GODOT_VERSION_MINOR;
|
||||
} else {
|
||||
#if GODOT_VERSION_PATCH > 0
|
||||
compatible = internal::godot_version.patch >= GODOT_VERSION_PATCH;
|
||||
#else
|
||||
// Prevent -Wtype-limits warning due to unsigned comparison.
|
||||
compatible = true;
|
||||
#endif
|
||||
}
|
||||
if (!compatible) {
|
||||
// We need to use snprintf() here because vformat() uses Variant, and we haven't loaded
|
||||
// the GDExtension interface far enough to use Variants yet.
|
||||
char msg[128];
|
||||
snprintf(msg, 128, "Cannot load a GDExtension built for Godot %d.%d.%d using an older version of Godot (%d.%d.%d).",
|
||||
GODOT_VERSION_MAJOR, GODOT_VERSION_MINOR, GODOT_VERSION_PATCH,
|
||||
internal::godot_version.major, internal::godot_version.minor, internal::godot_version.patch);
|
||||
ERR_PRINT_EARLY(msg);
|
||||
return false;
|
||||
}
|
||||
|
||||
LOAD_PROC_ADDRESS(mem_alloc, GDExtensionInterfaceMemAlloc);
|
||||
LOAD_PROC_ADDRESS(mem_realloc, GDExtensionInterfaceMemRealloc);
|
||||
LOAD_PROC_ADDRESS(mem_free, GDExtensionInterfaceMemFree);
|
||||
LOAD_PROC_ADDRESS(print_error, GDExtensionInterfacePrintError);
|
||||
LOAD_PROC_ADDRESS(print_error_with_message, GDExtensionInterfacePrintErrorWithMessage);
|
||||
LOAD_PROC_ADDRESS(print_warning, GDExtensionInterfacePrintWarning);
|
||||
LOAD_PROC_ADDRESS(print_warning_with_message, GDExtensionInterfacePrintWarningWithMessage);
|
||||
LOAD_PROC_ADDRESS(print_script_error, GDExtensionInterfacePrintScriptError);
|
||||
@@ -368,63 +417,98 @@ GDExtensionBool GDExtensionBinding::init(GDExtensionInterfaceGetProcAddress p_ge
|
||||
LOAD_PROC_ADDRESS(editor_add_plugin, GDExtensionInterfaceEditorAddPlugin);
|
||||
LOAD_PROC_ADDRESS(editor_remove_plugin, GDExtensionInterfaceEditorRemovePlugin);
|
||||
|
||||
// Load the Godot version.
|
||||
internal::gdextension_interface_get_godot_version(&internal::godot_version);
|
||||
|
||||
r_initialization->initialize = initialize_level;
|
||||
r_initialization->deinitialize = deinitialize_level;
|
||||
r_initialization->minimum_initialization_level = minimum_initialization_level;
|
||||
|
||||
ERR_FAIL_COND_V_MSG(init_callback == nullptr, false, "Initialization callback must be defined.");
|
||||
r_initialization->userdata = p_init_data;
|
||||
r_initialization->minimum_initialization_level = p_init_data->minimum_initialization_level;
|
||||
|
||||
Variant::init_bindings();
|
||||
register_engine_classes();
|
||||
godot::internal::register_engine_classes();
|
||||
|
||||
api_initialized = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
#undef LOAD_PROC_ADDRESS
|
||||
#undef ERR_PRINT_EARLY
|
||||
|
||||
void GDExtensionBinding::initialize_level(void *userdata, GDExtensionInitializationLevel p_level) {
|
||||
void GDExtensionBinding::initialize_level(void *p_userdata, GDExtensionInitializationLevel p_level) {
|
||||
ERR_FAIL_COND(static_cast<ModuleInitializationLevel>(p_level) >= MODULE_INITIALIZATION_LEVEL_MAX);
|
||||
ClassDB::current_level = p_level;
|
||||
|
||||
if (init_callback) {
|
||||
init_callback(static_cast<ModuleInitializationLevel>(p_level));
|
||||
InitData *init_data = static_cast<InitData *>(p_userdata);
|
||||
if (init_data && init_data->init_callback) {
|
||||
init_data->init_callback(static_cast<ModuleInitializationLevel>(p_level));
|
||||
}
|
||||
|
||||
ClassDB::initialize(p_level);
|
||||
if (level_initialized[p_level] == 0) {
|
||||
ClassDB::initialize(p_level);
|
||||
}
|
||||
level_initialized[p_level]++;
|
||||
}
|
||||
|
||||
void GDExtensionBinding::deinitialize_level(void *userdata, GDExtensionInitializationLevel p_level) {
|
||||
void GDExtensionBinding::deinitialize_level(void *p_userdata, GDExtensionInitializationLevel p_level) {
|
||||
ERR_FAIL_COND(static_cast<ModuleInitializationLevel>(p_level) >= MODULE_INITIALIZATION_LEVEL_MAX);
|
||||
ClassDB::current_level = p_level;
|
||||
|
||||
if (terminate_callback) {
|
||||
terminate_callback(static_cast<ModuleInitializationLevel>(p_level));
|
||||
InitData *init_data = static_cast<InitData *>(p_userdata);
|
||||
if (init_data && init_data->terminate_callback) {
|
||||
init_data->terminate_callback(static_cast<ModuleInitializationLevel>(p_level));
|
||||
}
|
||||
|
||||
EditorPlugins::deinitialize(p_level);
|
||||
ClassDB::deinitialize(p_level);
|
||||
level_initialized[p_level]--;
|
||||
if (level_initialized[p_level] == 0) {
|
||||
EditorPlugins::deinitialize(p_level);
|
||||
ClassDB::deinitialize(p_level);
|
||||
}
|
||||
}
|
||||
|
||||
void GDExtensionBinding::InitDataList::add(InitData *p_data) {
|
||||
if (data_count == data_capacity) {
|
||||
void *new_ptr = realloc(data, sizeof(InitData *) * (data_capacity + 32));
|
||||
if (new_ptr) {
|
||||
data = (InitData **)(new_ptr);
|
||||
data_capacity += 32;
|
||||
} else {
|
||||
ERR_FAIL_MSG("Unable to allocate memory for extension callbacks.");
|
||||
}
|
||||
}
|
||||
data[data_count++] = p_data;
|
||||
}
|
||||
|
||||
GDExtensionBinding::InitDataList::~InitDataList() {
|
||||
for (int i = 0; i < data_count; i++) {
|
||||
if (data[i]) {
|
||||
delete data[i];
|
||||
}
|
||||
}
|
||||
if (data) {
|
||||
free(data);
|
||||
}
|
||||
}
|
||||
|
||||
GDExtensionBinding::InitObject::InitObject(GDExtensionInterfaceGetProcAddress p_get_proc_address, GDExtensionClassLibraryPtr p_library, GDExtensionInitialization *r_initialization) {
|
||||
get_proc_address = p_get_proc_address;
|
||||
library = p_library;
|
||||
initialization = r_initialization;
|
||||
init_data = new InitData();
|
||||
GDExtensionBinding::initdata.add(init_data);
|
||||
}
|
||||
|
||||
void GDExtensionBinding::InitObject::register_initializer(Callback p_init) const {
|
||||
GDExtensionBinding::init_callback = p_init;
|
||||
init_data->init_callback = p_init;
|
||||
}
|
||||
|
||||
void GDExtensionBinding::InitObject::register_terminator(Callback p_terminate) const {
|
||||
GDExtensionBinding::terminate_callback = p_terminate;
|
||||
init_data->terminate_callback = p_terminate;
|
||||
}
|
||||
|
||||
void GDExtensionBinding::InitObject::set_minimum_library_initialization_level(ModuleInitializationLevel p_level) const {
|
||||
GDExtensionBinding::minimum_initialization_level = static_cast<GDExtensionInitializationLevel>(p_level);
|
||||
init_data->minimum_initialization_level = static_cast<GDExtensionInitializationLevel>(p_level);
|
||||
}
|
||||
|
||||
GDExtensionBool GDExtensionBinding::InitObject::init() const {
|
||||
return GDExtensionBinding::init(get_proc_address, library, initialization);
|
||||
return GDExtensionBinding::init(get_proc_address, library, init_data, initialization);
|
||||
}
|
||||
|
||||
} // namespace godot
|
||||
|
||||
@@ -38,117 +38,121 @@
|
||||
#include <godot_cpp/godot.hpp>
|
||||
|
||||
#include <cmath>
|
||||
#include <string>
|
||||
|
||||
namespace godot {
|
||||
|
||||
int CharString::length() const {
|
||||
return _length;
|
||||
}
|
||||
template <typename L, typename R>
|
||||
_FORCE_INLINE_ bool is_str_less(const L *l_ptr, const R *r_ptr) {
|
||||
while (true) {
|
||||
const char32_t l = *l_ptr;
|
||||
const char32_t r = *r_ptr;
|
||||
|
||||
const char *CharString::get_data() const {
|
||||
return _data;
|
||||
}
|
||||
if (l == 0 && r == 0) {
|
||||
return false;
|
||||
} else if (l == 0) {
|
||||
return true;
|
||||
} else if (r == 0) {
|
||||
return false;
|
||||
} else if (l < r) {
|
||||
return true;
|
||||
} else if (l > r) {
|
||||
return false;
|
||||
}
|
||||
|
||||
CharString::CharString(CharString &&p_str) {
|
||||
SWAP(_length, p_str._length);
|
||||
SWAP(_data, p_str._data);
|
||||
}
|
||||
|
||||
void CharString::operator=(CharString &&p_str) {
|
||||
SWAP(_length, p_str._length);
|
||||
SWAP(_data, p_str._data);
|
||||
}
|
||||
|
||||
CharString::CharString(const char *str, int length) :
|
||||
_data(str), _length(length) {}
|
||||
|
||||
CharString::~CharString() {
|
||||
if (_data != nullptr) {
|
||||
memdelete_arr(_data);
|
||||
l_ptr++;
|
||||
r_ptr++;
|
||||
}
|
||||
}
|
||||
|
||||
int Char16String::length() const {
|
||||
return _length;
|
||||
template <typename T>
|
||||
bool CharStringT<T>::operator<(const CharStringT<T> &p_right) const {
|
||||
if (length() == 0) {
|
||||
return p_right.length() != 0;
|
||||
}
|
||||
|
||||
return is_str_less(get_data(), p_right.get_data());
|
||||
}
|
||||
|
||||
const char16_t *Char16String::get_data() const {
|
||||
return _data;
|
||||
template <typename T>
|
||||
CharStringT<T> &CharStringT<T>::operator+=(T p_char) {
|
||||
const int64_t lhs_len = length();
|
||||
resize(lhs_len + 2);
|
||||
|
||||
T *dst = ptrw();
|
||||
dst[lhs_len] = p_char;
|
||||
dst[lhs_len + 1] = 0;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
Char16String::Char16String(Char16String &&p_str) {
|
||||
SWAP(_length, p_str._length);
|
||||
SWAP(_data, p_str._data);
|
||||
template <typename T>
|
||||
void CharStringT<T>::operator=(const T *p_cstr) {
|
||||
copy_from(p_cstr);
|
||||
}
|
||||
|
||||
void Char16String::operator=(Char16String &&p_str) {
|
||||
SWAP(_length, p_str._length);
|
||||
SWAP(_data, p_str._data);
|
||||
}
|
||||
|
||||
Char16String::Char16String(const char16_t *str, int length) :
|
||||
_data(str), _length(length) {}
|
||||
|
||||
Char16String::~Char16String() {
|
||||
if (_data != nullptr) {
|
||||
memdelete_arr(_data);
|
||||
template <>
|
||||
const char *CharStringT<char>::get_data() const {
|
||||
if (size()) {
|
||||
return &operator[](0);
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
int Char32String::length() const {
|
||||
return _length;
|
||||
}
|
||||
|
||||
const char32_t *Char32String::get_data() const {
|
||||
return _data;
|
||||
}
|
||||
|
||||
Char32String::Char32String(Char32String &&p_str) {
|
||||
SWAP(_length, p_str._length);
|
||||
SWAP(_data, p_str._data);
|
||||
}
|
||||
|
||||
void Char32String::operator=(Char32String &&p_str) {
|
||||
SWAP(_length, p_str._length);
|
||||
SWAP(_data, p_str._data);
|
||||
}
|
||||
|
||||
Char32String::Char32String(const char32_t *str, int length) :
|
||||
_data(str), _length(length) {}
|
||||
|
||||
Char32String::~Char32String() {
|
||||
if (_data != nullptr) {
|
||||
memdelete_arr(_data);
|
||||
template <>
|
||||
const char16_t *CharStringT<char16_t>::get_data() const {
|
||||
if (size()) {
|
||||
return &operator[](0);
|
||||
} else {
|
||||
return u"";
|
||||
}
|
||||
}
|
||||
|
||||
int CharWideString::length() const {
|
||||
return _length;
|
||||
}
|
||||
|
||||
const wchar_t *CharWideString::get_data() const {
|
||||
return _data;
|
||||
}
|
||||
|
||||
CharWideString::CharWideString(CharWideString &&p_str) {
|
||||
SWAP(_length, p_str._length);
|
||||
SWAP(_data, p_str._data);
|
||||
}
|
||||
|
||||
void CharWideString::operator=(CharWideString &&p_str) {
|
||||
SWAP(_length, p_str._length);
|
||||
SWAP(_data, p_str._data);
|
||||
}
|
||||
|
||||
CharWideString::CharWideString(const wchar_t *str, int length) :
|
||||
_data(str), _length(length) {}
|
||||
|
||||
CharWideString::~CharWideString() {
|
||||
if (_data != nullptr) {
|
||||
memdelete_arr(_data);
|
||||
template <>
|
||||
const char32_t *CharStringT<char32_t>::get_data() const {
|
||||
if (size()) {
|
||||
return &operator[](0);
|
||||
} else {
|
||||
return U"";
|
||||
}
|
||||
}
|
||||
|
||||
template <>
|
||||
const wchar_t *CharStringT<wchar_t>::get_data() const {
|
||||
if (size()) {
|
||||
return &operator[](0);
|
||||
} else {
|
||||
return L"";
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void CharStringT<T>::copy_from(const T *p_cstr) {
|
||||
if (!p_cstr) {
|
||||
resize(0);
|
||||
return;
|
||||
}
|
||||
|
||||
size_t len = std::char_traits<T>::length(p_cstr);
|
||||
|
||||
if (len == 0) {
|
||||
resize(0);
|
||||
return;
|
||||
}
|
||||
|
||||
Error err = resize(++len); // include terminating null char
|
||||
|
||||
ERR_FAIL_COND_MSG(err != OK, "Failed to copy C-string.");
|
||||
|
||||
memcpy(ptrw(), p_cstr, len);
|
||||
}
|
||||
|
||||
template class CharStringT<char>;
|
||||
template class CharStringT<char16_t>;
|
||||
template class CharStringT<char32_t>;
|
||||
template class CharStringT<wchar_t>;
|
||||
|
||||
// Custom String functions that are not part of bound API.
|
||||
// It's easier to have them written in C++ directly than in a Python script that generates them.
|
||||
|
||||
@@ -168,23 +172,23 @@ String::String(const char32_t *from) {
|
||||
internal::gdextension_interface_string_new_with_utf32_chars(_native_ptr(), from);
|
||||
}
|
||||
|
||||
String String::utf8(const char *from, int len) {
|
||||
String String::utf8(const char *from, int64_t len) {
|
||||
String ret;
|
||||
ret.parse_utf8(from, len);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void String::parse_utf8(const char *from, int len) {
|
||||
void String::parse_utf8(const char *from, int64_t len) {
|
||||
internal::gdextension_interface_string_new_with_utf8_chars_and_len(_native_ptr(), from, len);
|
||||
}
|
||||
|
||||
String String::utf16(const char16_t *from, int len) {
|
||||
String String::utf16(const char16_t *from, int64_t len) {
|
||||
String ret;
|
||||
ret.parse_utf16(from, len);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void String::parse_utf16(const char16_t *from, int len) {
|
||||
void String::parse_utf16(const char16_t *from, int64_t len) {
|
||||
internal::gdextension_interface_string_new_with_utf16_chars_and_len(_native_ptr(), from, len);
|
||||
}
|
||||
|
||||
@@ -226,58 +230,63 @@ String rtoss(double p_val) {
|
||||
}
|
||||
|
||||
CharString String::utf8() const {
|
||||
int length = internal::gdextension_interface_string_to_utf8_chars(_native_ptr(), nullptr, 0);
|
||||
int size = length + 1;
|
||||
char *cstr = memnew_arr(char, size);
|
||||
internal::gdextension_interface_string_to_utf8_chars(_native_ptr(), cstr, length);
|
||||
int64_t length = internal::gdextension_interface_string_to_utf8_chars(_native_ptr(), nullptr, 0);
|
||||
int64_t size = length + 1;
|
||||
CharString str;
|
||||
str.resize(size);
|
||||
internal::gdextension_interface_string_to_utf8_chars(_native_ptr(), str.ptrw(), length);
|
||||
|
||||
cstr[length] = '\0';
|
||||
str[length] = '\0';
|
||||
|
||||
return CharString(cstr, length);
|
||||
return str;
|
||||
}
|
||||
|
||||
CharString String::ascii() const {
|
||||
int length = internal::gdextension_interface_string_to_latin1_chars(_native_ptr(), nullptr, 0);
|
||||
int size = length + 1;
|
||||
char *cstr = memnew_arr(char, size);
|
||||
internal::gdextension_interface_string_to_latin1_chars(_native_ptr(), cstr, length);
|
||||
int64_t length = internal::gdextension_interface_string_to_latin1_chars(_native_ptr(), nullptr, 0);
|
||||
int64_t size = length + 1;
|
||||
CharString str;
|
||||
str.resize(size);
|
||||
internal::gdextension_interface_string_to_latin1_chars(_native_ptr(), str.ptrw(), length);
|
||||
|
||||
cstr[length] = '\0';
|
||||
str[length] = '\0';
|
||||
|
||||
return CharString(cstr, length);
|
||||
return str;
|
||||
}
|
||||
|
||||
Char16String String::utf16() const {
|
||||
int length = internal::gdextension_interface_string_to_utf16_chars(_native_ptr(), nullptr, 0);
|
||||
int size = length + 1;
|
||||
char16_t *cstr = memnew_arr(char16_t, size);
|
||||
internal::gdextension_interface_string_to_utf16_chars(_native_ptr(), cstr, length);
|
||||
int64_t length = internal::gdextension_interface_string_to_utf16_chars(_native_ptr(), nullptr, 0);
|
||||
int64_t size = length + 1;
|
||||
Char16String str;
|
||||
str.resize(size);
|
||||
internal::gdextension_interface_string_to_utf16_chars(_native_ptr(), str.ptrw(), length);
|
||||
|
||||
cstr[length] = '\0';
|
||||
str[length] = '\0';
|
||||
|
||||
return Char16String(cstr, length);
|
||||
return str;
|
||||
}
|
||||
|
||||
Char32String String::utf32() const {
|
||||
int length = internal::gdextension_interface_string_to_utf32_chars(_native_ptr(), nullptr, 0);
|
||||
int size = length + 1;
|
||||
char32_t *cstr = memnew_arr(char32_t, size);
|
||||
internal::gdextension_interface_string_to_utf32_chars(_native_ptr(), cstr, length);
|
||||
int64_t length = internal::gdextension_interface_string_to_utf32_chars(_native_ptr(), nullptr, 0);
|
||||
int64_t size = length + 1;
|
||||
Char32String str;
|
||||
str.resize(size);
|
||||
internal::gdextension_interface_string_to_utf32_chars(_native_ptr(), str.ptrw(), length);
|
||||
|
||||
cstr[length] = '\0';
|
||||
str[length] = '\0';
|
||||
|
||||
return Char32String(cstr, length);
|
||||
return str;
|
||||
}
|
||||
|
||||
CharWideString String::wide_string() const {
|
||||
int length = internal::gdextension_interface_string_to_wide_chars(_native_ptr(), nullptr, 0);
|
||||
int size = length + 1;
|
||||
wchar_t *cstr = memnew_arr(wchar_t, size);
|
||||
internal::gdextension_interface_string_to_wide_chars(_native_ptr(), cstr, length);
|
||||
int64_t length = internal::gdextension_interface_string_to_wide_chars(_native_ptr(), nullptr, 0);
|
||||
int64_t size = length + 1;
|
||||
CharWideString str;
|
||||
str.resize(size);
|
||||
internal::gdextension_interface_string_to_wide_chars(_native_ptr(), str.ptrw(), length);
|
||||
|
||||
cstr[length] = '\0';
|
||||
str[length] = '\0';
|
||||
|
||||
return CharWideString(cstr, length);
|
||||
return str;
|
||||
}
|
||||
|
||||
String &String::operator=(const char *p_str) {
|
||||
@@ -377,11 +386,11 @@ String &String::operator+=(const char32_t *p_str) {
|
||||
return *this;
|
||||
}
|
||||
|
||||
const char32_t &String::operator[](int p_index) const {
|
||||
const char32_t &String::operator[](int64_t p_index) const {
|
||||
return *internal::gdextension_interface_string_operator_index_const((GDExtensionStringPtr)this, p_index);
|
||||
}
|
||||
|
||||
char32_t &String::operator[](int p_index) {
|
||||
char32_t &String::operator[](int64_t p_index) {
|
||||
return *internal::gdextension_interface_string_operator_index((GDExtensionStringPtr)this, p_index);
|
||||
}
|
||||
|
||||
|
||||
@@ -46,11 +46,11 @@
|
||||
|
||||
namespace godot {
|
||||
|
||||
const uint8_t &PackedByteArray::operator[](int p_index) const {
|
||||
const uint8_t &PackedByteArray::operator[](int64_t p_index) const {
|
||||
return *internal::gdextension_interface_packed_byte_array_operator_index_const((GDExtensionTypePtr *)this, p_index);
|
||||
}
|
||||
|
||||
uint8_t &PackedByteArray::operator[](int p_index) {
|
||||
uint8_t &PackedByteArray::operator[](int64_t p_index) {
|
||||
return *internal::gdextension_interface_packed_byte_array_operator_index((GDExtensionTypePtr *)this, p_index);
|
||||
}
|
||||
|
||||
@@ -62,12 +62,12 @@ uint8_t *PackedByteArray::ptrw() {
|
||||
return internal::gdextension_interface_packed_byte_array_operator_index((GDExtensionTypePtr *)this, 0);
|
||||
}
|
||||
|
||||
const Color &PackedColorArray::operator[](int p_index) const {
|
||||
const Color &PackedColorArray::operator[](int64_t p_index) const {
|
||||
const Color *color = (const Color *)internal::gdextension_interface_packed_color_array_operator_index_const((GDExtensionTypePtr *)this, p_index);
|
||||
return *color;
|
||||
}
|
||||
|
||||
Color &PackedColorArray::operator[](int p_index) {
|
||||
Color &PackedColorArray::operator[](int64_t p_index) {
|
||||
Color *color = (Color *)internal::gdextension_interface_packed_color_array_operator_index((GDExtensionTypePtr *)this, p_index);
|
||||
return *color;
|
||||
}
|
||||
@@ -80,11 +80,11 @@ Color *PackedColorArray::ptrw() {
|
||||
return (Color *)internal::gdextension_interface_packed_color_array_operator_index((GDExtensionTypePtr *)this, 0);
|
||||
}
|
||||
|
||||
const float &PackedFloat32Array::operator[](int p_index) const {
|
||||
const float &PackedFloat32Array::operator[](int64_t p_index) const {
|
||||
return *internal::gdextension_interface_packed_float32_array_operator_index_const((GDExtensionTypePtr *)this, p_index);
|
||||
}
|
||||
|
||||
float &PackedFloat32Array::operator[](int p_index) {
|
||||
float &PackedFloat32Array::operator[](int64_t p_index) {
|
||||
return *internal::gdextension_interface_packed_float32_array_operator_index((GDExtensionTypePtr *)this, p_index);
|
||||
}
|
||||
|
||||
@@ -96,11 +96,11 @@ float *PackedFloat32Array::ptrw() {
|
||||
return internal::gdextension_interface_packed_float32_array_operator_index((GDExtensionTypePtr *)this, 0);
|
||||
}
|
||||
|
||||
const double &PackedFloat64Array::operator[](int p_index) const {
|
||||
const double &PackedFloat64Array::operator[](int64_t p_index) const {
|
||||
return *internal::gdextension_interface_packed_float64_array_operator_index_const((GDExtensionTypePtr *)this, p_index);
|
||||
}
|
||||
|
||||
double &PackedFloat64Array::operator[](int p_index) {
|
||||
double &PackedFloat64Array::operator[](int64_t p_index) {
|
||||
return *internal::gdextension_interface_packed_float64_array_operator_index((GDExtensionTypePtr *)this, p_index);
|
||||
}
|
||||
|
||||
@@ -112,11 +112,11 @@ double *PackedFloat64Array::ptrw() {
|
||||
return internal::gdextension_interface_packed_float64_array_operator_index((GDExtensionTypePtr *)this, 0);
|
||||
}
|
||||
|
||||
const int32_t &PackedInt32Array::operator[](int p_index) const {
|
||||
const int32_t &PackedInt32Array::operator[](int64_t p_index) const {
|
||||
return *internal::gdextension_interface_packed_int32_array_operator_index_const((GDExtensionTypePtr *)this, p_index);
|
||||
}
|
||||
|
||||
int32_t &PackedInt32Array::operator[](int p_index) {
|
||||
int32_t &PackedInt32Array::operator[](int64_t p_index) {
|
||||
return *internal::gdextension_interface_packed_int32_array_operator_index((GDExtensionTypePtr *)this, p_index);
|
||||
}
|
||||
|
||||
@@ -128,11 +128,11 @@ int32_t *PackedInt32Array::ptrw() {
|
||||
return internal::gdextension_interface_packed_int32_array_operator_index((GDExtensionTypePtr *)this, 0);
|
||||
}
|
||||
|
||||
const int64_t &PackedInt64Array::operator[](int p_index) const {
|
||||
const int64_t &PackedInt64Array::operator[](int64_t p_index) const {
|
||||
return *internal::gdextension_interface_packed_int64_array_operator_index_const((GDExtensionTypePtr *)this, p_index);
|
||||
}
|
||||
|
||||
int64_t &PackedInt64Array::operator[](int p_index) {
|
||||
int64_t &PackedInt64Array::operator[](int64_t p_index) {
|
||||
return *internal::gdextension_interface_packed_int64_array_operator_index((GDExtensionTypePtr *)this, p_index);
|
||||
}
|
||||
|
||||
@@ -144,12 +144,12 @@ int64_t *PackedInt64Array::ptrw() {
|
||||
return internal::gdextension_interface_packed_int64_array_operator_index((GDExtensionTypePtr *)this, 0);
|
||||
}
|
||||
|
||||
const String &PackedStringArray::operator[](int p_index) const {
|
||||
const String &PackedStringArray::operator[](int64_t p_index) const {
|
||||
const String *string = (const String *)internal::gdextension_interface_packed_string_array_operator_index_const((GDExtensionTypePtr *)this, p_index);
|
||||
return *string;
|
||||
}
|
||||
|
||||
String &PackedStringArray::operator[](int p_index) {
|
||||
String &PackedStringArray::operator[](int64_t p_index) {
|
||||
String *string = (String *)internal::gdextension_interface_packed_string_array_operator_index((GDExtensionTypePtr *)this, p_index);
|
||||
return *string;
|
||||
}
|
||||
@@ -162,12 +162,12 @@ String *PackedStringArray::ptrw() {
|
||||
return (String *)internal::gdextension_interface_packed_string_array_operator_index((GDExtensionTypePtr *)this, 0);
|
||||
}
|
||||
|
||||
const Vector2 &PackedVector2Array::operator[](int p_index) const {
|
||||
const Vector2 &PackedVector2Array::operator[](int64_t p_index) const {
|
||||
const Vector2 *vec = (const Vector2 *)internal::gdextension_interface_packed_vector2_array_operator_index_const((GDExtensionTypePtr *)this, p_index);
|
||||
return *vec;
|
||||
}
|
||||
|
||||
Vector2 &PackedVector2Array::operator[](int p_index) {
|
||||
Vector2 &PackedVector2Array::operator[](int64_t p_index) {
|
||||
Vector2 *vec = (Vector2 *)internal::gdextension_interface_packed_vector2_array_operator_index((GDExtensionTypePtr *)this, p_index);
|
||||
return *vec;
|
||||
}
|
||||
@@ -180,12 +180,12 @@ Vector2 *PackedVector2Array::ptrw() {
|
||||
return (Vector2 *)internal::gdextension_interface_packed_vector2_array_operator_index((GDExtensionTypePtr *)this, 0);
|
||||
}
|
||||
|
||||
const Vector3 &PackedVector3Array::operator[](int p_index) const {
|
||||
const Vector3 &PackedVector3Array::operator[](int64_t p_index) const {
|
||||
const Vector3 *vec = (const Vector3 *)internal::gdextension_interface_packed_vector3_array_operator_index_const((GDExtensionTypePtr *)this, p_index);
|
||||
return *vec;
|
||||
}
|
||||
|
||||
Vector3 &PackedVector3Array::operator[](int p_index) {
|
||||
Vector3 &PackedVector3Array::operator[](int64_t p_index) {
|
||||
Vector3 *vec = (Vector3 *)internal::gdextension_interface_packed_vector3_array_operator_index((GDExtensionTypePtr *)this, p_index);
|
||||
return *vec;
|
||||
}
|
||||
@@ -198,12 +198,12 @@ Vector3 *PackedVector3Array::ptrw() {
|
||||
return (Vector3 *)internal::gdextension_interface_packed_vector3_array_operator_index((GDExtensionTypePtr *)this, 0);
|
||||
}
|
||||
|
||||
const Variant &Array::operator[](int p_index) const {
|
||||
const Variant &Array::operator[](int64_t p_index) const {
|
||||
const Variant *var = (const Variant *)internal::gdextension_interface_array_operator_index_const((GDExtensionTypePtr *)this, p_index);
|
||||
return *var;
|
||||
}
|
||||
|
||||
Variant &Array::operator[](int p_index) {
|
||||
Variant &Array::operator[](int64_t p_index) {
|
||||
Variant *var = (Variant *)internal::gdextension_interface_array_operator_index((GDExtensionTypePtr *)this, p_index);
|
||||
return *var;
|
||||
}
|
||||
|
||||
@@ -136,7 +136,7 @@ Projection Projection::create_for_hmd(int p_eye, real_t p_aspect, real_t p_intra
|
||||
|
||||
Projection Projection::create_orthogonal(real_t p_left, real_t p_right, real_t p_bottom, real_t p_top, real_t p_znear, real_t p_zfar) {
|
||||
Projection proj;
|
||||
proj.set_orthogonal(p_left, p_right, p_bottom, p_top, p_zfar, p_zfar);
|
||||
proj.set_orthogonal(p_left, p_right, p_bottom, p_top, p_znear, p_zfar);
|
||||
return proj;
|
||||
}
|
||||
|
||||
|
||||
@@ -268,6 +268,14 @@ Variant::operator int32_t() const {
|
||||
return static_cast<int32_t>(operator int64_t());
|
||||
}
|
||||
|
||||
Variant::operator int16_t() const {
|
||||
return static_cast<int16_t>(operator int64_t());
|
||||
}
|
||||
|
||||
Variant::operator int8_t() const {
|
||||
return static_cast<int8_t>(operator int64_t());
|
||||
}
|
||||
|
||||
Variant::operator uint64_t() const {
|
||||
return static_cast<uint64_t>(operator int64_t());
|
||||
}
|
||||
@@ -276,6 +284,14 @@ Variant::operator uint32_t() const {
|
||||
return static_cast<uint32_t>(operator int64_t());
|
||||
}
|
||||
|
||||
Variant::operator uint16_t() const {
|
||||
return static_cast<uint16_t>(operator int64_t());
|
||||
}
|
||||
|
||||
Variant::operator uint8_t() const {
|
||||
return static_cast<uint8_t>(operator int64_t());
|
||||
}
|
||||
|
||||
Variant::operator double() const {
|
||||
double result;
|
||||
to_type_constructor[FLOAT](&result, _native_ptr());
|
||||
@@ -287,123 +303,131 @@ Variant::operator float() const {
|
||||
}
|
||||
|
||||
Variant::operator String() const {
|
||||
String result;
|
||||
to_type_constructor[STRING](result._native_ptr(), _native_ptr());
|
||||
return result;
|
||||
return String(this);
|
||||
}
|
||||
|
||||
Variant::operator Vector2() const {
|
||||
// @todo Avoid initializing result before calling constructor (which will initialize it again)
|
||||
Vector2 result;
|
||||
to_type_constructor[VECTOR2]((GDExtensionTypePtr)&result, _native_ptr());
|
||||
return result;
|
||||
}
|
||||
|
||||
Variant::operator Vector2i() const {
|
||||
// @todo Avoid initializing result before calling constructor (which will initialize it again)
|
||||
Vector2i result;
|
||||
to_type_constructor[VECTOR2I]((GDExtensionTypePtr)&result, _native_ptr());
|
||||
return result;
|
||||
}
|
||||
|
||||
Variant::operator Rect2() const {
|
||||
// @todo Avoid initializing result before calling constructor (which will initialize it again)
|
||||
Rect2 result;
|
||||
to_type_constructor[RECT2]((GDExtensionTypePtr)&result, _native_ptr());
|
||||
return result;
|
||||
}
|
||||
|
||||
Variant::operator Rect2i() const {
|
||||
// @todo Avoid initializing result before calling constructor (which will initialize it again)
|
||||
Rect2i result;
|
||||
to_type_constructor[RECT2I]((GDExtensionTypePtr)&result, _native_ptr());
|
||||
return result;
|
||||
}
|
||||
|
||||
Variant::operator Vector3() const {
|
||||
// @todo Avoid initializing result before calling constructor (which will initialize it again)
|
||||
Vector3 result;
|
||||
to_type_constructor[VECTOR3]((GDExtensionTypePtr)&result, _native_ptr());
|
||||
return result;
|
||||
}
|
||||
|
||||
Variant::operator Vector3i() const {
|
||||
// @todo Avoid initializing result before calling constructor (which will initialize it again)
|
||||
Vector3i result;
|
||||
to_type_constructor[VECTOR3I]((GDExtensionTypePtr)&result, _native_ptr());
|
||||
return result;
|
||||
}
|
||||
|
||||
Variant::operator Transform2D() const {
|
||||
// @todo Avoid initializing result before calling constructor (which will initialize it again)
|
||||
Transform2D result;
|
||||
to_type_constructor[TRANSFORM2D]((GDExtensionTypePtr)&result, _native_ptr());
|
||||
return result;
|
||||
}
|
||||
|
||||
Variant::operator Vector4() const {
|
||||
// @todo Avoid initializing result before calling constructor (which will initialize it again)
|
||||
Vector4 result;
|
||||
to_type_constructor[VECTOR4]((GDExtensionTypePtr)&result, _native_ptr());
|
||||
return result;
|
||||
}
|
||||
|
||||
Variant::operator Vector4i() const {
|
||||
// @todo Avoid initializing result before calling constructor (which will initialize it again)
|
||||
Vector4i result;
|
||||
to_type_constructor[VECTOR4I]((GDExtensionTypePtr)&result, _native_ptr());
|
||||
return result;
|
||||
}
|
||||
|
||||
Variant::operator Plane() const {
|
||||
// @todo Avoid initializing result before calling constructor (which will initialize it again)
|
||||
Plane result;
|
||||
to_type_constructor[PLANE]((GDExtensionTypePtr)&result, _native_ptr());
|
||||
return result;
|
||||
}
|
||||
|
||||
Variant::operator Quaternion() const {
|
||||
// @todo Avoid initializing result before calling constructor (which will initialize it again)
|
||||
Quaternion result;
|
||||
to_type_constructor[QUATERNION]((GDExtensionTypePtr)&result, _native_ptr());
|
||||
return result;
|
||||
}
|
||||
|
||||
Variant::operator godot::AABB() const {
|
||||
// @todo Avoid initializing result before calling constructor (which will initialize it again)
|
||||
godot::AABB result;
|
||||
to_type_constructor[AABB]((GDExtensionTypePtr)&result, _native_ptr());
|
||||
return result;
|
||||
}
|
||||
|
||||
Variant::operator Basis() const {
|
||||
// @todo Avoid initializing result before calling constructor (which will initialize it again)
|
||||
Basis result;
|
||||
to_type_constructor[BASIS]((GDExtensionTypePtr)&result, _native_ptr());
|
||||
return result;
|
||||
}
|
||||
|
||||
Variant::operator Transform3D() const {
|
||||
// @todo Avoid initializing result before calling constructor (which will initialize it again)
|
||||
Transform3D result;
|
||||
to_type_constructor[TRANSFORM3D]((GDExtensionTypePtr)&result, _native_ptr());
|
||||
return result;
|
||||
}
|
||||
|
||||
Variant::operator Projection() const {
|
||||
// @todo Avoid initializing result before calling constructor (which will initialize it again)
|
||||
Projection result;
|
||||
to_type_constructor[PROJECTION]((GDExtensionTypePtr)&result, _native_ptr());
|
||||
return result;
|
||||
}
|
||||
|
||||
Variant::operator Color() const {
|
||||
// @todo Avoid initializing result before calling constructor (which will initialize it again)
|
||||
Color result;
|
||||
to_type_constructor[COLOR]((GDExtensionTypePtr)&result, _native_ptr());
|
||||
return result;
|
||||
}
|
||||
|
||||
Variant::operator StringName() const {
|
||||
StringName result;
|
||||
to_type_constructor[STRING_NAME](result._native_ptr(), _native_ptr());
|
||||
return result;
|
||||
return StringName(this);
|
||||
}
|
||||
|
||||
Variant::operator NodePath() const {
|
||||
NodePath result;
|
||||
to_type_constructor[NODE_PATH](result._native_ptr(), _native_ptr());
|
||||
return result;
|
||||
return NodePath(this);
|
||||
}
|
||||
|
||||
Variant::operator godot::RID() const {
|
||||
godot::RID result;
|
||||
to_type_constructor[RID](result._native_ptr(), _native_ptr());
|
||||
return result;
|
||||
return godot::RID(this);
|
||||
}
|
||||
|
||||
Variant::operator Object *() const {
|
||||
@@ -431,81 +455,55 @@ Variant::operator ObjectID() const {
|
||||
}
|
||||
|
||||
Variant::operator Callable() const {
|
||||
Callable result;
|
||||
to_type_constructor[CALLABLE](result._native_ptr(), _native_ptr());
|
||||
return result;
|
||||
return Callable(this);
|
||||
}
|
||||
|
||||
Variant::operator Signal() const {
|
||||
Signal result;
|
||||
to_type_constructor[SIGNAL](result._native_ptr(), _native_ptr());
|
||||
return result;
|
||||
return Signal(this);
|
||||
}
|
||||
|
||||
Variant::operator Dictionary() const {
|
||||
Dictionary result;
|
||||
to_type_constructor[DICTIONARY](result._native_ptr(), _native_ptr());
|
||||
return result;
|
||||
return Dictionary(this);
|
||||
}
|
||||
|
||||
Variant::operator Array() const {
|
||||
Array result;
|
||||
to_type_constructor[ARRAY](result._native_ptr(), _native_ptr());
|
||||
return result;
|
||||
return Array(this);
|
||||
}
|
||||
|
||||
Variant::operator PackedByteArray() const {
|
||||
PackedByteArray result;
|
||||
to_type_constructor[PACKED_BYTE_ARRAY](result._native_ptr(), _native_ptr());
|
||||
return result;
|
||||
return PackedByteArray(this);
|
||||
}
|
||||
|
||||
Variant::operator PackedInt32Array() const {
|
||||
PackedInt32Array result;
|
||||
to_type_constructor[PACKED_INT32_ARRAY](result._native_ptr(), _native_ptr());
|
||||
return result;
|
||||
return PackedInt32Array(this);
|
||||
}
|
||||
|
||||
Variant::operator PackedInt64Array() const {
|
||||
PackedInt64Array result;
|
||||
to_type_constructor[PACKED_INT64_ARRAY](result._native_ptr(), _native_ptr());
|
||||
return result;
|
||||
return PackedInt64Array(this);
|
||||
}
|
||||
|
||||
Variant::operator PackedFloat32Array() const {
|
||||
PackedFloat32Array result;
|
||||
to_type_constructor[PACKED_FLOAT32_ARRAY](result._native_ptr(), _native_ptr());
|
||||
return result;
|
||||
return PackedFloat32Array(this);
|
||||
}
|
||||
|
||||
Variant::operator PackedFloat64Array() const {
|
||||
PackedFloat64Array result;
|
||||
to_type_constructor[PACKED_FLOAT64_ARRAY](result._native_ptr(), _native_ptr());
|
||||
return result;
|
||||
return PackedFloat64Array(this);
|
||||
}
|
||||
|
||||
Variant::operator PackedStringArray() const {
|
||||
PackedStringArray result;
|
||||
to_type_constructor[PACKED_STRING_ARRAY](result._native_ptr(), _native_ptr());
|
||||
return result;
|
||||
return PackedStringArray(this);
|
||||
}
|
||||
|
||||
Variant::operator PackedVector2Array() const {
|
||||
PackedVector2Array result;
|
||||
to_type_constructor[PACKED_VECTOR2_ARRAY](result._native_ptr(), _native_ptr());
|
||||
return result;
|
||||
return PackedVector2Array(this);
|
||||
}
|
||||
|
||||
Variant::operator PackedVector3Array() const {
|
||||
PackedVector3Array result;
|
||||
to_type_constructor[PACKED_VECTOR3_ARRAY](result._native_ptr(), _native_ptr());
|
||||
return result;
|
||||
return PackedVector3Array(this);
|
||||
}
|
||||
|
||||
Variant::operator PackedColorArray() const {
|
||||
PackedColorArray result;
|
||||
to_type_constructor[PACKED_COLOR_ARRAY](result._native_ptr(), _native_ptr());
|
||||
return result;
|
||||
return PackedColorArray(this);
|
||||
}
|
||||
|
||||
Variant &Variant::operator=(const Variant &other) {
|
||||
@@ -549,11 +547,11 @@ bool Variant::operator<(const Variant &other) const {
|
||||
return result.operator bool();
|
||||
}
|
||||
|
||||
void Variant::call(const StringName &method, const Variant **args, int argcount, Variant &r_ret, GDExtensionCallError &r_error) {
|
||||
void Variant::callp(const StringName &method, const Variant **args, int argcount, Variant &r_ret, GDExtensionCallError &r_error) {
|
||||
internal::gdextension_interface_variant_call(_native_ptr(), method._native_ptr(), reinterpret_cast<GDExtensionConstVariantPtr *>(args), argcount, r_ret._native_ptr(), &r_error);
|
||||
}
|
||||
|
||||
void Variant::call_static(Variant::Type type, const StringName &method, const Variant **args, int argcount, Variant &r_ret, GDExtensionCallError &r_error) {
|
||||
void Variant::callp_static(Variant::Type type, const StringName &method, const Variant **args, int argcount, Variant &r_ret, GDExtensionCallError &r_error) {
|
||||
internal::gdextension_interface_variant_call_static(static_cast<GDExtensionVariantType>(type), method._native_ptr(), reinterpret_cast<GDExtensionConstVariantPtr *>(args), argcount, r_ret._native_ptr(), &r_error);
|
||||
}
|
||||
|
||||
@@ -638,14 +636,16 @@ bool Variant::in(const Variant &index, bool *r_valid) const {
|
||||
|
||||
bool Variant::iter_init(Variant &r_iter, bool &r_valid) const {
|
||||
GDExtensionBool valid;
|
||||
internal::gdextension_interface_variant_iter_init(_native_ptr(), r_iter._native_ptr(), &valid);
|
||||
return PtrToArg<bool>::convert(&valid);
|
||||
GDExtensionBool result = internal::gdextension_interface_variant_iter_init(_native_ptr(), r_iter._native_ptr(), &valid);
|
||||
r_valid = PtrToArg<bool>::convert(&valid);
|
||||
return PtrToArg<bool>::convert(&result);
|
||||
}
|
||||
|
||||
bool Variant::iter_next(Variant &r_iter, bool &r_valid) const {
|
||||
GDExtensionBool valid;
|
||||
internal::gdextension_interface_variant_iter_next(_native_ptr(), r_iter._native_ptr(), &valid);
|
||||
return PtrToArg<bool>::convert(&valid);
|
||||
GDExtensionBool result = internal::gdextension_interface_variant_iter_next(_native_ptr(), r_iter._native_ptr(), &valid);
|
||||
r_valid = PtrToArg<bool>::convert(&valid);
|
||||
return PtrToArg<bool>::convert(&result);
|
||||
}
|
||||
|
||||
Variant Variant::iter_get(const Variant &r_iter, bool &r_valid) const {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
cmake_minimum_required(VERSION 3.13)
|
||||
project(godot-cpp-test)
|
||||
cmake_minimum_required(VERSION 3.6)
|
||||
|
||||
set(GODOT_GDEXTENSION_DIR ../gdextension/ CACHE STRING "Path to GDExtension interface header directory")
|
||||
set(CPP_BINDINGS_PATH ../ CACHE STRING "Path to C++ bindings")
|
||||
@@ -36,7 +36,7 @@ set(GODOT_LINKER_FLAGS )
|
||||
|
||||
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
|
||||
# using Visual Studio C++
|
||||
set(GODOT_COMPILE_FLAGS "${GODOT_COMPILE_FLAGS} /EHsc /WX") # /GF /MP
|
||||
set(GODOT_COMPILE_FLAGS "${GODOT_COMPILE_FLAGS} /WX") # /GF /MP
|
||||
set(GODOT_COMPILE_FLAGS "${GODOT_COMPILE_FLAGS} /DTYPED_METHOD_BIND")
|
||||
|
||||
if(CMAKE_BUILD_TYPE MATCHES Debug)
|
||||
@@ -59,31 +59,9 @@ if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
|
||||
|
||||
else()
|
||||
|
||||
#elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
|
||||
# using Clang
|
||||
#elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
|
||||
# using GCC and maybe MinGW?
|
||||
|
||||
set(GODOT_LINKER_FLAGS "-static-libgcc -static-libstdc++ -Wl,-R,'$$ORIGIN'")
|
||||
|
||||
# Hmm.. maybe to strikt?
|
||||
set(GODOT_COMPILE_FLAGS "-fPIC -g -Wwrite-strings")
|
||||
set(GODOT_COMPILE_FLAGS "${GODOT_COMPILE_FLAGS} -Wchar-subscripts -Wcomment -Wdisabled-optimization")
|
||||
set(GODOT_COMPILE_FLAGS "${GODOT_COMPILE_FLAGS} -Wformat -Wformat=2 -Wformat-security -Wformat-y2k")
|
||||
set(GODOT_COMPILE_FLAGS "${GODOT_COMPILE_FLAGS} -Wimport -Winit-self -Winline -Winvalid-pch -Werror")
|
||||
set(GODOT_COMPILE_FLAGS "${GODOT_COMPILE_FLAGS} -Wmissing-braces -Wmissing-format-attribute")
|
||||
set(GODOT_COMPILE_FLAGS "${GODOT_COMPILE_FLAGS} -Wmissing-include-dirs -Wmissing-noreturn -Wpacked -Wpointer-arith")
|
||||
set(GODOT_COMPILE_FLAGS "${GODOT_COMPILE_FLAGS} -Wredundant-decls -Wreturn-type -Wsequence-point")
|
||||
set(GODOT_COMPILE_FLAGS "${GODOT_COMPILE_FLAGS} -Wswitch -Wswitch-enum -Wtrigraphs")
|
||||
set(GODOT_COMPILE_FLAGS "${GODOT_COMPILE_FLAGS} -Wuninitialized -Wunknown-pragmas -Wunreachable-code -Wunused-label")
|
||||
set(GODOT_COMPILE_FLAGS "${GODOT_COMPILE_FLAGS} -Wunused-value -Wvariadic-macros -Wvolatile-register-var -Wno-error=attributes")
|
||||
|
||||
# -Wshadow -Wextra -Wall -Weffc++ -Wfloat-equal -Wstack-protector -Wunused-parameter -Wsign-compare -Wunused-variable -Wcast-align
|
||||
# -Wunused-function -Wstrict-aliasing -Wstrict-aliasing=2 -Wmissing-field-initializers
|
||||
|
||||
if(NOT CMAKE_SYSTEM_NAME STREQUAL "Android")
|
||||
set(GODOT_COMPILE_FLAGS "${GODOT_COMPILE_FLAGS} -Wno-ignored-attributes")
|
||||
endif()
|
||||
|
||||
if(CMAKE_BUILD_TYPE MATCHES Debug)
|
||||
set(GODOT_COMPILE_FLAGS "${GODOT_COMPILE_FLAGS} -fno-omit-frame-pointer -O0")
|
||||
@@ -92,6 +70,21 @@ else()
|
||||
endif(CMAKE_BUILD_TYPE MATCHES Debug)
|
||||
endif()
|
||||
|
||||
# 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(GODOT_DISABLE_EXCEPTIONS OFF "Force disabling exception handling code")
|
||||
if (GODOT_DISABLE_EXCEPTIONS)
|
||||
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
|
||||
set(GODOT_COMPILE_FLAGS "${GODOT_COMPILE_FLAGS} -D_HAS_EXCEPTIONS=0")
|
||||
else()
|
||||
set(GODOT_COMPILE_FLAGS "${GODOT_COMPILE_FLAGS} -fno-exceptions")
|
||||
endif()
|
||||
else()
|
||||
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
|
||||
set(GODOT_COMPILE_FLAGS "${GODOT_COMPILE_FLAGS} /EHsc")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Get Sources
|
||||
file(GLOB_RECURSE SOURCES src/*.c**)
|
||||
file(GLOB_RECURSE HEADERS include/*.h**)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
[configuration]
|
||||
|
||||
entry_symbol = "example_library_init"
|
||||
compatibility_minimum = 4.1
|
||||
compatibility_minimum = "4.1"
|
||||
|
||||
[libraries]
|
||||
|
||||
@@ -21,3 +21,5 @@ android.debug.x86_64 = "res://bin/libgdexample.android.template_debug.x86_64.so"
|
||||
android.release.x86_64 = "res://bin/libgdexample.android.template_release.x86_64.so"
|
||||
android.debug.arm64 = "res://bin/libgdexample.android.template_debug.arm64.so"
|
||||
android.release.arm64 = "res://bin/libgdexample.android.template_release.arm64.so"
|
||||
web.debug.wasm32 = "res://bin/libgdexample.web.template_debug.wasm32.wasm"
|
||||
web.release.wasm32 = "res://bin/libgdexample.web.template_release.wasm32.wasm"
|
||||
|
||||
@@ -2,6 +2,9 @@ extends "res://test_base.gd"
|
||||
|
||||
var custom_signal_emitted = null
|
||||
|
||||
class TestClass:
|
||||
func test(p_msg: String) -> String:
|
||||
return p_msg + " world"
|
||||
|
||||
func _ready():
|
||||
var example: Example = $Example
|
||||
@@ -82,14 +85,66 @@ func _ready():
|
||||
# UtilityFunctions::str()
|
||||
assert_equal(example.test_str_utility(), "Hello, World! The answer is 42")
|
||||
|
||||
# Test converting string to char* and doing comparison.
|
||||
assert_equal(example.test_string_is_fourty_two("blah"), false)
|
||||
assert_equal(example.test_string_is_fourty_two("fourty two"), true)
|
||||
|
||||
# PackedArray iterators
|
||||
assert_equal(example.test_vector_ops(), 105)
|
||||
assert_equal(example.test_vector_init_list(), 105)
|
||||
|
||||
# Properties.
|
||||
assert_equal(example.group_subgroup_custom_position, Vector2(0, 0))
|
||||
example.group_subgroup_custom_position = Vector2(50, 50)
|
||||
assert_equal(example.group_subgroup_custom_position, Vector2(50, 50))
|
||||
|
||||
# Test Object::cast_to<>() and that correct wrappers are being used.
|
||||
var control = Control.new()
|
||||
var sprite = Sprite2D.new()
|
||||
var example_ref = ExampleRef.new()
|
||||
|
||||
assert_equal(example.test_object_cast_to_node(control), true)
|
||||
assert_equal(example.test_object_cast_to_control(control), true)
|
||||
assert_equal(example.test_object_cast_to_example(control), false)
|
||||
|
||||
assert_equal(example.test_object_cast_to_node(example), true)
|
||||
assert_equal(example.test_object_cast_to_control(example), true)
|
||||
assert_equal(example.test_object_cast_to_example(example), true)
|
||||
|
||||
assert_equal(example.test_object_cast_to_node(sprite), true)
|
||||
assert_equal(example.test_object_cast_to_control(sprite), false)
|
||||
assert_equal(example.test_object_cast_to_example(sprite), false)
|
||||
|
||||
assert_equal(example.test_object_cast_to_node(example_ref), false)
|
||||
assert_equal(example.test_object_cast_to_control(example_ref), false)
|
||||
assert_equal(example.test_object_cast_to_example(example_ref), false)
|
||||
|
||||
control.queue_free()
|
||||
sprite.queue_free()
|
||||
|
||||
# Test conversions to and from Variant.
|
||||
assert_equal(example.test_variant_vector2i_conversion(Vector2i(1, 1)), Vector2i(1, 1))
|
||||
assert_equal(example.test_variant_vector2i_conversion(Vector2(1.0, 1.0)), Vector2i(1, 1))
|
||||
assert_equal(example.test_variant_int_conversion(10), 10)
|
||||
assert_equal(example.test_variant_int_conversion(10.0), 10)
|
||||
assert_equal(example.test_variant_float_conversion(10.0), 10.0)
|
||||
assert_equal(example.test_variant_float_conversion(10), 10.0)
|
||||
|
||||
# Test that ptrcalls from GDExtension to the engine are correctly encoding Object and RefCounted.
|
||||
var new_node = Node.new()
|
||||
example.test_add_child(new_node)
|
||||
assert_equal(new_node.get_parent(), example)
|
||||
|
||||
var new_tileset = TileSet.new()
|
||||
var new_tilemap = TileMap.new()
|
||||
example.test_set_tileset(new_tilemap, new_tileset)
|
||||
assert_equal(new_tilemap.tile_set, new_tileset)
|
||||
new_tilemap.queue_free()
|
||||
|
||||
# Test variant call.
|
||||
var test_obj = TestClass.new()
|
||||
assert_equal(example.test_variant_call(test_obj), "hello world")
|
||||
|
||||
# Constants.
|
||||
assert_equal(Example.FIRST, 0)
|
||||
assert_equal(Example.ANSWER_TO_EVERYTHING, 42)
|
||||
@@ -115,6 +170,16 @@ func _ready():
|
||||
get_viewport().push_input(event)
|
||||
assert_equal(custom_signal_emitted, ["_input: H", 72])
|
||||
|
||||
# Check NOTIFICATION_POST_INITIALIZED, both when created from GDScript and godot-cpp.
|
||||
var new_example_ref = ExampleRef.new()
|
||||
assert_equal(new_example_ref.was_post_initialized(), true)
|
||||
assert_equal(example.test_post_initialize(), true)
|
||||
|
||||
# Test that notifications happen on both parent and child classes.
|
||||
var example_child = $ExampleChild
|
||||
assert_equal(example_child.get_value1(), 11)
|
||||
assert_equal(example_child.get_value2(), 33)
|
||||
|
||||
exit_with_status()
|
||||
|
||||
func _on_Example_custom_signal(signal_name, value):
|
||||
|
||||
@@ -22,4 +22,6 @@ offset_right = 79.0
|
||||
offset_bottom = 29.0
|
||||
text = "Click me!"
|
||||
|
||||
[node name="ExampleChild" type="ExampleChild" parent="."]
|
||||
|
||||
[connection signal="custom_signal" from="Example" to="." method="_on_Example_custom_signal"]
|
||||
|
||||
@@ -23,10 +23,18 @@ int ExampleRef::get_id() const {
|
||||
return id;
|
||||
}
|
||||
|
||||
void ExampleRef::_notification(int p_what) {
|
||||
if (p_what == NOTIFICATION_POSTINITIALIZE) {
|
||||
post_initialized = true;
|
||||
}
|
||||
}
|
||||
|
||||
void ExampleRef::_bind_methods() {
|
||||
ClassDB::bind_method(D_METHOD("set_id", "id"), &ExampleRef::set_id);
|
||||
ClassDB::bind_method(D_METHOD("get_id"), &ExampleRef::get_id);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("was_post_initialized"), &ExampleRef::was_post_initialized);
|
||||
|
||||
ADD_PROPERTY(PropertyInfo(Variant::INT, "id"), "set_id", "get_id");
|
||||
}
|
||||
|
||||
@@ -138,7 +146,22 @@ void Example::_bind_methods() {
|
||||
ClassDB::bind_method(D_METHOD("test_node_argument"), &Example::test_node_argument);
|
||||
ClassDB::bind_method(D_METHOD("test_string_ops"), &Example::test_string_ops);
|
||||
ClassDB::bind_method(D_METHOD("test_str_utility"), &Example::test_str_utility);
|
||||
ClassDB::bind_method(D_METHOD("test_string_is_fourty_two"), &Example::test_string_is_fourty_two);
|
||||
ClassDB::bind_method(D_METHOD("test_vector_ops"), &Example::test_vector_ops);
|
||||
ClassDB::bind_method(D_METHOD("test_vector_init_list"), &Example::test_vector_init_list);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("test_object_cast_to_node", "object"), &Example::test_object_cast_to_node);
|
||||
ClassDB::bind_method(D_METHOD("test_object_cast_to_control", "object"), &Example::test_object_cast_to_control);
|
||||
ClassDB::bind_method(D_METHOD("test_object_cast_to_example", "object"), &Example::test_object_cast_to_example);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("test_variant_vector2i_conversion", "variant"), &Example::test_variant_vector2i_conversion);
|
||||
ClassDB::bind_method(D_METHOD("test_variant_int_conversion", "variant"), &Example::test_variant_int_conversion);
|
||||
ClassDB::bind_method(D_METHOD("test_variant_float_conversion", "variant"), &Example::test_variant_float_conversion);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("test_add_child", "node"), &Example::test_add_child);
|
||||
ClassDB::bind_method(D_METHOD("test_set_tileset", "tilemap", "tileset"), &Example::test_set_tileset);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("test_variant_call", "variant"), &Example::test_variant_call);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("test_bitfield", "flags"), &Example::test_bitfield);
|
||||
|
||||
@@ -147,6 +170,7 @@ void Example::_bind_methods() {
|
||||
ClassDB::bind_method(D_METHOD("return_last_rpc_arg"), &Example::return_last_rpc_arg);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("def_args", "a", "b"), &Example::def_args, DEFVAL(100), DEFVAL(200));
|
||||
ClassDB::bind_method(D_METHOD("test_post_initialize"), &Example::test_post_initialize);
|
||||
|
||||
ClassDB::bind_static_method("Example", D_METHOD("test_static", "a", "b"), &Example::test_static);
|
||||
ClassDB::bind_static_method("Example", D_METHOD("test_static2"), &Example::test_static2);
|
||||
@@ -299,6 +323,10 @@ String Example::test_str_utility() const {
|
||||
return UtilityFunctions::str("Hello, ", "World", "! The answer is ", 42);
|
||||
}
|
||||
|
||||
bool Example::test_string_is_fourty_two(const String &p_string) const {
|
||||
return strcmp(p_string.utf8().ptr(), "fourty two") == 0;
|
||||
}
|
||||
|
||||
int Example::test_vector_ops() const {
|
||||
PackedInt32Array arr;
|
||||
arr.push_back(10);
|
||||
@@ -312,6 +340,15 @@ int Example::test_vector_ops() const {
|
||||
return ret;
|
||||
}
|
||||
|
||||
int Example::test_vector_init_list() const {
|
||||
PackedInt32Array arr = { 10, 20, 30, 45 };
|
||||
int ret = 0;
|
||||
for (const int32_t &E : arr) {
|
||||
ret += E;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int Example::test_tarray_arg(const TypedArray<int64_t> &p_array) {
|
||||
int sum = 0;
|
||||
for (int i = 0; i < p_array.size(); i++) {
|
||||
@@ -343,6 +380,42 @@ Example *Example::test_node_argument(Example *p_node) const {
|
||||
return p_node;
|
||||
}
|
||||
|
||||
bool Example::test_object_cast_to_node(Object *p_object) const {
|
||||
return Object::cast_to<Node>(p_object) != nullptr;
|
||||
}
|
||||
|
||||
bool Example::test_object_cast_to_control(Object *p_object) const {
|
||||
return Object::cast_to<Control>(p_object) != nullptr;
|
||||
}
|
||||
|
||||
bool Example::test_object_cast_to_example(Object *p_object) const {
|
||||
return Object::cast_to<Example>(p_object) != nullptr;
|
||||
}
|
||||
|
||||
Vector2i Example::test_variant_vector2i_conversion(const Variant &p_variant) const {
|
||||
return p_variant;
|
||||
}
|
||||
|
||||
int Example::test_variant_int_conversion(const Variant &p_variant) const {
|
||||
return p_variant;
|
||||
}
|
||||
|
||||
float Example::test_variant_float_conversion(const Variant &p_variant) const {
|
||||
return p_variant;
|
||||
}
|
||||
|
||||
void Example::test_add_child(Node *p_node) {
|
||||
add_child(p_node);
|
||||
}
|
||||
|
||||
void Example::test_set_tileset(TileMap *p_tilemap, const Ref<TileSet> &p_tileset) const {
|
||||
p_tilemap->set_tileset(p_tileset);
|
||||
}
|
||||
|
||||
Variant Example::test_variant_call(Variant p_variant) {
|
||||
return p_variant.call("test", "hello");
|
||||
}
|
||||
|
||||
BitField<Example::Flags> Example::test_bitfield(BitField<Flags> flags) {
|
||||
return flags;
|
||||
}
|
||||
@@ -372,6 +445,12 @@ Vector4 Example::get_v4() const {
|
||||
return Vector4(1.2, 3.4, 5.6, 7.8);
|
||||
}
|
||||
|
||||
bool Example::test_post_initialize() const {
|
||||
Ref<ExampleRef> new_example_ref;
|
||||
new_example_ref.instantiate();
|
||||
return new_example_ref->was_post_initialized();
|
||||
}
|
||||
|
||||
// Virtual function override.
|
||||
bool Example::_has_point(const Vector2 &point) const {
|
||||
Label *label = get_node<Label>("Label");
|
||||
@@ -386,3 +465,21 @@ void Example::_input(const Ref<InputEvent> &event) {
|
||||
emit_custom_signal(String("_input: ") + key_event->get_key_label(), key_event->get_unicode());
|
||||
}
|
||||
}
|
||||
|
||||
void ExampleBase::_bind_methods() {
|
||||
ClassDB::bind_method(D_METHOD("get_value1"), &ExampleBase::get_value1);
|
||||
ClassDB::bind_method(D_METHOD("get_value2"), &ExampleBase::get_value2);
|
||||
}
|
||||
|
||||
void ExampleBase::_notification(int p_what) {
|
||||
if (p_what == NOTIFICATION_ENTER_TREE) {
|
||||
value1 = 11;
|
||||
value2 = 22;
|
||||
}
|
||||
}
|
||||
|
||||
void ExampleChild::_notification(int p_what) {
|
||||
if (p_what == NOTIFICATION_ENTER_TREE) {
|
||||
value2 = 33;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,7 +18,10 @@
|
||||
#include <godot_cpp/classes/global_constants.hpp>
|
||||
#include <godot_cpp/classes/image.hpp>
|
||||
#include <godot_cpp/classes/input_event_key.hpp>
|
||||
#include <godot_cpp/classes/tile_map.hpp>
|
||||
#include <godot_cpp/classes/tile_set.hpp>
|
||||
#include <godot_cpp/classes/viewport.hpp>
|
||||
#include <godot_cpp/variant/variant.hpp>
|
||||
|
||||
#include <godot_cpp/core/binder_common.hpp>
|
||||
|
||||
@@ -32,16 +35,21 @@ private:
|
||||
static int last_id;
|
||||
|
||||
int id;
|
||||
bool post_initialized = false;
|
||||
|
||||
protected:
|
||||
static void _bind_methods();
|
||||
|
||||
void _notification(int p_what);
|
||||
|
||||
public:
|
||||
ExampleRef();
|
||||
~ExampleRef();
|
||||
|
||||
void set_id(int p_id);
|
||||
int get_id() const;
|
||||
|
||||
bool was_post_initialized() const { return post_initialized; }
|
||||
};
|
||||
|
||||
class ExampleMin : public Control {
|
||||
@@ -117,7 +125,22 @@ public:
|
||||
Example *test_node_argument(Example *p_node) const;
|
||||
String test_string_ops() const;
|
||||
String test_str_utility() const;
|
||||
bool test_string_is_fourty_two(const String &p_str) const;
|
||||
int test_vector_ops() const;
|
||||
int test_vector_init_list() const;
|
||||
|
||||
bool test_object_cast_to_node(Object *p_object) const;
|
||||
bool test_object_cast_to_control(Object *p_object) const;
|
||||
bool test_object_cast_to_example(Object *p_object) const;
|
||||
|
||||
Vector2i test_variant_vector2i_conversion(const Variant &p_variant) const;
|
||||
int test_variant_int_conversion(const Variant &p_variant) const;
|
||||
float test_variant_float_conversion(const Variant &p_variant) const;
|
||||
|
||||
void test_add_child(Node *p_node);
|
||||
void test_set_tileset(TileMap *p_tilemap, const Ref<TileSet> &p_tileset) const;
|
||||
|
||||
Variant test_variant_call(Variant p_variant);
|
||||
|
||||
BitField<Flags> test_bitfield(BitField<Flags> flags);
|
||||
|
||||
@@ -131,6 +154,8 @@ public:
|
||||
Vector2 get_custom_position() const;
|
||||
Vector4 get_v4() const;
|
||||
|
||||
bool test_post_initialize() const;
|
||||
|
||||
// Static method.
|
||||
static int test_static(int p_a, int p_b);
|
||||
static void test_static2();
|
||||
@@ -162,4 +187,29 @@ protected:
|
||||
static void _bind_methods() {}
|
||||
};
|
||||
|
||||
class ExampleBase : public Node {
|
||||
GDCLASS(ExampleBase, Node);
|
||||
|
||||
protected:
|
||||
int value1 = 0;
|
||||
int value2 = 0;
|
||||
|
||||
static void _bind_methods();
|
||||
|
||||
void _notification(int p_what);
|
||||
|
||||
public:
|
||||
int get_value1() { return value1; }
|
||||
int get_value2() { return value2; }
|
||||
};
|
||||
|
||||
class ExampleChild : public ExampleBase {
|
||||
GDCLASS(ExampleChild, ExampleBase);
|
||||
|
||||
protected:
|
||||
static void _bind_methods() {}
|
||||
|
||||
void _notification(int p_what);
|
||||
};
|
||||
|
||||
#endif // EXAMPLE_CLASS_H
|
||||
|
||||
@@ -21,11 +21,13 @@ void initialize_example_module(ModuleInitializationLevel p_level) {
|
||||
return;
|
||||
}
|
||||
|
||||
ClassDB::register_class<ExampleRef>();
|
||||
ClassDB::register_class<ExampleMin>();
|
||||
ClassDB::register_class<Example>();
|
||||
ClassDB::register_class<ExampleVirtual>(true);
|
||||
ClassDB::register_abstract_class<ExampleAbstract>();
|
||||
GDREGISTER_CLASS(ExampleRef);
|
||||
GDREGISTER_CLASS(ExampleMin);
|
||||
GDREGISTER_CLASS(Example);
|
||||
GDREGISTER_VIRTUAL_CLASS(ExampleVirtual);
|
||||
GDREGISTER_ABSTRACT_CLASS(ExampleAbstract);
|
||||
GDREGISTER_CLASS(ExampleBase);
|
||||
GDREGISTER_CLASS(ExampleChild);
|
||||
}
|
||||
|
||||
void uninitialize_example_module(ModuleInitializationLevel p_level) {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import os
|
||||
import sys
|
||||
import my_spawn
|
||||
import common_compiler_flags
|
||||
from SCons.Script import ARGUMENTS
|
||||
|
||||
|
||||
@@ -8,41 +9,51 @@ def options(opts):
|
||||
opts.Add(
|
||||
"android_api_level",
|
||||
"Target Android API level",
|
||||
"18" if "32" in ARGUMENTS.get("arch", "arm64") else "21",
|
||||
"21",
|
||||
)
|
||||
opts.Add(
|
||||
"ANDROID_NDK_ROOT",
|
||||
"Path to your Android NDK installation. By default, uses ANDROID_NDK_ROOT from your defined environment variables.",
|
||||
os.environ.get("ANDROID_NDK_ROOT", None),
|
||||
"ANDROID_HOME",
|
||||
"Path to your Android SDK installation. By default, uses ANDROID_HOME from your defined environment variables.",
|
||||
os.environ.get("ANDROID_HOME", os.environ.get("ANDROID_SDK_ROOT")),
|
||||
)
|
||||
|
||||
|
||||
def exists(env):
|
||||
return "ANDROID_NDK_ROOT" in os.environ or "ANDROID_NDK_ROOT" in ARGUMENTS
|
||||
return get_android_ndk_root(env) is not None
|
||||
|
||||
|
||||
# This must be kept in sync with the value in https://github.com/godotengine/godot/blob/master/platform/android/detect.py#L58.
|
||||
def get_ndk_version():
|
||||
return "23.2.8568313"
|
||||
|
||||
|
||||
def get_android_ndk_root(env):
|
||||
if env["ANDROID_HOME"]:
|
||||
return env["ANDROID_HOME"] + "/ndk/" + get_ndk_version()
|
||||
else:
|
||||
return os.environ.get("ANDROID_NDK_ROOT")
|
||||
|
||||
|
||||
def generate(env):
|
||||
if "ANDROID_NDK_ROOT" not in env:
|
||||
if get_android_ndk_root(env) is None:
|
||||
raise ValueError(
|
||||
"To build for Android, ANDROID_NDK_ROOT must be defined. Please set ANDROID_NDK_ROOT to the root folder of your Android NDK installation."
|
||||
"To build for Android, the path to the NDK must be defined. Please set ANDROID_HOME to the root folder of your Android SDK installation."
|
||||
)
|
||||
|
||||
if env["arch"] not in ("arm64", "x86_64", "arm32", "x86_32"):
|
||||
print("Only arm64, x86_64, arm32, and x86_32 are supported on Android. Exiting.")
|
||||
Exit()
|
||||
env.Exit(1)
|
||||
|
||||
if sys.platform == "win32" or sys.platform == "msys":
|
||||
my_spawn.configure(env)
|
||||
|
||||
# Validate API level
|
||||
api_level = int(env["android_api_level"])
|
||||
if "64" in env["arch"] and api_level < 21:
|
||||
print("WARN: 64-bit Android architectures require an API level of at least 21; setting android_api_level=21")
|
||||
if int(env["android_api_level"]) < 21:
|
||||
print("WARNING: minimum supported Android target api is 21. Forcing target api 21.")
|
||||
env["android_api_level"] = "21"
|
||||
api_level = 21
|
||||
|
||||
# Setup toolchain
|
||||
toolchain = env["ANDROID_NDK_ROOT"] + "/toolchains/llvm/prebuilt/"
|
||||
toolchain = get_android_ndk_root(env) + "/toolchains/llvm/prebuilt/"
|
||||
if sys.platform == "win32" or sys.platform == "msys":
|
||||
toolchain += "windows"
|
||||
import platform as pltfm
|
||||
@@ -54,6 +65,12 @@ def generate(env):
|
||||
elif sys.platform == "darwin":
|
||||
toolchain += "darwin-x86_64"
|
||||
env.Append(LINKFLAGS=["-shared"])
|
||||
|
||||
if not os.path.exists(toolchain):
|
||||
print("ERROR: Could not find NDK toolchain at " + toolchain + ".")
|
||||
print("Make sure NDK version " + get_ndk_version() + " is installed.")
|
||||
env.Exit(1)
|
||||
|
||||
env.PrependENVPath("PATH", toolchain + "/bin") # This does nothing half of the time, but we'll put it here anyways
|
||||
|
||||
# Get architecture info
|
||||
@@ -100,3 +117,7 @@ def generate(env):
|
||||
)
|
||||
env.Append(CCFLAGS=arch_info["ccflags"])
|
||||
env.Append(LINKFLAGS=["--target=" + arch_info["target"] + env["android_api_level"], "-march=" + arch_info["march"]])
|
||||
|
||||
env.Append(CPPDEFINES=["ANDROID_ENABLED", "UNIX_ENABLED"])
|
||||
|
||||
common_compiler_flags.generate(env)
|
||||
|
||||
86
tools/common_compiler_flags.py
Normal file
86
tools/common_compiler_flags.py
Normal file
@@ -0,0 +1,86 @@
|
||||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
|
||||
def using_clang(env):
|
||||
return "clang" in os.path.basename(env["CC"])
|
||||
|
||||
|
||||
def is_vanilla_clang(env):
|
||||
if not using_clang(env):
|
||||
return False
|
||||
try:
|
||||
version = subprocess.check_output([env.subst(env["CXX"]), "--version"]).strip().decode("utf-8")
|
||||
except (subprocess.CalledProcessError, OSError):
|
||||
print("Couldn't parse CXX environment variable to infer compiler version.")
|
||||
return False
|
||||
return not version.startswith("Apple")
|
||||
|
||||
|
||||
def exists(env):
|
||||
return True
|
||||
|
||||
|
||||
def generate(env):
|
||||
# Require C++17
|
||||
if env.get("is_msvc", False):
|
||||
env.Append(CXXFLAGS=["/std:c++17"])
|
||||
else:
|
||||
env.Append(CXXFLAGS=["-std=c++17"])
|
||||
|
||||
# Disable exception handling. Godot doesn't use exceptions anywhere, and this
|
||||
# saves around 20% of binary size and very significant build time.
|
||||
if env["disable_exceptions"]:
|
||||
if env.get("is_msvc", False):
|
||||
env.Append(CPPDEFINES=[("_HAS_EXCEPTIONS", 0)])
|
||||
else:
|
||||
env.Append(CXXFLAGS=["-fno-exceptions"])
|
||||
elif env.get("is_msvc", False):
|
||||
env.Append(CXXFLAGS=["/EHsc"])
|
||||
|
||||
# Set optimize and debug_symbols flags.
|
||||
# "custom" means do nothing and let users set their own optimization flags.
|
||||
if env.get("is_msvc", False):
|
||||
if env["debug_symbols"]:
|
||||
env.Append(CCFLAGS=["/Zi", "/FS"])
|
||||
env.Append(LINKFLAGS=["/DEBUG:FULL"])
|
||||
|
||||
if env["optimize"] == "speed":
|
||||
env.Append(CCFLAGS=["/O2"])
|
||||
env.Append(LINKFLAGS=["/OPT:REF"])
|
||||
elif env["optimize"] == "speed_trace":
|
||||
env.Append(CCFLAGS=["/O2"])
|
||||
env.Append(LINKFLAGS=["/OPT:REF", "/OPT:NOICF"])
|
||||
elif env["optimize"] == "size":
|
||||
env.Append(CCFLAGS=["/O1"])
|
||||
env.Append(LINKFLAGS=["/OPT:REF"])
|
||||
elif env["optimize"] == "debug" or env["optimize"] == "none":
|
||||
env.Append(CCFLAGS=["/Od"])
|
||||
else:
|
||||
if env["debug_symbols"]:
|
||||
# Adding dwarf-4 explicitly makes stacktraces work with clang builds,
|
||||
# otherwise addr2line doesn't understand them.
|
||||
env.Append(CCFLAGS=["-gdwarf-4"])
|
||||
if env.dev_build:
|
||||
env.Append(CCFLAGS=["-g3"])
|
||||
else:
|
||||
env.Append(CCFLAGS=["-g2"])
|
||||
else:
|
||||
if using_clang(env) and not is_vanilla_clang(env):
|
||||
# Apple Clang, its linker doesn't like -s.
|
||||
env.Append(LINKFLAGS=["-Wl,-S", "-Wl,-x", "-Wl,-dead_strip"])
|
||||
else:
|
||||
env.Append(LINKFLAGS=["-s"])
|
||||
|
||||
if env["optimize"] == "speed":
|
||||
env.Append(CCFLAGS=["-O3"])
|
||||
# `-O2` is friendlier to debuggers than `-O3`, leading to better crash backtraces.
|
||||
elif env["optimize"] == "speed_trace":
|
||||
env.Append(CCFLAGS=["-O2"])
|
||||
elif env["optimize"] == "size":
|
||||
env.Append(CCFLAGS=["-Os"])
|
||||
elif env["optimize"] == "debug":
|
||||
env.Append(CCFLAGS=["-Og"])
|
||||
elif env["optimize"] == "none":
|
||||
env.Append(CCFLAGS=["-O0"])
|
||||
482
tools/godotcpp.py
Normal file
482
tools/godotcpp.py
Normal file
@@ -0,0 +1,482 @@
|
||||
import os, sys, platform
|
||||
|
||||
from SCons.Variables import EnumVariable, PathVariable, BoolVariable
|
||||
from SCons.Variables.BoolVariable import _text2bool
|
||||
from SCons.Tool import Tool
|
||||
from SCons.Action import Action
|
||||
from SCons.Builder import Builder
|
||||
from SCons.Errors import UserError
|
||||
from SCons.Script import ARGUMENTS
|
||||
|
||||
|
||||
from binding_generator import scons_generate_bindings, scons_emit_files
|
||||
|
||||
|
||||
def add_sources(sources, dir, extension):
|
||||
for f in os.listdir(dir):
|
||||
if f.endswith("." + extension):
|
||||
sources.append(dir + "/" + f)
|
||||
|
||||
|
||||
def get_cmdline_bool(option, default):
|
||||
"""We use `ARGUMENTS.get()` to check if options were manually overridden on the command line,
|
||||
and SCons' _text2bool helper to convert them to booleans, otherwise they're handled as strings.
|
||||
"""
|
||||
cmdline_val = ARGUMENTS.get(option)
|
||||
if cmdline_val is not None:
|
||||
return _text2bool(cmdline_val)
|
||||
else:
|
||||
return default
|
||||
|
||||
|
||||
def normalize_path(val, env):
|
||||
return val if os.path.isabs(val) else os.path.join(env.Dir("#").abspath, val)
|
||||
|
||||
|
||||
def validate_file(key, val, env):
|
||||
if not os.path.isfile(normalize_path(val, env)):
|
||||
raise UserError("'%s' is not a file: %s" % (key, val))
|
||||
|
||||
|
||||
def validate_dir(key, val, env):
|
||||
if not os.path.isdir(normalize_path(val, env)):
|
||||
raise UserError("'%s' is not a directory: %s" % (key, val))
|
||||
|
||||
|
||||
def validate_parent_dir(key, val, env):
|
||||
if not os.path.isdir(normalize_path(os.path.dirname(val), env)):
|
||||
raise UserError("'%s' is not a directory: %s" % (key, os.path.dirname(val)))
|
||||
|
||||
|
||||
def get_platform_tools_paths(env):
|
||||
path = env.get("custom_tools", None)
|
||||
if path is None:
|
||||
return ["tools"]
|
||||
return [normalize_path(path, env), "tools"]
|
||||
|
||||
|
||||
def get_custom_platforms(env):
|
||||
path = env.get("custom_tools", None)
|
||||
if path is None:
|
||||
return []
|
||||
platforms = []
|
||||
for x in os.listdir(normalize_path(path, env)):
|
||||
if not x.endswith(".py"):
|
||||
continue
|
||||
platforms.append(x.removesuffix(".py"))
|
||||
return platforms
|
||||
|
||||
|
||||
def no_verbose(env):
|
||||
colors = {}
|
||||
|
||||
# Colors are disabled in non-TTY environments such as pipes. This means
|
||||
# that if output is redirected to a file, it will not contain color codes
|
||||
if sys.stdout.isatty():
|
||||
colors["blue"] = "\033[0;94m"
|
||||
colors["bold_blue"] = "\033[1;94m"
|
||||
colors["reset"] = "\033[0m"
|
||||
else:
|
||||
colors["blue"] = ""
|
||||
colors["bold_blue"] = ""
|
||||
colors["reset"] = ""
|
||||
|
||||
# There is a space before "..." to ensure that source file names can be
|
||||
# Ctrl + clicked in the VS Code terminal.
|
||||
compile_source_message = "{}Compiling {}$SOURCE{} ...{}".format(
|
||||
colors["blue"], colors["bold_blue"], colors["blue"], colors["reset"]
|
||||
)
|
||||
java_compile_source_message = "{}Compiling {}$SOURCE{} ...{}".format(
|
||||
colors["blue"], colors["bold_blue"], colors["blue"], colors["reset"]
|
||||
)
|
||||
compile_shared_source_message = "{}Compiling shared {}$SOURCE{} ...{}".format(
|
||||
colors["blue"], colors["bold_blue"], colors["blue"], colors["reset"]
|
||||
)
|
||||
link_program_message = "{}Linking Program {}$TARGET{} ...{}".format(
|
||||
colors["blue"], colors["bold_blue"], colors["blue"], colors["reset"]
|
||||
)
|
||||
link_library_message = "{}Linking Static Library {}$TARGET{} ...{}".format(
|
||||
colors["blue"], colors["bold_blue"], colors["blue"], colors["reset"]
|
||||
)
|
||||
ranlib_library_message = "{}Ranlib Library {}$TARGET{} ...{}".format(
|
||||
colors["blue"], colors["bold_blue"], colors["blue"], colors["reset"]
|
||||
)
|
||||
link_shared_library_message = "{}Linking Shared Library {}$TARGET{} ...{}".format(
|
||||
colors["blue"], colors["bold_blue"], colors["blue"], colors["reset"]
|
||||
)
|
||||
java_library_message = "{}Creating Java Archive {}$TARGET{} ...{}".format(
|
||||
colors["blue"], colors["bold_blue"], colors["blue"], colors["reset"]
|
||||
)
|
||||
compiled_resource_message = "{}Creating Compiled Resource {}$TARGET{} ...{}".format(
|
||||
colors["blue"], colors["bold_blue"], colors["blue"], colors["reset"]
|
||||
)
|
||||
generated_file_message = "{}Generating {}$TARGET{} ...{}".format(
|
||||
colors["blue"], colors["bold_blue"], colors["blue"], colors["reset"]
|
||||
)
|
||||
|
||||
env.Append(CXXCOMSTR=[compile_source_message])
|
||||
env.Append(CCCOMSTR=[compile_source_message])
|
||||
env.Append(SHCCCOMSTR=[compile_shared_source_message])
|
||||
env.Append(SHCXXCOMSTR=[compile_shared_source_message])
|
||||
env.Append(ARCOMSTR=[link_library_message])
|
||||
env.Append(RANLIBCOMSTR=[ranlib_library_message])
|
||||
env.Append(SHLINKCOMSTR=[link_shared_library_message])
|
||||
env.Append(LINKCOMSTR=[link_program_message])
|
||||
env.Append(JARCOMSTR=[java_library_message])
|
||||
env.Append(JAVACCOMSTR=[java_compile_source_message])
|
||||
env.Append(RCCOMSTR=[compiled_resource_message])
|
||||
env.Append(GENCOMSTR=[generated_file_message])
|
||||
|
||||
|
||||
platforms = ["linux", "macos", "windows", "android", "ios", "web"]
|
||||
|
||||
# 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",
|
||||
}
|
||||
|
||||
|
||||
def exists(env):
|
||||
return True
|
||||
|
||||
|
||||
def options(opts, env):
|
||||
# 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>")
|
||||
|
||||
opts.Add(
|
||||
PathVariable(
|
||||
key="custom_tools",
|
||||
help="Path to directory containing custom tools",
|
||||
default=env.get("custom_tools", None),
|
||||
validator=validate_dir,
|
||||
)
|
||||
)
|
||||
|
||||
opts.Update(env)
|
||||
|
||||
custom_platforms = get_custom_platforms(env)
|
||||
|
||||
opts.Add(
|
||||
EnumVariable(
|
||||
key="platform",
|
||||
help="Target platform",
|
||||
default=env.get("platform", default_platform),
|
||||
allowed_values=platforms + custom_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(
|
||||
key="target",
|
||||
help="Compilation target",
|
||||
default=env.get("target", "template_debug"),
|
||||
allowed_values=("editor", "template_release", "template_debug"),
|
||||
)
|
||||
)
|
||||
opts.Add(
|
||||
PathVariable(
|
||||
key="gdextension_dir",
|
||||
help="Path to a custom directory containing GDExtension interface header and API JSON file",
|
||||
default=env.get("gdextension_dir", None),
|
||||
validator=validate_dir,
|
||||
)
|
||||
)
|
||||
opts.Add(
|
||||
PathVariable(
|
||||
key="custom_api_file",
|
||||
help="Path to a custom GDExtension API JSON file (takes precedence over `gdextension_dir`)",
|
||||
default=env.get("custom_api_file", None),
|
||||
validator=validate_file,
|
||||
)
|
||||
)
|
||||
opts.Add(
|
||||
BoolVariable(
|
||||
key="generate_bindings",
|
||||
help="Force GDExtension API bindings generation. Auto-detected by default.",
|
||||
default=env.get("generate_bindings", False),
|
||||
)
|
||||
)
|
||||
opts.Add(
|
||||
BoolVariable(
|
||||
key="generate_template_get_node",
|
||||
help="Generate a template version of the Node class's get_node.",
|
||||
default=env.get("generate_template_get_node", True),
|
||||
)
|
||||
)
|
||||
opts.Add(
|
||||
BoolVariable(
|
||||
key="build_library",
|
||||
help="Build the godot-cpp library.",
|
||||
default=env.get("build_library", True),
|
||||
)
|
||||
)
|
||||
opts.Add(
|
||||
EnumVariable(
|
||||
key="precision",
|
||||
help="Set the floating-point precision level",
|
||||
default=env.get("precision", "single"),
|
||||
allowed_values=("single", "double"),
|
||||
)
|
||||
)
|
||||
opts.Add(
|
||||
EnumVariable(
|
||||
key="arch",
|
||||
help="CPU architecture",
|
||||
default=env.get("arch", ""),
|
||||
allowed_values=architecture_array,
|
||||
map=architecture_aliases,
|
||||
)
|
||||
)
|
||||
|
||||
# compiledb
|
||||
opts.Add(
|
||||
BoolVariable(
|
||||
key="compiledb",
|
||||
help="Generate compilation DB (`compile_commands.json`) for external tools",
|
||||
default=env.get("compiledb", False),
|
||||
)
|
||||
)
|
||||
opts.Add(
|
||||
PathVariable(
|
||||
key="compiledb_file",
|
||||
help="Path to a custom `compile_commands.json` file",
|
||||
default=env.get("compiledb_file", "compile_commands.json"),
|
||||
validator=validate_parent_dir,
|
||||
)
|
||||
)
|
||||
|
||||
opts.Add(
|
||||
BoolVariable(
|
||||
"disable_exceptions",
|
||||
"Force disabling exception handling code",
|
||||
default=env.get("disable_exceptions", False),
|
||||
)
|
||||
)
|
||||
|
||||
opts.Add(
|
||||
EnumVariable(
|
||||
"optimize",
|
||||
"The desired optimization flags",
|
||||
"speed_trace",
|
||||
("none", "custom", "debug", "speed", "speed_trace", "size"),
|
||||
)
|
||||
)
|
||||
opts.Add(BoolVariable("debug_symbols", "Build with debugging symbols", True))
|
||||
opts.Add(BoolVariable("dev_build", "Developer build with dev-only debugging code (DEV_ENABLED)", False))
|
||||
opts.Add(BoolVariable("verbose", "Enable verbose output for the compilation", False))
|
||||
|
||||
# Add platform options (custom tools can override platforms)
|
||||
for pl in sorted(set(platforms + custom_platforms)):
|
||||
tool = Tool(pl, toolpath=get_platform_tools_paths(env))
|
||||
if hasattr(tool, "options"):
|
||||
tool.options(opts)
|
||||
|
||||
|
||||
def generate(env):
|
||||
# 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)
|
||||
|
||||
# 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"] == "web":
|
||||
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)
|
||||
env.Exit(1)
|
||||
|
||||
print("Building for architecture " + env["arch"] + " on platform " + env["platform"])
|
||||
|
||||
# These defaults may be needed by platform tools
|
||||
env.editor_build = env["target"] == "editor"
|
||||
env.dev_build = env["dev_build"]
|
||||
env.debug_features = env["target"] in ["editor", "template_debug"]
|
||||
|
||||
if env.dev_build:
|
||||
opt_level = "none"
|
||||
elif env.debug_features:
|
||||
opt_level = "speed_trace"
|
||||
else: # Release
|
||||
opt_level = "speed"
|
||||
|
||||
env["optimize"] = ARGUMENTS.get("optimize", opt_level)
|
||||
env["debug_symbols"] = get_cmdline_bool("debug_symbols", env.dev_build)
|
||||
|
||||
tool = Tool(env["platform"], toolpath=get_platform_tools_paths(env))
|
||||
|
||||
if tool is None or not tool.exists(env):
|
||||
raise ValueError("Required toolchain not found for platform " + env["platform"])
|
||||
|
||||
tool.generate(env)
|
||||
|
||||
if env.editor_build:
|
||||
env.Append(CPPDEFINES=["TOOLS_ENABLED"])
|
||||
|
||||
# Configuration of build targets:
|
||||
# - Editor or template
|
||||
# - Debug features (DEBUG_ENABLED code)
|
||||
# - Dev only code (DEV_ENABLED code)
|
||||
# - Optimization level
|
||||
# - Debug symbols for crash traces / debuggers
|
||||
# Keep this configuration in sync with SConstruct in upstream Godot.
|
||||
if env.debug_features:
|
||||
# DEBUG_ENABLED enables debugging *features* and debug-only code, which is intended
|
||||
# to give *users* extra debugging information for their game development.
|
||||
env.Append(CPPDEFINES=["DEBUG_ENABLED"])
|
||||
# In upstream Godot this is added in typedefs.h when DEBUG_ENABLED is set.
|
||||
env.Append(CPPDEFINES=["DEBUG_METHODS_ENABLED"])
|
||||
|
||||
if env.dev_build:
|
||||
# DEV_ENABLED enables *engine developer* code which should only be compiled for those
|
||||
# working on the engine itself.
|
||||
env.Append(CPPDEFINES=["DEV_ENABLED"])
|
||||
else:
|
||||
# Disable assert() for production targets (only used in thirdparty code).
|
||||
env.Append(CPPDEFINES=["NDEBUG"])
|
||||
|
||||
if env["precision"] == "double":
|
||||
env.Append(CPPDEFINES=["REAL_T_IS_DOUBLE"])
|
||||
|
||||
# Allow detecting when building as a GDExtension.
|
||||
env.Append(CPPDEFINES=["GDEXTENSION"])
|
||||
|
||||
# Suffix
|
||||
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"
|
||||
|
||||
env["suffix"] = suffix # Exposed when included from another project
|
||||
env["OBJSUFFIX"] = suffix + env["OBJSUFFIX"]
|
||||
|
||||
# compile_commands.json
|
||||
env.Tool("compilation_db")
|
||||
env.Alias("compiledb", env.CompilationDatabase(normalize_path(env["compiledb_file"], env)))
|
||||
|
||||
# Formatting
|
||||
if not env["verbose"]:
|
||||
no_verbose(env)
|
||||
|
||||
# Builders
|
||||
env.Append(
|
||||
BUILDERS={
|
||||
"GodotCPPBindings": Builder(action=Action(scons_generate_bindings, "$GENCOMSTR"), emitter=scons_emit_files)
|
||||
}
|
||||
)
|
||||
env.AddMethod(_godot_cpp, "GodotCPP")
|
||||
|
||||
|
||||
def _godot_cpp(env):
|
||||
extension_dir = normalize_path(env.get("gdextension_dir", env.Dir("gdextension").abspath), env)
|
||||
api_file = normalize_path(env.get("custom_api_file", env.File(extension_dir + "/extension_api.json").abspath), env)
|
||||
bindings = env.GodotCPPBindings(
|
||||
env.Dir("."),
|
||||
[
|
||||
api_file,
|
||||
os.path.join(extension_dir, "gdextension_interface.h"),
|
||||
"binding_generator.py",
|
||||
],
|
||||
)
|
||||
# Forces bindings regeneration.
|
||||
if env["generate_bindings"]:
|
||||
env.AlwaysBuild(bindings)
|
||||
env.NoCache(bindings)
|
||||
|
||||
# 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")])
|
||||
|
||||
# Includes
|
||||
env.AppendUnique(CPPPATH=[env.Dir(d) for d in [extension_dir, "include", "gen/include"]])
|
||||
|
||||
library = None
|
||||
library_name = "libgodot-cpp" + env["suffix"] + env["LIBSUFFIX"]
|
||||
|
||||
if env["build_library"]:
|
||||
library = env.StaticLibrary(target=env.File("bin/%s" % library_name), source=sources)
|
||||
default_args = [library]
|
||||
|
||||
# Add compiledb if the option is set
|
||||
if env.get("compiledb", False):
|
||||
default_args += ["compiledb"]
|
||||
|
||||
env.Default(*default_args)
|
||||
|
||||
env.AppendUnique(LIBS=[env.File("bin/%s" % library_name)])
|
||||
return library
|
||||
40
tools/ios.py
40
tools/ios.py
@@ -1,7 +1,7 @@
|
||||
import os
|
||||
import sys
|
||||
import subprocess
|
||||
import ios_osxcross
|
||||
import common_compiler_flags
|
||||
from SCons.Variables import *
|
||||
|
||||
if sys.version_info < (3,):
|
||||
@@ -16,6 +16,10 @@ else:
|
||||
return codecs.utf_8_decode(x)[0]
|
||||
|
||||
|
||||
def has_ios_osxcross():
|
||||
return "OSXCROSS_IOS" in os.environ
|
||||
|
||||
|
||||
def options(opts):
|
||||
opts.Add(BoolVariable("ios_simulator", "Target iOS Simulator", False))
|
||||
opts.Add("ios_min_version", "Target minimum iphoneos/iphonesimulator version", "10.0")
|
||||
@@ -25,17 +29,18 @@ def options(opts):
|
||||
"/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain",
|
||||
)
|
||||
opts.Add("IOS_SDK_PATH", "Path to the iOS SDK", "")
|
||||
ios_osxcross.options(opts)
|
||||
|
||||
if has_ios_osxcross():
|
||||
opts.Add("ios_triple", "Triple for ios toolchain", "")
|
||||
|
||||
|
||||
def exists(env):
|
||||
return sys.platform == "darwin" or ios_osxcross.exists(env)
|
||||
return sys.platform == "darwin" or has_ios_osxcross()
|
||||
|
||||
|
||||
def generate(env):
|
||||
if env["arch"] not in ("universal", "arm64", "x86_64"):
|
||||
print("Only universal, arm64, and x86_64 are supported on iOS. Exiting.")
|
||||
Exit()
|
||||
raise ValueError("Only universal, arm64, and x86_64 are supported on iOS. Exiting.")
|
||||
|
||||
if env["ios_simulator"]:
|
||||
sdk_name = "iphonesimulator"
|
||||
@@ -64,7 +69,26 @@ def generate(env):
|
||||
env["ENV"]["PATH"] = env["IOS_TOOLCHAIN_PATH"] + "/Developer/usr/bin/:" + env["ENV"]["PATH"]
|
||||
|
||||
else:
|
||||
ios_osxcross.generate(env)
|
||||
# OSXCross
|
||||
compiler_path = "$IOS_TOOLCHAIN_PATH/usr/bin/${ios_triple}"
|
||||
env["CC"] = compiler_path + "clang"
|
||||
env["CXX"] = compiler_path + "clang++"
|
||||
env["AR"] = compiler_path + "ar"
|
||||
env["RANLIB"] = compiler_path + "ranlib"
|
||||
env["SHLIBSUFFIX"] = ".dylib"
|
||||
|
||||
env.Prepend(
|
||||
CPPPATH=[
|
||||
"$IOS_SDK_PATH/usr/include",
|
||||
"$IOS_SDK_PATH/System/Library/Frameworks/AudioUnit.framework/Headers",
|
||||
]
|
||||
)
|
||||
|
||||
env.Append(CCFLAGS=["-stdlib=libc++"])
|
||||
|
||||
binpath = os.path.join(env["IOS_TOOLCHAIN_PATH"], "usr", "bin")
|
||||
if binpath not in env["ENV"]["PATH"]:
|
||||
env.PrependENVPath("PATH", binpath)
|
||||
|
||||
if env["arch"] == "universal":
|
||||
if env["ios_simulator"]:
|
||||
@@ -79,3 +103,7 @@ def generate(env):
|
||||
|
||||
env.Append(CCFLAGS=["-isysroot", env["IOS_SDK_PATH"]])
|
||||
env.Append(LINKFLAGS=["-isysroot", env["IOS_SDK_PATH"], "-F" + env["IOS_SDK_PATH"]])
|
||||
|
||||
env.Append(CPPDEFINES=["IOS_ENABLED", "UNIX_ENABLED"])
|
||||
|
||||
common_compiler_flags.generate(env)
|
||||
|
||||
@@ -1,26 +0,0 @@
|
||||
import os
|
||||
|
||||
|
||||
def options(opts):
|
||||
opts.Add("ios_triple", "Triple for ios toolchain", "")
|
||||
|
||||
|
||||
def exists(env):
|
||||
return "OSXCROSS_IOS" in os.environ
|
||||
|
||||
|
||||
def generate(env):
|
||||
compiler_path = "$IOS_TOOLCHAIN_PATH/usr/bin/${ios_triple}"
|
||||
env["CC"] = compiler_path + "clang"
|
||||
env["CXX"] = compiler_path + "clang++"
|
||||
env["AR"] = compiler_path + "ar"
|
||||
env["RANLIB"] = compiler_path + "ranlib"
|
||||
env["SHLIBSUFFIX"] = ".dylib"
|
||||
|
||||
env.Prepend(
|
||||
CPPPATH=[
|
||||
"$IOS_SDK_PATH/usr/include",
|
||||
"$IOS_SDK_PATH/System/Library/Frameworks/AudioUnit.framework/Headers",
|
||||
]
|
||||
)
|
||||
env.Append(CCFLAGS=["-stdlib=libc++"])
|
||||
@@ -1,3 +1,4 @@
|
||||
import common_compiler_flags
|
||||
from SCons.Variables import *
|
||||
from SCons.Tool import clang, clangxx
|
||||
|
||||
@@ -32,3 +33,7 @@ def generate(env):
|
||||
elif env["arch"] == "rv64":
|
||||
env.Append(CCFLAGS=["-march=rv64gc"])
|
||||
env.Append(LINKFLAGS=["-march=rv64gc"])
|
||||
|
||||
env.Append(CPPDEFINES=["LINUX_ENABLED", "UNIX_ENABLED"])
|
||||
|
||||
common_compiler_flags.generate(env)
|
||||
|
||||
@@ -1,31 +1,52 @@
|
||||
import os
|
||||
import sys
|
||||
import macos_osxcross
|
||||
import common_compiler_flags
|
||||
|
||||
|
||||
def has_osxcross():
|
||||
return "OSXCROSS_ROOT" in os.environ
|
||||
|
||||
|
||||
def options(opts):
|
||||
opts.Add("macos_deployment_target", "macOS deployment target", "default")
|
||||
opts.Add("macos_sdk_path", "macOS SDK path", "")
|
||||
macos_osxcross.options(opts)
|
||||
if has_osxcross():
|
||||
opts.Add("osxcross_sdk", "OSXCross SDK version", "darwin16")
|
||||
|
||||
|
||||
def exists(env):
|
||||
return sys.platform == "darwin" or macos_osxcross.exists(env)
|
||||
return sys.platform == "darwin" or has_osxcross()
|
||||
|
||||
|
||||
def generate(env):
|
||||
if env["arch"] not in ("universal", "arm64", "x86_64"):
|
||||
print("Only universal, arm64, and x86_64 are supported on macOS. Exiting.")
|
||||
Exit()
|
||||
env.Exit(1)
|
||||
|
||||
if sys.platform == "darwin":
|
||||
# Use clang on macOS by default
|
||||
env["CXX"] = "clang++"
|
||||
env["CC"] = "clang"
|
||||
else:
|
||||
# Use osxcross
|
||||
macos_osxcross.generate(env)
|
||||
# OSXCross
|
||||
root = os.environ.get("OSXCROSS_ROOT", "")
|
||||
if env["arch"] == "arm64":
|
||||
basecmd = root + "/target/bin/arm64-apple-" + env["osxcross_sdk"] + "-"
|
||||
else:
|
||||
basecmd = root + "/target/bin/x86_64-apple-" + env["osxcross_sdk"] + "-"
|
||||
|
||||
env["CC"] = basecmd + "clang"
|
||||
env["CXX"] = basecmd + "clang++"
|
||||
env["AR"] = basecmd + "ar"
|
||||
env["RANLIB"] = basecmd + "ranlib"
|
||||
env["AS"] = basecmd + "as"
|
||||
|
||||
binpath = os.path.join(root, "target", "bin")
|
||||
if binpath not in env["ENV"]["PATH"]:
|
||||
# Add OSXCROSS bin folder to PATH (required for linking).
|
||||
env.PrependENVPath("PATH", binpath)
|
||||
|
||||
# Common flags
|
||||
if env["arch"] == "universal":
|
||||
env.Append(LINKFLAGS=["-arch", "x86_64", "-arch", "arm64"])
|
||||
env.Append(CCFLAGS=["-arch", "x86_64", "-arch", "arm64"])
|
||||
@@ -48,3 +69,7 @@ def generate(env):
|
||||
"-Wl,-undefined,dynamic_lookup",
|
||||
]
|
||||
)
|
||||
|
||||
env.Append(CPPDEFINES=["MACOS_ENABLED", "UNIX_ENABLED"])
|
||||
|
||||
common_compiler_flags.generate(env)
|
||||
|
||||
@@ -1,28 +0,0 @@
|
||||
import os
|
||||
|
||||
|
||||
def options(opts):
|
||||
opts.Add("osxcross_sdk", "OSXCross SDK version", "darwin16")
|
||||
|
||||
|
||||
def exists(env):
|
||||
return "OSXCROSS_ROOT" in os.environ
|
||||
|
||||
|
||||
def generate(env):
|
||||
root = os.environ.get("OSXCROSS_ROOT", "")
|
||||
if env["arch"] == "arm64":
|
||||
basecmd = root + "/target/bin/arm64-apple-" + env["osxcross_sdk"] + "-"
|
||||
else:
|
||||
basecmd = root + "/target/bin/x86_64-apple-" + env["osxcross_sdk"] + "-"
|
||||
|
||||
env["CC"] = basecmd + "clang"
|
||||
env["CXX"] = basecmd + "clang++"
|
||||
env["AR"] = basecmd + "ar"
|
||||
env["RANLIB"] = basecmd + "ranlib"
|
||||
env["AS"] = basecmd + "as"
|
||||
|
||||
binpath = os.path.join(root, "target", "bin")
|
||||
if binpath not in env["ENV"]["PATH"]:
|
||||
# Add OSXCROSS bin folder to PATH (required for linking).
|
||||
env["ENV"]["PATH"] = "%s:%s" % (binpath, env["ENV"]["PATH"])
|
||||
@@ -1,92 +0,0 @@
|
||||
import os
|
||||
import sys
|
||||
from SCons.Script import ARGUMENTS
|
||||
from SCons.Variables import *
|
||||
from SCons.Variables.BoolVariable import _text2bool
|
||||
|
||||
|
||||
def get_cmdline_bool(option, default):
|
||||
"""We use `ARGUMENTS.get()` to check if options were manually overridden on the command line,
|
||||
and SCons' _text2bool helper to convert them to booleans, otherwise they're handled as strings.
|
||||
"""
|
||||
cmdline_val = ARGUMENTS.get(option)
|
||||
if cmdline_val is not None:
|
||||
return _text2bool(cmdline_val)
|
||||
else:
|
||||
return default
|
||||
|
||||
|
||||
def options(opts):
|
||||
opts.Add(
|
||||
EnumVariable(
|
||||
"optimize",
|
||||
"The desired optimization flags",
|
||||
"speed_trace",
|
||||
("none", "custom", "debug", "speed", "speed_trace", "size"),
|
||||
)
|
||||
)
|
||||
opts.Add(BoolVariable("debug_symbols", "Build with debugging symbols", True))
|
||||
opts.Add(BoolVariable("dev_build", "Developer build with dev-only debugging code (DEV_ENABLED)", False))
|
||||
|
||||
|
||||
def exists(env):
|
||||
return True
|
||||
|
||||
|
||||
def generate(env):
|
||||
env.dev_build = env["dev_build"]
|
||||
env.debug_features = env["target"] in ["editor", "template_debug"]
|
||||
env.editor_build = env["target"] == "editor"
|
||||
|
||||
if env.editor_build:
|
||||
env.AppendUnique(CPPDEFINES=["TOOLS_ENABLED"])
|
||||
|
||||
if env.debug_features:
|
||||
env.AppendUnique(CPPDEFINES=["DEBUG_ENABLED", "DEBUG_METHODS_ENABLED"])
|
||||
|
||||
if env.dev_build:
|
||||
opt_level = "none"
|
||||
env.AppendUnique(CPPDEFINES=["DEV_ENABLED"])
|
||||
elif env.debug_features:
|
||||
opt_level = "speed_trace"
|
||||
else: # Release
|
||||
opt_level = "speed"
|
||||
|
||||
env["optimize"] = ARGUMENTS.get("optimize", opt_level)
|
||||
env["debug_symbols"] = get_cmdline_bool("debug_symbols", env.dev_build)
|
||||
|
||||
if env.get("is_msvc", False):
|
||||
if env["debug_symbols"]:
|
||||
env.Append(CCFLAGS=["/Zi", "/FS"])
|
||||
env.Append(LINKFLAGS=["/DEBUG:FULL"])
|
||||
|
||||
if env["optimize"] == "speed" or env["optimize"] == "speed_trace":
|
||||
env.Append(CCFLAGS=["/O2"])
|
||||
env.Append(LINKFLAGS=["/OPT:REF"])
|
||||
elif env["optimize"] == "size":
|
||||
env.Append(CCFLAGS=["/O1"])
|
||||
env.Append(LINKFLAGS=["/OPT:REF"])
|
||||
|
||||
if env["optimize"] == "debug" or env["optimize"] == "none":
|
||||
env.Append(CCFLAGS=["/MDd", "/Od"])
|
||||
else:
|
||||
env.Append(CCFLAGS=["/MD"])
|
||||
|
||||
else:
|
||||
if env["debug_symbols"]:
|
||||
if env.dev_build:
|
||||
env.Append(CCFLAGS=["-g3"])
|
||||
else:
|
||||
env.Append(CCFLAGS=["-g2"])
|
||||
|
||||
if env["optimize"] == "speed":
|
||||
env.Append(CCFLAGS=["-O3"])
|
||||
# `-O2` is friendlier to debuggers than `-O3`, leading to better crash backtraces.
|
||||
elif env["optimize"] == "speed_trace":
|
||||
env.Append(CCFLAGS=["-O2"])
|
||||
elif env["optimize"] == "size":
|
||||
env.Append(CCFLAGS=["-Os"])
|
||||
elif env["optimize"] == "debug":
|
||||
env.Append(CCFLAGS=["-Og"])
|
||||
elif env["optimize"] == "none":
|
||||
env.Append(CCFLAGS=["-O0"])
|
||||
@@ -1,45 +1,47 @@
|
||||
import os
|
||||
import common_compiler_flags
|
||||
from SCons.Util import WhereIs
|
||||
|
||||
|
||||
def exists(env):
|
||||
return "EM_CONFIG" in os.environ
|
||||
return WhereIs("emcc") is not None
|
||||
|
||||
|
||||
def generate(env):
|
||||
if env["arch"] not in ("wasm32"):
|
||||
print("Only wasm32 supported on web. Exiting.")
|
||||
Exit()
|
||||
|
||||
if "EM_CONFIG" in os.environ:
|
||||
env["ENV"] = os.environ
|
||||
env.Exit(1)
|
||||
|
||||
# Emscripten toolchain
|
||||
env["CC"] = "emcc"
|
||||
env["CXX"] = "em++"
|
||||
env["AR"] = "emar"
|
||||
env["RANLIB"] = "emranlib"
|
||||
env.Append(CPPFLAGS=["-s", "SIDE_MODULE=1"])
|
||||
env.Append(LINKFLAGS=["-s", "SIDE_MODULE=1"])
|
||||
env["SHOBJSUFFIX"] = ".bc"
|
||||
env["SHLIBSUFFIX"] = ".wasm"
|
||||
|
||||
# Use TempFileMunge since some AR invocations are too long for cmd.exe.
|
||||
# Use POSIX-style paths, required with TempFileMunge.
|
||||
env["ARCOM_POSIX"] = env["ARCOM"].replace("$TARGET", "$TARGET.posix").replace("$SOURCES", "$SOURCES.posix")
|
||||
env["ARCOM"] = "${TEMPFILE(ARCOM_POSIX)}"
|
||||
|
||||
# All intermediate files are just LLVM bitcode.
|
||||
env["OBJPREFIX"] = ""
|
||||
env["OBJSUFFIX"] = ".bc"
|
||||
env["PROGPREFIX"] = ""
|
||||
# Program() output consists of multiple files, so specify suffixes manually at builder.
|
||||
env["PROGSUFFIX"] = ""
|
||||
# All intermediate files are just object files.
|
||||
env["OBJSUFFIX"] = ".o"
|
||||
env["SHOBJSUFFIX"] = ".o"
|
||||
|
||||
# Static libraries clang-style.
|
||||
env["LIBPREFIX"] = "lib"
|
||||
env["LIBSUFFIX"] = ".a"
|
||||
env["LIBPREFIXES"] = ["$LIBPREFIX"]
|
||||
env["LIBSUFFIXES"] = ["$LIBSUFFIX"]
|
||||
env.Replace(SHLINKFLAGS="$LINKFLAGS")
|
||||
env.Replace(SHLINKFLAGS="$LINKFLAGS")
|
||||
|
||||
if env["target"] == "debug":
|
||||
env.Append(CCFLAGS=["-O0", "-g"])
|
||||
elif env["target"] == "release":
|
||||
env.Append(CCFLAGS=["-O3"])
|
||||
# Shared library as wasm.
|
||||
env["SHLIBSUFFIX"] = ".wasm"
|
||||
|
||||
# Thread support (via SharedArrayBuffer).
|
||||
env.Append(CCFLAGS=["-s", "USE_PTHREADS=1"])
|
||||
env.Append(LINKFLAGS=["-s", "USE_PTHREADS=1"])
|
||||
|
||||
# Build as side module (shared library).
|
||||
env.Append(CPPFLAGS=["-s", "SIDE_MODULE=1"])
|
||||
env.Append(LINKFLAGS=["-s", "SIDE_MODULE=1"])
|
||||
|
||||
env.Append(CPPDEFINES=["WEB_ENABLED", "UNIX_ENABLED"])
|
||||
|
||||
common_compiler_flags.generate(env)
|
||||
@@ -1,7 +1,6 @@
|
||||
import sys
|
||||
|
||||
import my_spawn
|
||||
|
||||
import common_compiler_flags
|
||||
from SCons.Tool import msvc, mingw
|
||||
from SCons.Variables import *
|
||||
|
||||
@@ -9,6 +8,7 @@ from SCons.Variables import *
|
||||
def options(opts):
|
||||
opts.Add(BoolVariable("use_mingw", "Use the MinGW compiler instead of MSVC - only effective on Windows", False))
|
||||
opts.Add(BoolVariable("use_clang_cl", "Use the clang driver instead of MSVC - only effective on Windows", False))
|
||||
opts.Add(BoolVariable("use_static_cpp", "Link MinGW/MSVC C++ runtime libraries statically", True))
|
||||
|
||||
|
||||
def exists(env):
|
||||
@@ -30,13 +30,18 @@ def generate(env):
|
||||
env.Tool("mslink")
|
||||
|
||||
env.Append(CPPDEFINES=["TYPED_METHOD_BIND", "NOMINMAX"])
|
||||
env.Append(CCFLAGS=["/EHsc", "/utf-8"])
|
||||
env.Append(CCFLAGS=["/utf-8"])
|
||||
env.Append(LINKFLAGS=["/WX"])
|
||||
|
||||
if env["use_clang_cl"]:
|
||||
env["CC"] = "clang-cl"
|
||||
env["CXX"] = "clang-cl"
|
||||
|
||||
if env["use_static_cpp"]:
|
||||
env.Append(CCFLAGS=["/MT"])
|
||||
else:
|
||||
env.Append(CCFLAGS=["/MD"])
|
||||
|
||||
elif sys.platform == "win32" or sys.platform == "msys":
|
||||
env["use_mingw"] = True
|
||||
mingw.generate(env)
|
||||
@@ -45,6 +50,18 @@ def generate(env):
|
||||
env["SHLIBPREFIX"] = ""
|
||||
# Want dll suffix
|
||||
env["SHLIBSUFFIX"] = ".dll"
|
||||
|
||||
env.Append(CCFLAGS=["-Wwrite-strings"])
|
||||
env.Append(LINKFLAGS=["-Wl,--no-undefined"])
|
||||
if env["use_static_cpp"]:
|
||||
env.Append(
|
||||
LINKFLAGS=[
|
||||
"-static",
|
||||
"-static-libgcc",
|
||||
"-static-libstdc++",
|
||||
]
|
||||
)
|
||||
|
||||
# Long line hack. Use custom spawn, quick AR append (to avoid files with the same names to override each other).
|
||||
my_spawn.configure(env)
|
||||
|
||||
@@ -60,13 +77,17 @@ def generate(env):
|
||||
# Want dll suffix
|
||||
env["SHLIBSUFFIX"] = ".dll"
|
||||
|
||||
# These options are for a release build even using target=debug
|
||||
env.Append(CCFLAGS=["-O3", "-Wwrite-strings"])
|
||||
env.Append(
|
||||
LINKFLAGS=[
|
||||
"--static",
|
||||
"-Wl,--no-undefined",
|
||||
"-static-libgcc",
|
||||
"-static-libstdc++",
|
||||
]
|
||||
)
|
||||
env.Append(CCFLAGS=["-Wwrite-strings"])
|
||||
env.Append(LINKFLAGS=["-Wl,--no-undefined"])
|
||||
if env["use_static_cpp"]:
|
||||
env.Append(
|
||||
LINKFLAGS=[
|
||||
"-static",
|
||||
"-static-libgcc",
|
||||
"-static-libstdc++",
|
||||
]
|
||||
)
|
||||
|
||||
env.Append(CPPDEFINES=["WINDOWS_ENABLED"])
|
||||
|
||||
common_compiler_flags.generate(env)
|
||||
|
||||
Reference in New Issue
Block a user