Compare commits

...

828 Commits

Author SHA1 Message Date
Rémi Verschelde
54136ee835 Add 4.2 branch to README 2023-11-30 10:02:53 +01:00
Rémi Verschelde
0f78fc45bd gdextension: Sync with upstream commit 46dc277917a93cbf601bbcf0d27d00f6feeec0d5 (4.2-stable) 2023-11-30 10:01:44 +01:00
Rémi Verschelde
11b2700b23 Merge pull request #1321 from dsnopek/postinitialize
Send NOTIFICATION_POSTINITIALIZE to extension classes
2023-11-30 09:55:30 +01:00
David Snopek
20c4e843b0 Send NOTIFICATION_POSTINITIALIZE to extension classes 2023-11-29 12:00:43 -06:00
Rémi Verschelde
f3143c7a9c Merge pull request #1320 from mihe/bit-field-size
Change bit field enums to use `uint64_t` as underlying type
2023-11-28 15:05:41 +01:00
Mikael Hermansson
943d1c8cdf Change bit field enums to use uint64_t as underlying type 2023-11-28 01:03:41 +01:00
David Snopek
588d869a3b Merge pull request #1313 from DmitriySalnikov/visibility_hidden
[Scons] Added the ability to change the visibility of symbols
2023-11-24 07:15:52 -06:00
Rémi Verschelde
5be275d73b gdextension: Sync with upstream commit d6a1db2b07595f80c0f19ab01c6b4d0b66002b18 (4.2-rc2) 2023-11-24 12:36:26 +01:00
Rémi Verschelde
4fed88afcf Merge pull request #1307 from LAK132/master
Fix file list issues when trying to build with meson via cmake
2023-11-24 12:35:29 +01:00
Rémi Verschelde
7fb8acaa53 Merge pull request #1288 from bytzo/cmake-fix-persistent-debug-symbols
Make CMake only include debug symbols when appropriate
2023-11-24 12:35:22 +01:00
Rémi Verschelde
2f16eddf15 Merge pull request #1316 from bruvzg/static_multiple_init
[iOS] Fix initialisation/termination of multiple statically linked extensions.
2023-11-24 09:23:42 +01:00
bruvzg
adc9def046 [iOS] Fix initialisation/termination of multiple statically linked extensions. 2023-11-23 13:38:20 +02:00
Rémi Verschelde
32409472b7 Merge pull request #1318 from DmitriySalnikov/android_api_version
[Scons] Set the minimum Android API level to 21
2023-11-22 22:56:44 +01:00
DmitriySalnikov
79d2a9c456 [Scons] Set the minimum Android API level to 21 2023-11-23 00:28:03 +03:00
Rémi Verschelde
d0fdc3adf3 Merge pull request #1317 from godotengine/dependabot/github_actions/mymindstorm/setup-emsdk-13
Bump mymindstorm/setup-emsdk from 12 to 13
2023-11-22 22:16:15 +01:00
dependabot[bot]
78bf5a42ed Bump mymindstorm/setup-emsdk from 12 to 13
Bumps [mymindstorm/setup-emsdk](https://github.com/mymindstorm/setup-emsdk) from 12 to 13.
- [Release notes](https://github.com/mymindstorm/setup-emsdk/releases)
- [Commits](https://github.com/mymindstorm/setup-emsdk/compare/v12...v13)

---
updated-dependencies:
- dependency-name: mymindstorm/setup-emsdk
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-11-22 19:10:15 +00:00
DmitriySalnikov
f5e4f95cde [Scons] Added the ability to change the visibility of symbols 2023-11-21 18:55:02 +03:00
Rémi Verschelde
6fd4e151b8 Merge pull request #1315 from bruvzg/ios_bump_version
[iOS] Bump default version to 12 to match engine.
2023-11-21 10:37:36 +01:00
bruvzg
e854e0b592 [iOS] Bump default version to 12 to match engine. 2023-11-21 09:39:53 +02:00
Rémi Verschelde
fa10d1a303 Merge pull request #1314 from akien-mga/ci-android-ndk-r23c
CI: Install Android NDK r23c explicitly
2023-11-21 00:00:26 +01:00
Rémi Verschelde
eea33b4133 CI: Install Android NDK r23c explicitly
It has just been removed from the Ubuntu 20.04 default install,
breaking our CI setup.

Also, sets Emscripten version to 3.1.39, as done upstream.
Newer versions actually break dynamic library support.
2023-11-20 23:43:58 +01:00
Rémi Verschelde
7cd79e4cc6 gdextension: Sync with upstream commit ad72de508363ca8d10c6b148be44a02cdf12be13 (4.2-rc1) 2023-11-20 14:42:29 +01:00
David Snopek
8d17966e81 Merge pull request #1294 from dsnopek/is-connected
Fix comparison of `Callable`s from `callable_mp()` of the same method
2023-11-17 13:18:19 -06:00
David Snopek
f426b12b5b Fix comparison of Callables from callable_mp() of the same method 2023-11-17 12:49:53 -06:00
David Snopek
4439a4a569 Merge pull request #1280 from dsnopek/callable-custom
Add `CallableCustom` that devs can use in their GDExtensions
2023-11-17 12:48:39 -06:00
David Snopek
c4b7b08c91 Merge pull request #1298 from Repiteo/int-to-variant-fix
Add missing int→Variant conversions
2023-11-15 09:07:48 -06:00
Rémi Verschelde
9d528c30ee gdextension: Sync with upstream commit 64150060f89677eaf11229813ae6c5cf8a873802 (4.2-beta6) 2023-11-13 20:32:11 +01:00
Rémi Verschelde
3d22ab88a3 gdextension: Sync with upstream commit 4c96e9676b66d0cc9a25022b019b78f4c20ddc60 (4.2-beta5) 2023-11-13 20:31:34 +01:00
Rémi Verschelde
5deb29b283 gdextension: Sync with upstream commit 93cdacbb0a30f12b2f3f5e8e06b90149deeb554b (4.2-beta4) 2023-11-13 20:30:59 +01:00
Rémi Verschelde
c51c5425ba Merge pull request #1308 from akien-mga/ci-tests-timeout-import
CI: Workaround upstream issue with .NET editor build not exiting
2023-11-13 19:13:54 +01:00
Rémi Verschelde
306774b5a4 CI: Workaround upstream issue with .NET editor build not exiting
We force closing the process after 10 s, which should be ample time to generate
the .godot folder.
2023-11-13 18:51:47 +01:00
LAK132
39c139c814 Fix file list issues when trying to build with meson via cmake 2023-11-11 23:29:33 +10:30
Rémi Verschelde
73757e3a9f Merge pull request #1304 from dsnopek/revert-fix-tests-hack
Revert "Hack adding `--quit-after 100` to ensure extension_list.cfg gets generated"
2023-11-10 11:38:44 +01:00
Rémi Verschelde
adb0cfc59c Merge pull request #1302 from bruvzg/ios_static
[iOS] Fix building as static library or xcframework, add iOS config and xcframework build script to the test project.
2023-11-10 11:38:21 +01:00
bruvzg
29b34d92bb [iOS] Fix building as static library or xcframework, add iOS config and xcframework build script to the test project. 2023-11-09 20:01:59 +02:00
Rémi Verschelde
cc89bd2132 Merge pull request #1301 from brno32/master
ignoring venv in .gitignore
2023-11-09 12:42:16 +01:00
Rémi Verschelde
4af46132c2 Merge pull request #1303 from Repiteo/is_msvc-and-use_hot_reload-fix
Fix `is_msvc` and `use_hot_reload` variables
2023-11-09 12:36:11 +01:00
Thaddeus Crews
bcac96c8c2 Add missing int→Variant conversions 2023-11-08 09:45:53 -06:00
David Snopek
d239312e7b Merge pull request #1292 from Repiteo/GDCLASS-style-sync
`GDCLASS` synced by ending with "private:"
2023-11-08 16:22:46 +01:00
David Snopek
59392bc1fa Revert "Hack adding --quit-after 100 to ensure extension_list.cfg gets generated"
This reverts commit 93260e1700.
2023-11-07 15:48:25 -06:00
Alex Drozd
92dd34ae96 ignoring venv in .gitignore 2023-11-06 22:32:52 +01:00
Thaddeus Crews
648b8c4489 fix is_msvc and use_hot_reload variables 2023-11-06 10:50:19 -06:00
David Snopek
d33bd47219 Add CallableCustom that devs can use in their GDExtensions 2023-11-06 00:09:06 -06:00
David Snopek
2dfe7929de Merge pull request #1299 from dsnopek/fix-tests
Hack adding `--quit-after 100` to ensure `extension_list.cfg` gets generated
2023-11-06 07:05:58 +01:00
David Snopek
93260e1700 Hack adding --quit-after 100 to ensure extension_list.cfg gets generated 2023-11-04 17:24:36 -05:00
David Snopek
e4eee8b12d Merge pull request #1291 from m4gr3d/update_android_logic_to_retrieve_ndk_toolchain
Update the environment variables used to access the Android NDK toolchain
2023-11-03 18:31:25 -05:00
Fredia Huya-Kouadio
86dbd5fa0d Update the environment variables used to access the Android NDK toolchain 2023-11-01 12:14:55 -07:00
Thaddeus Crews
6eb5d450bd GDCLASS synced by ending with "private:"
• Matches implementation used by modules and godot itself
• Apply same to GDEXTENSION_CLASS, setup with same diff-friendly spacers as GDCLASS
2023-11-01 12:44:14 -05:00
Bytzo
db884e9b1d Prevent CMake from always including debug symbols 2023-10-25 23:57:13 -07:00
David Snopek
c1196a1ab0 Merge pull request #1286 from dsnopek/callable-custom-object-id
Switch to using `ObjectID` in custom callables
2023-10-25 15:13:22 -05:00
David Snopek
4b76485a4e Switch to using ObjectID in custom callables 2023-10-25 13:05:32 -05:00
Rémi Verschelde
f79bd795d5 gdextension: Sync with upstream commit e8d57afaeccf0d9f9726746f49936eb93aa0039b (4.2-beta3) 2023-10-24 22:58:57 +02:00
Rémi Verschelde
1ab94699c5 Merge pull request #1277 from dsnopek/variant-iter-tests
Add an automated test using a Variant iterator
2023-10-24 22:30:42 +02:00
David Snopek
c82f2a3714 Merge pull request #1279 from dsnopek/gdclass-protections
Add protections against registering classes that didn't use `GDCLASS()`
2023-10-22 10:07:41 -05:00
David Snopek
edb52293d9 Merge pull request #1278 from dsnopek/gdextension-callable-bind-test
Add test for `Callable.bind()`
2023-10-22 10:07:09 -05:00
David Snopek
379ce2b5e5 Merge pull request #1216 from akien-mga/scons-disable-exception-handling
SCons: Disable C++ exception handling by default
2023-10-22 10:06:34 -05:00
David Snopek
a61cdc8860 Add protections against registering classes that didn't use GDCLASS() 2023-10-22 08:44:09 -05:00
Rémi Verschelde
bf1c03ab5f SCons: Disable C++ exception handling by default
Counterpart to https://github.com/godotengine/godot/pull/80612.
2023-10-22 12:45:46 +02:00
David Snopek
421c61e730 Add test for Callable.bind() 2023-10-21 17:42:10 -05:00
David Snopek
d733663e8b Add an automated test using a Variant iterator 2023-10-20 12:58:00 -05:00
David Snopek
0a6a19e33b Merge pull request #1253 from gilzoide/fix-variant-iteration-valid-flag
Fix return value and `r_valid` value in `Variant::iter_init` and `Variant::iter_next`
2023-10-20 10:39:05 -05:00
Rémi Verschelde
5182624141 gdextension: Sync with upstream commit f8818f85e6c43cdf1277e8ae85eba19ca0a003b0 (4.2-beta2) 2023-10-20 08:40:49 +02:00
David Snopek
7a260f5e93 Merge pull request #1230 from adamscott/compiledb-alias
Refactor compiledb implementation
2023-10-19 14:34:17 -05:00
Adam Scott
2d5024ac8e Refactor compiledb implementation
This comment enables the possibility to build the "compile_commands.json"
file by only using `scons -Q compiledb`. No need to use the argument
`compiledb=yes`.

And when using the `compiledb=yes`, it will create a
"compiled_commands.json" automatically.
2023-10-19 10:51:31 -04:00
David Snopek
7a3cfe8089 Merge pull request #1275 from capnm/fix-clang-virt_destructor-warning
clang: Add CallableCustomMethodPointerBase virtual destructor
2023-10-19 09:06:45 -05:00
David Snopek
5c4a7dc7b2 Merge pull request #1258 from Repiteo/standalone-gdextension_dir
Let `gdextension_dir` function as standalone argument
2023-10-19 09:06:12 -05:00
Martin Capitanio
a926b96103 clang: Add CallableCustomMethodPointerBase virtual destructor
Fixes #1272
+ clang++ (debian v16/v17) warning:
	destructor called on
	'godot::CallableCustomMethodPointerBase' that is abstract but has non-virtual destructor
	[-Wdelete-abstract-non-virtual-dtor]
2023-10-19 09:37:11 +02:00
Thaddeus Crews
7a5cbcac21 Let gdextension_dir function as only argument 2023-10-18 11:32:51 -05:00
David Snopek
64eac01d04 Merge pull request #1266 from dsnopek/automatic-engine-class-registration
Automatically register only engine classes whose header has been included
2023-10-16 10:47:06 -05:00
David Snopek
b507b3e591 Automatically register only engine classes whose header has been included 2023-10-16 10:19:11 -05:00
David Snopek
4320c62c76 Merge pull request #1270 from Faless/build/web_rename
[SCons] Rename javascript tool to web
2023-10-15 09:49:53 -05:00
Fabio Alessandrelli
18bfa133ab [SCons] Rename javascript tool to web
And clean it up a bit.
2023-10-15 13:12:49 +02:00
Rémi Verschelde
c4d3f019da gdextension: Sync with upstream commit b1371806ad3907c009458ea939bd4b810f9deb21 (4.2-beta1) 2023-10-12 18:10:11 +02:00
Rémi Verschelde
4f0eb2f520 Merge pull request #1263 from dsnopek/string-name-new
Use the new `string_name_new_with_latin1_chars` function to improve StringName construction performance
2023-10-12 18:08:09 +02:00
David Snopek
292a50dd08 Merge pull request #1265 from mihe/char-string-specializations
Declare explicit specializations for `CharStringT`
2023-10-12 10:47:06 -05:00
Mikael Hermansson
6e05b978b8 Declare explicit specializations for CharStringT 2023-10-12 16:00:48 +02:00
Rémi Verschelde
55618ebf58 Merge pull request #1264 from dsnopek/misc-gdextension-interface-changes
Miscellaneous updates to gdextension_interface.h
2023-10-12 09:19:23 +02:00
David Snopek
29248c31ae Miscellaneous updates to gdextension_interface.h 2023-10-11 21:42:05 -05:00
David Snopek
3d814f9e4a Use the new string_name_new_with_latin1_chars function to improve StringName construction performance 2023-10-09 16:59:29 -05:00
David Snopek
ef2f63a00c Merge pull request #1260 from Klaim/master
Fixes crash in ClassDB::deinitialize due to usage of invalid iterator.
2023-10-05 11:07:11 -05:00
Joël Lamotte (Klaim)
5134c82573 Fixes crash in ClassDB::deinitialize due to usage of invalid iterator.
After the removed call to `std::vector::erase` all iterators,
`i` included, are invalidated and therefore this code has undefined
behavior (which can or not lead to a crash).
This change delays the removal of class names from
`class_register_order` to after having gone through it's content,
removing the undefined behavior.
2023-10-05 16:58:49 +02:00
David Snopek
cd61a9bbe8 Merge pull request #1257 from dsnopek/script-class-category
Update for `get_class_category` added to `GDExtensionScriptInstanceInfo2`
2023-10-04 11:17:41 -05:00
David Snopek
96bec613a0 Merge pull request #1247 from nicholas-maltbie/nickmaltbie/javascript-wasm-fix
Javascript Web WASM Fix
2023-10-04 09:58:01 -05:00
David Snopek
6ad187cc7e Update for get_class_category added to GDExtensionScriptInstanceInfo2 2023-10-04 09:19:45 -05:00
Rémi Verschelde
98737b2678 Merge pull request #1259 from akien-mga/ci-fix-mingw-install-error
CI: Fix MinGW install error by pinning to earlier version
2023-10-04 15:20:37 +02:00
Rémi Verschelde
0369f6fea0 CI: Fix MinGW install error by pinning to earlier version
Works around https://github.com/egor-tensin/setup-mingw/issues/14.
2023-10-04 13:42:49 +02:00
Nick Maltbie
2b4bcbb0ce Added fix for javascript build for godot 4.x
Added changes to tools/javascript.py to add PFlags to fix SharedArrayBuffer memory error.
Corrected some small errors in tools/javascript.py to support new target names.
Also updated ci to include validation for web build.
2023-10-01 13:43:19 -07:00
David Snopek
bf2f9e2f55 Merge pull request #1200 from dsnopek/hot-reload
Changes necessary for hot reload to work
2023-09-26 08:38:12 -05:00
David Snopek
df849651d9 Changes necessary for hot reload to work 2023-09-25 22:13:33 -05:00
gilzoide
60dfa3445a Fix return value and r_valid value in Variant::iter_init and iter_next 2023-09-24 17:10:29 -03:00
David Snopek
c44c3d5ebf Merge pull request #1155 from dsnopek/callable-mp
Implement `callable_mp()` and `callable_mp_static()`
2023-09-21 16:20:21 -05:00
David Snopek
c18c1916c3 Implement callable_mp() and callable_mp_static() 2023-09-21 15:17:50 -05:00
David Snopek
4314f91b7d Merge pull request #1238 from dsnopek/variant-call-callp
Fix variant call compiler error (alternate)
2023-09-21 15:07:05 -05:00
David Snopek
db15731e4d Merge pull request #1165 from dsnopek/missing-classes
Handle missing instance binding callbacks by finding the closest parent
2023-09-21 15:06:51 -05:00
David Snopek
381df0081a Merge pull request #1220 from adamscott/add-local-custom-support-redux
Add support to import custom variables from parent SConstruct (redux)
2023-09-21 15:06:30 -05:00
David Snopek
a963b8b7c7 Merge pull request #1246 from dsnopek/virtual-call-data
Update for addition of `get_virtual_call_data_func` and `call_virtual_func` to `GDExtensionClassCreationInfo2`
2023-09-20 14:16:43 -05:00
David Snopek
3a02feddc3 Update for addition of get_virtual_call_data_func and call_virtual_func to GDExtensionClassCreationInfo2 2023-09-20 12:15:31 -05:00
David Snopek
a3dfbbde85 Merge pull request #1245 from AThousandShips/alloc_fix
Fix allocation size overflow check in `CowData`
2023-09-20 07:39:27 -05:00
David Snopek
b1fd1b65fd Merge pull request #1242 from AThousandShips/null_check
Replace `ERR_FAIL_COND` with `ERR_FAIL_NULL` where applicable
2023-09-20 07:32:14 -05:00
David Snopek
52ca3ef547 Handle missing instance binding callbacks by finding the closest parent 2023-09-19 10:54:07 -05:00
David Snopek
0d6de7a80e Merge pull request #1164 from dsnopek/classdb-singleton-alternate
Add static methods to `ClassDB` for the methods bound to the `ClassDB` singleton
2023-09-19 10:33:15 -05:00
A Thousand Ships
06ffc7e952 Fix allocation size overflow check in CowData 2023-09-19 16:14:00 +02:00
David Snopek
73500966ae Merge pull request #1243 from dsnopek/load-print-error-with-message
Load 'print_error_with_message' function
2023-09-15 15:29:33 -05:00
David Snopek
634ed09ec0 Load 'print_error_with_message' function 2023-09-15 14:08:27 -05:00
A Thousand Ships
1e5767693e Replace ERR_FAIL_COND with ERR_FAIL_NULL where applicable 2023-09-13 14:34:04 +02:00
Rémi Verschelde
6caf4909d4 Merge pull request #1239 from dsnopek/gdextension-validate-property-object
Support `_validate_property()`
2023-09-13 13:44:22 +02:00
David Snopek
aa6867e6c9 Support _validate_property() 2023-09-12 13:21:16 -05:00
David Snopek
16ffb2795a Merge pull request #970 from Daylily-Zeleen/daylily-zeleen/register_unexposed_class
Implement register unexposed classes
2023-09-11 09:35:32 -05:00
Matthew Murphy
ca3e25de04 Fix variant call compiler error
Co-authored-by: David Snopek <dsnopek@gmail.com>
2023-09-09 11:30:29 -05:00
David Snopek
b488f009bd Merge pull request #1208 from dsnopek/check-godot-version
Check that GDExtension is opened by compatible Godot version
2023-09-09 09:30:36 -05:00
David Snopek
80f98de905 Merge pull request #1237 from DmitriySalnikov/fix-scons-crashes
[SCons] Fixed crashes in several scripts
2023-09-09 09:19:38 -05:00
DmitriySalnikov
0e5975dd26 [SCons] Fixed crashes in several scripts 2023-09-09 12:44:14 +03:00
David Snopek
5cdc2fc099 Merge pull request #1214 from dsnopek/ptrtoarg-native-struct
Ensure that PtrToArg specializations for native structs are used
2023-09-08 10:12:23 -05:00
David Snopek
adcc95534b Merge pull request #1231 from godotengine/dependabot/github_actions/actions/checkout-4
Bump actions/checkout from 3 to 4
2023-09-07 17:46:16 -05:00
David Snopek
82e960a810 Merge pull request #1233 from AThousandShips/wrapper_fix
Ensure `const` correctness for wrappers
2023-09-07 08:27:38 -05:00
A Thousand Ships
f651df5e7a Ensure const correctness for wrappers 2023-09-06 19:33:03 +02:00
dependabot[bot]
5d4ff63930 Bump actions/checkout from 3 to 4
Bumps [actions/checkout](https://github.com/actions/checkout) from 3 to 4.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v3...v4)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-09-04 19:13:12 +00:00
Adam Scott
982e01ec7f Add support to import custom variables from parent SConstruct (redux) 2023-09-04 15:05:52 -04:00
Daylily-Zeleen
2d1f852baf Implement register unexposed class. 2023-09-04 00:59:10 +08:00
David Snopek
0db95a92a6 Merge pull request #1228 from Bromeon/bugfix/yet-another-bool
GDExtension: fix `bool` unknown in C
2023-09-02 16:13:51 -05:00
David Snopek
8990d5a40e Merge pull request #1091 from Daylily-Zeleen/daylily-zeleen/implement_builtin_classes_vararg_methods
Implement vararg methods of builtin classes.
2023-09-02 08:04:29 -05:00
Jan Haller
54092861f1 GDExtension: fix bool unknown in C 2023-09-02 13:19:14 +02:00
David Snopek
9ada7065d6 Merge pull request #1226 from AThousandShips/version_str
Fix formatting of `compatibility_minimum` examples
2023-08-31 08:17:51 -05:00
A Thousand Ships
b3596a18e1 Fix formatting of compatibility_minimum examples
Without quotes the values is parsed as a float, breaking in various
cases.
2023-08-31 12:45:11 +02:00
David Snopek
9a6c741d5d Merge pull request #1151 from Sauermann/fix-notification-order
Fix `Object::notification` order (cpp-bindings)
2023-08-30 14:19:51 -05:00
Markus Sauermann
c2d99fd519 Fix Object::notification order
For the notification-order to work correctly, it is necessary to
allow the `p_reversed` argument to be used within cpp.
This PR changes the necessary bindings.
2023-08-30 00:07:28 +02:00
David Snopek
dd9586b841 Merge pull request #1190 from Faless/build/godotcpp_tool
[SCons] Move the GodotCPP build to its own tool.
2023-08-29 13:07:38 -05:00
Fabio Alessandrelli
f8b4f60cb9 [SCons] Move the GodotCPP build to its own tool. 2023-08-29 18:14:42 +02:00
David Snopek
6d9416eb17 Merge pull request #1225 from dsnopek/placeholder-script-instance
Add support for placeholder_script_instance_create/update
2023-08-29 09:39:05 -05:00
David Snopek
f0405f18a3 Add support for placeholder_script_instance_create/update 2023-08-28 17:02:13 -05:00
Rémi Verschelde
c370f0f24a Merge pull request #1221 from dsnopek/readme-improvements
Clarify versions and examples in the README
2023-08-17 17:14:07 +02:00
David Snopek
1588dc8437 Clarify versions and examples in the README 2023-08-17 09:39:13 -05:00
David Snopek
a7d3f00b26 Merge pull request #1218 from AThousandShips/readme_fix
Fix link to test project in readme
2023-08-17 06:27:11 -05:00
A Thousand Ships
e586e11637 Fix link to test project in readme
Also updated format for library paths
2023-08-17 10:51:12 +02:00
David Snopek
7ed7a84782 Merge pull request #1197 from AThousandShips/vec_elem
Add remaining component-wise `min/max` functions to `Vector*`
2023-08-16 16:45:33 -05:00
David Snopek
112e41bd8f Merge pull request #1204 from akien-mga/scons-targets-sync-with-godot
SCons: Sync `targets.py` fully with upstream Godot
2023-08-16 10:02:54 -05:00
A Thousand Ships
52eb77efd4 Add remaining component-wise min/max functions to Vector* 2023-08-16 13:52:51 +02:00
Rémi Verschelde
74b352e979 Merge pull request #1215 from adamscott/fix-deprecated-builtins-clang-2
Fix forgotten not operator
2023-08-16 12:29:56 +02:00
Adam Scott
f5c8e5190f Fix forgotten not operator 2023-08-16 05:30:40 -04:00
Rémi Verschelde
524bbd3ee9 Merge pull request #1211 from adamscott/fix-deprecated-builtins-clang
Fix Clang deprecated builtins
2023-08-16 09:12:41 +02:00
David Snopek
3cd3f24150 Ensure that PtrToArg specializations for native structs are used 2023-08-15 17:54:11 -05:00
Adam Scott
5c262844ad Fix Clang deprecated builtins
It seems that Clang and GCC have different interpretations of certain
builtins. So this PR uses std <type_traits> functions just as cowdata.h
does in the godot project.
2023-08-15 18:50:47 -04:00
Rémi Verschelde
df5500565a Merge pull request #1209 from dsnopek/missing-tests
Add automated tests to verify some previous fixes
2023-08-15 09:30:21 +02:00
David Snopek
d5fab0b9f8 Add automated tests to verify some previous fixes 2023-08-14 20:48:51 -05:00
David Snopek
fecb2959b4 Check that GDExtension is opened by compatible Godot version 2023-08-14 17:01:12 -05:00
David Snopek
5eebc6b20c Merge pull request #1193 from Zylann/version_header
Added generated version header
2023-08-11 10:33:49 -05:00
Rémi Verschelde
600e749d9b SCons: Sync targets.py fully with upstream Godot
- Reorders existing code to match Godot.
- Adds `NDEBUG` for non-dev builds.
- Adds `-gdwarf-4` for Clang debug symbols.
- Adds strip link flag for GCC/Clang builds without debug symbols.
2023-08-10 09:23:32 +02:00
David Snopek
c47bd60c73 Merge pull request #1203 from dsnopek/1082-update
Statically link mingw/msvc runtime libraries on Windows
2023-08-09 18:53:16 -05:00
Feiyun Wang
a745c2ac47 Statically link mingw/msvc runtime libraries on Windows
Co-authored-by: David Snopek <dsnopek@gmail.com>
2023-08-09 13:38:38 -05:00
David Snopek
5834e16a22 Merge pull request #1166 from dsnopek/string-resize
Implement `String::resize()` in godot-cpp
2023-07-31 18:31:24 -05:00
David Snopek
6f913563d8 Add static methods to ClassDB for the methods bound to the ClassDB singleton 2023-07-31 16:04:27 -05:00
David Snopek
845226d66a Merge pull request #1191 from Faless/build/unify_osxcross
[SCons] Merge OSXCross tools into platform ones
2023-07-31 15:40:27 -05:00
David Snopek
d168dd021e Merge pull request #1189 from Faless/build/compiledb
[SCons] Add option to generate a compilation database.
2023-07-31 15:39:07 -05:00
David Snopek
494b51698d Merge pull request #1188 from adamscott/add-platform-macros
Add platform macros
2023-07-31 15:38:47 -05:00
David Snopek
8bc1c1dbeb Implement String::resize() 2023-07-31 15:14:10 -05:00
David Snopek
c5d8447861 Merge pull request #1181 from Zylann/fix_singleton_caching
Don't cache `null` forever if a singleton isn't available yet
2023-07-26 21:09:10 -05:00
Marc Gilleron
c6b2c82570 Added generated version header 2023-07-26 23:23:56 +01:00
David Snopek
1d49bef096 Merge pull request #1184 from Zylann/fix_get_property_list_calling_parent
Don't call parent _get_property_list when a class doesn't define it (for internal binding).
2023-07-26 15:31:15 -05:00
David Snopek
d15550fdee Merge pull request #1186 from mihe/indexed-properties
Add support for indexed properties
2023-07-26 14:22:34 -05:00
Marc Gilleron
baf0b9e0f7 Don't call parent _get_property_list when a class doesn't define it.
Godot is already supposed to call _get_property_list of parent classes,
so this binding function must really only return procedural properties of
the class it belongs to, and not parent or child classes.
2023-07-26 20:12:25 +01:00
Mikael Hermansson
7d8cb7c155 Add support for indexed properties 2023-07-26 00:31:53 +02:00
Adam Scott
9d9f4279ed Add platform macros 2023-07-23 19:23:01 -04:00
Fabio Alessandrelli
6d195137fe [SCons] Merge OSXCross tools into platofrm ones 2023-07-23 22:54:07 +02:00
Fabio Alessandrelli
2586ad016e [SCons] Add option to generate a compilation database. 2023-07-22 20:04:30 +02:00
Marc Gilleron
548c758677 Don't cache null forever if a singleton isn't available yet
# Conflicts:
#	binding_generator.py
2023-07-22 16:31:28 +01:00
David Snopek
3162be28e5 Merge pull request #1150 from dsnopek/charstring-full
Attempt to fully implement CharString
2023-07-22 09:04:27 -05:00
David Snopek
ef5a185dc4 Merge pull request #1176 from dsnopek/string-name-allocate-once
In generated methods, only allocate the method StringName the first time
2023-07-22 09:04:13 -05:00
Yuri Sizov
1009da4d7e gdextension: Sync with upstream commit bd6af8e0ea69167dd0627f3bd54f9105bda0f8b5 (4.1.1-stable) 2023-07-17 20:10:45 +02:00
David Snopek
749b0b9ae0 Merge pull request #1172 from adamscott/add-cache-dir-gitignore
Add lower-case "*.cache" in ".gitignore"
2023-07-14 11:41:03 -05:00
David Snopek
67bd2eac44 Merge pull request #1170 from adamscott/import-env-if-exists
Import `env` if possible
2023-07-14 11:40:52 -05:00
David Snopek
a9209ce881 Merge pull request #1175 from bruvzg/msvc_force_utf8
[MSVC] Force UTF-8 encoding.
2023-07-14 06:49:42 -05:00
David Snopek
efc16b49d9 In generated methods, only construct the method StringName the first time 2023-07-13 13:05:41 -05:00
bruvzg
d1aeba771a [MSVC] Force UTF-8 encoding. 2023-07-11 16:11:51 +03:00
Adam Scott
8155f35b29 Import env if possible
This PR make it possible to import `env` and use it instead of creating
one from scratch every time.

Handy because we encourage users to use the godot-cpp SConstruct file as
a base to their projects (see the test project). So, if a project want
to override specific settings, (eg. make a path local to their SConstruct
file, not local to the godot-cpp/SConstruct file), it can do so.
2023-07-11 04:41:55 -04:00
Adam Scott
67501f1ee2 Add lower-case "*.cache" in ".gitignore" 2023-07-09 12:13:34 -04:00
Rémi Verschelde
d627942b64 gdextension: Sync with upstream commit 970459615f6b2b4151742ec6d7ef8559f87fd5c5 (4.1-stable) 2023-07-05 16:31:31 +02:00
Rémi Verschelde
d2b8ff4e9c gdextension: Sync with upstream commit cdd2313ba27d0a2600a18e849b4c5d1fd6a6e351 (4.1-rc3) 2023-07-04 13:42:41 +02:00
Daylily-Zeleen
3536803e9e Implement vararg methods of builtin classes. 2023-07-03 17:30:42 +08:00
Rémi Verschelde
ff6f5792d2 Merge pull request #1159 from mihe/unused-exports
Remove unused free-standing `initialize_level` and `deinitialize_level`
2023-07-01 00:33:09 +02:00
Mikael Hermansson
4b1072e4da Remove unused free-standing initialize_level and deinitialize_level 2023-06-30 19:36:46 +02:00
Rémi Verschelde
3e44ad1867 Merge pull request #1157 from Faless/feat/rpc_test
Add RPC tests.
2023-06-30 15:50:03 +02:00
Fabio Alessandrelli
155f2e2a62 Add RPC tests. 2023-06-30 15:07:42 +02:00
Rémi Verschelde
80986f8497 gdextension: Sync with upstream commit 46424488edc341b65467ee7fd3ac423e4d49ad34 (4.1-rc2) 2023-06-30 10:02:54 +02:00
Rémi Verschelde
a4784e12b9 gdextension: Sync with upstream commit ada712e06a471da2a2f4646237830bbd7980c114 (4.1-rc1) 2023-06-29 09:51:49 +02:00
David Snopek
4df112cd95 Attempt to fully implement CharString 2023-06-22 21:03:30 -05:00
Rémi Verschelde
bfc9e0bd93 gdextension: Sync with upstream commit ada712e06a471da2a2f4646237830bbd7980c114 (4.1-beta3) 2023-06-21 15:58:41 +02:00
David Snopek
2377f7ec75 Merge pull request #1047 from Kehom/master
Unregister custom classes in reverse registration order
2023-06-20 08:24:56 -05:00
Kehom
20be441026 Unregister custom classes in reverse registration order 2023-06-19 11:04:11 -03:00
Rémi Verschelde
82edc89cfa Merge pull request #1148 from Bromeon/bugfix/uninit-ptr-signature
GDExtension: `Uninitialized*Ptr` for constructors/converters using placement new
2023-06-19 10:43:58 +02:00
Rémi Verschelde
130644c061 Merge pull request #1138 from dsnopek/editor-plugins-deinitialize
Automatically remove editor plugins when deinitializing GDExtension
2023-06-19 10:43:34 +02:00
Rémi Verschelde
ca78bcf558 Merge pull request #1086 from lucasrafael98/fixes/missing-include-audio-frame
Fix: Include method_ptrcall.hpp on simple structs.
2023-06-19 10:43:10 +02:00
Jan Haller
2d4ec829a0 GDExtension: Uninitialized*Ptr for constructors/converters using placement new
These methods construct their destination in-place, but the parameters are not declared using the `Uninitialized*Ptr` pointer types.
2023-06-18 23:11:12 +02:00
Rémi Verschelde
f56f45156b Merge pull request #1143 from bruvzg/py_utf8
Force UTF-8 encoding in the binding generator script.
2023-06-16 10:30:08 +02:00
Rémi Verschelde
f0065bd801 Merge pull request #1048 from asmaloney/reserved_identifiers
Identifiers containing double underscore are reserved according to the C++ standard
2023-06-16 10:29:45 +02:00
bruvzg
f1ad719ffc Force UTF-8 encoding in the binding generator script. 2023-06-16 10:41:23 +03:00
Andy Maloney
db2394dbe7 Identifiers containing double underscore are reserved according to the C++ standard
Rename __* to _gde_*

https://timsong-cpp.github.io/cppwp/n3337/global.names

https://en.cppreference.com/w/cpp/language/identifiers

Identifiers appearing as a token or preprocessing token (i.e., not in user-defined-string-literal like operator ""id) (since C++11) of one of the following forms are reserved:
 - identifiers with a double underscore anywhere;
 - identifiers that begin with an underscore followed by an uppercase letter;
 - in the global namespace, identifiers that begin with an underscore.
2023-06-15 20:45:01 -04:00
Rémi Verschelde
1bc9ca7b57 Merge pull request #1139 from Trey2k/master
Prepend PATH to scons env to allow use of buildroot
2023-06-15 10:58:13 +02:00
Trey Moller
6f7e80bbb6 Prepend PATH to scons env 2023-06-14 10:30:24 -05:00
Rémi Verschelde
be25a50617 gdextension: Sync with upstream commit a2575cba48121a9e31c3a550ebd29398a7facf3f (4.1-beta2) 2023-06-14 10:05:18 +02:00
David Snopek
d28a3cbbd5 Automatically remove editor plugins when deinitializing GDExtension 2023-06-13 14:24:33 -05:00
Rémi Verschelde
d12cf071bb Merge pull request #1128 from Mathis-Z/master
Fixing #1127 by making return types of auto-generated functions dynamic
2023-06-08 22:31:51 +02:00
Mathis-Z
ac98dd2752 Fixing #1127 by making return types of auto-generated functions dynamic 2023-06-08 20:35:29 +02:00
David Snopek
ee5cf3a11d Merge pull request #1137 from dsnopek/no-more-legacy-mode
Clarify error message because there isn't a legacy Godot 4.0 mode anymore
2023-06-08 10:11:29 -05:00
David Snopek
3074d22815 Clarify error message because there isn't a legacy Godot 4.0 mode anymore 2023-06-08 09:42:03 -05:00
Rémi Verschelde
92a139d31e Merge pull request #1129 from dsnopek/interface-print-error
Correctly load gdextension_interface_print_error
2023-06-08 16:01:40 +02:00
Rémi Verschelde
b5a3aeb8ee Merge pull request #1123 from dsnopek/revert-pr-1044-1045
Revert the changes from PR #1044 and #1045 and standardize on `Object **` encoding in ptrcall
2023-06-07 17:30:44 +02:00
David Snopek
ad726015e7 Revert the changes from PR #1044 and #1045 and standardize on Object ** encoding in ptrcall 2023-06-07 08:30:33 -05:00
Rémi Verschelde
c669f0b78a gdextension: Sync with upstream commit 828ec2c5d005b6499c7c4c88beaf81767d05614b (4.1-beta1) 2023-06-07 13:23:12 +02:00
David Snopek
59bffc94a8 Correctly load gdextension_interface_print_error 2023-05-31 01:32:44 -05:00
David Snopek
aef9ea7387 Merge pull request #1113 from Calinou/add-issue-template
Add issue template based on the main Godot repository
2023-05-26 17:00:25 -05:00
David Snopek
0c466ddb67 Merge pull request #1117 from dsnopek/sync-gdextension-interface
Synchronize gdextension_interface.h with Godot
2023-05-26 17:00:13 -05:00
David Snopek
6347ce2550 Synchronize gdextension_interface.h with Godot 2023-05-26 15:43:50 -05:00
Rémi Verschelde
2078c00bab Merge pull request #1114 from dsnopek/editor-plugins
Add support for adding/removing editor plugins
2023-05-26 11:04:35 +02:00
Hugo Locurcio
e7c57a39db Add issue template based on the main Godot repository 2023-05-25 15:59:33 +02:00
David Snopek
2e45bd8373 Merge pull request #1101 from dsnopek/better-tests
Add automated tests that run a GDExtension (rather than just building it)
2023-05-24 21:18:12 -05:00
David Snopek
0d0d5a670b Merge pull request #1116 from saki7/Ref-allow-non-const-access
Change Ref<T> to allow non const access to ptr
2023-05-24 21:17:25 -05:00
David Snopek
8052f818b4 Merge pull request #1050 from dsnopek/object-correct-class
Ensure GDExtension class is the correct type for the Godot engine class
2023-05-24 21:17:12 -05:00
David Snopek
08bc2ef680 Merge pull request #1115 from dgcole/master
Update Getting Started section of README.md
2023-05-24 21:16:28 -05:00
dgcole
6f0649a86d Update getting started section of README.md 2023-05-24 21:49:55 -04:00
David Snopek
1fd3f82d3a Add automated tests that run a GDExtension (rather than just building it) 2023-05-17 14:08:12 -05:00
Nana Sakisaka
48635729b9 Change Ref<T> to allow non const access to ptr 2023-05-17 19:24:09 +09:00
David Snopek
e75ebffb70 Add support for adding/removing editor plugins 2023-05-16 22:02:35 -05:00
David Snopek
431e30bc32 Ensure GDExtension class is the correct type for the Godot engine class 2023-05-16 15:18:48 -05:00
Rémi Verschelde
1c18413de0 Merge pull request #1095 from dsnopek/gdextension-interface
Update to load function pointers for GDExtension interface
2023-05-16 17:26:31 +02:00
Hugo Locurcio
813827c26a Merge pull request #1108 from sasichkamega/master 2023-05-12 19:58:34 +02:00
David Snopek
a5c6ca5920 Update to load function pointers for GDExtension interface 2023-05-09 21:45:48 -05:00
Alex
7f94f90b01 Update CMakeLists.txt 2023-05-06 09:55:41 +03:00
Lucas Rafael
cb0b105402 Fix: Include method_ptrcall.hpp on simple structs. 2023-04-07 18:53:07 +01:00
Rémi Verschelde
feaba551b5 Merge pull request #1045 from zhehangd/fix_ref_crash
Fix crash using Ref<T> as parameter
2023-04-04 11:30:08 +02:00
Rémi Verschelde
e9942db502 Merge pull request #1044 from zhehangd/fix_obj_ptr_crash
Fix crash using Object* as parameter
2023-04-01 11:36:17 +02:00
Zhehang Ding
093f0673f5 Fix PtrToArg<Object*> crash 2023-03-30 19:38:12 -07:00
Rémi Verschelde
9d1c396c54 gdextension: Sync with upstream commit 92bee43adba8d2401ef40e2480e53087bcb1eaf1 (4.0-stable) 2023-03-01 15:32:44 +01:00
Rémi Verschelde
e31e15bb3b Add compatibility warning: godot-cpp is still in beta 2023-03-01 15:32:36 +01:00
Rémi Verschelde
1f1a373041 gdextension: Sync with upstream commit 0cd148313213e2923004be65bafd6a3781c917ec (4.0-rc6) 2023-02-27 08:55:28 +01:00
Rémi Verschelde
4f2b1ed2e8 gdextension: Sync with upstream commit 6296b46008fb8d8e5cb9b60af05fa1ea26b8f600 (4.0-rc5) 2023-02-25 01:16:11 +01:00
Rémi Verschelde
c2c5c85ef4 gdextension: Sync with upstream commit e0de3573f3fc86062763152f5a1ac62f5a986da3 (4.0-rc4) 2023-02-23 18:05:21 +01:00
Rémi Verschelde
c1ff169bf3 gdextension: Sync with upstream commit 7e79aead99a53ee7cdf383add9a6a2aea4f15beb (4.0-rc3) 2023-02-21 21:38:17 +01:00
Rémi Verschelde
2a15286060 Merge pull request #1053 from bruvzg/fix_release_memalloc
Fix incorrect memory allocation in release builds.
2023-02-21 14:51:15 +01:00
bruvzg
ba4b50118d Fix incorrect memory allocation in release builds.
Co-authored-by: lightyears <lightyears1998@hotmail.com>
2023-02-21 15:32:26 +02:00
Rémi Verschelde
2f07eb07ee Merge pull request #1046 from dsnopek/revert-fix-object-cast-to
Revert "Fix Object::cast_to<T>() for custom classes"
2023-02-20 10:09:53 +01:00
David Snopek
964c515d75 Revert "Fix Object::cast_to<T>() for custom classes"
This reverts commit 75af9003dc.
2023-02-16 06:58:32 -06:00
Zhehang Ding
517db6686a Fix PtrToArg<Ref<T>> crash 2023-02-15 22:36:29 -08:00
Rémi Verschelde
f5133c08a5 Merge pull request #1040 from zhehangd/fix_const_str_ptr
Fix compilation error: const GDExtensionStringPtr -> GDExtensionConst…
2023-02-15 10:16:49 +01:00
Zhehang Ding
07c914b479 Fix compilation error: const GDExtensionStringPtr -> GDExtensionConstStringPtr 2023-02-14 18:53:11 -08:00
Rémi Verschelde
0068320ff1 gdextension: Sync with upstream commit d2699dc7ab96fbd75faccc1f32f55baebf1d84dc (4.0-rc2) 2023-02-14 19:12:02 +01:00
Rémi Verschelde
8a3faaa649 Merge pull request #1037 from dsnopek/fix-object-cast-to
Fix Object::cast_to<T>() for custom classes
2023-02-14 19:11:29 +01:00
David Snopek
75af9003dc Fix Object::cast_to<T>() for custom classes 2023-02-11 17:16:59 -06:00
Rémi Verschelde
f9ccf28374 Merge pull request #1034 from Bromeon/qol/array-set-typed
`array_set_typed()` now called with `GDExtensionVariantType` instead of `uint32_t`
2023-02-09 11:29:45 +01:00
Jan Haller
706006ec83 Update array_set_typed() call to use GDExtensionVariantType instead of uint32_t 2023-02-09 11:12:51 +01:00
Rémi Verschelde
516fad14e4 gdextension: Sync with upstream commit c4fb119f03477ad9a494ba6cdad211b35a8efcce (4.0-rc1) 2023-02-08 14:47:21 +01:00
Rémi Verschelde
52e63ddd22 Merge pull request #975 from asmaloney/cmake-static-and-pic
{cmake} Use STATIC and POSITION_INDEPENDENT_CODE
2023-02-08 14:46:32 +01:00
Andy Maloney
2379034958 {cmake} Use STATIC and POSITION_INDEPENDENT_CODE
Instead of specifying flags manually, use CMake.
2023-02-07 10:24:25 -05:00
Rémi Verschelde
50e97de636 Merge pull request #1008 from asmaloney/cmake-compiler-warnings
{cmake} Use the same compiler warnings as godot
2023-02-07 14:00:04 +01:00
Rémi Verschelde
99f6de1dfc Merge pull request #1029 from asmaloney/cmake-combine-includes
{cmake} Combine target_include_directories
2023-02-07 13:49:25 +01:00
Rémi Verschelde
0704528b4c Merge pull request #1027 from Daylily-Zeleen/daylily-zeleen/fix_global_enum_cast
Fix global enum cast and add `Varint::Type`'s cast.
2023-02-07 13:48:58 +01:00
Rémi Verschelde
e72bc1a12f Merge pull request #1028 from asmaloney/fix-improper-conversion
Fix improper implicit conversion
2023-02-07 13:48:54 +01:00
Rémi Verschelde
9607a51b52 Merge pull request #1030 from asmaloney/constify
ExampleRef::get_id() should be const
2023-02-07 13:48:38 +01:00
Rémi Verschelde
fccceb8736 Merge pull request #1011 from mihe/error-macros
Update error macros to match core
2023-02-07 13:47:51 +01:00
Andy Maloney
d081b4bab6 {cmake} Use the same compiler warnings as godot 2023-02-04 11:18:19 -05:00
Andy Maloney
b01f0cf99b ExampleRef::get_id() should be const 2023-02-02 13:01:31 -05:00
Andy Maloney
2a221300de {cmake} Combine target_include_directories
Makes all include directories consistent.

Turns GODOT_CPP_SYSTEM_HEADERS ON by default since that's what was already being done for ${GODOT_GDEXTENSION_DIR}.
2023-02-02 12:58:03 -05:00
Andy Maloney
f2cb5a7414 Fix improper implicit conversion 2023-02-02 11:30:37 -05:00
Daylily-Zeleen
a614f61015 Fix global enum cast and add Varint::Type cast. 2023-02-02 16:42:15 +08:00
Rémi Verschelde
f2b97528c1 gdextension: Sync with upstream commit c40020513ac8201a449b5ae2eeb58fef0ce0a2a4 (4.0-beta17) 2023-02-01 22:25:07 +01:00
Rémi Verschelde
6d4d18a4fa Merge pull request #1026 from bruvzg/typed_arr_ref
Update typed array API to match "GDScript: Fix typed arrays".
2023-01-31 10:41:27 +01:00
bruvzg
37f6e35974 Update typed array API to match "GDScript: Fix typed arrays". 2023-01-31 11:28:55 +02:00
Rémi Verschelde
014eda2535 Revert "gdextension: Sync with upstream commit 551f5191e5dbc1d1a43f99b13d5dbbf7f598dc58 + PR 69248"
This reverts commit 1166783725.

It's not as simple as I thought, needs some local changes too.
2023-01-30 19:42:53 +01:00
Rémi Verschelde
552f1383bf Merge pull request #977 from asmaloney/binding-cleanup
Binding generator cleanups
2023-01-30 19:39:52 +01:00
Rémi Verschelde
1166783725 gdextension: Sync with upstream commit 551f5191e5dbc1d1a43f99b13d5dbbf7f598dc58 + PR 69248
Needed for that PR to pass CI.
https://github.com/godotengine/godot/pull/69248
2023-01-30 19:39:22 +01:00
Andy Maloney
2d5e5c0fd6 Binding generator cleanups
- remove unused vars
- fix a few f-strings
- remove f-string notation where not used
2023-01-30 10:57:26 -05:00
Rémi Verschelde
d177752be1 Merge pull request #982 from WildRackoon/templates-add-LocalVector
Add missing local_vector.hpp template
2023-01-30 12:32:13 +01:00
Rémi Verschelde
c1d4fb2b68 Merge pull request #1023 from mashumafi/fix-alloc-order
Move DefaultTypedAllocator after memdelete
2023-01-30 12:32:07 +01:00
Rémi Verschelde
f59fd96ab4 Merge pull request #1013 from bruvzg/set_typed_move
Move Array:set_typed to internal GDExtension structure.
2023-01-30 12:31:38 +01:00
Rackoon
1df83331de Add missing LocalVector template
Co-authored-by: Rémi Verschelde <rverschelde@gmail.com>
2023-01-30 12:30:34 +01:00
bruvzg
40d3cfd97b Move Array:set_typed to internal GDExtension structure. 2023-01-30 13:27:25 +02:00
Rémi Verschelde
2ef10f9754 Merge pull request #956 from DmitriySalnikov/enum_bitfield_cast
Fixed `VARIANT_ENUM/BITFIELD_CAST` to show the correct names
2023-01-30 12:07:15 +01:00
mashumafi
a8be6aa8dd Move allocator to after memdelete 2023-01-29 23:29:31 -05:00
Rémi Verschelde
0f3a0913f1 Merge pull request #1018 from vnen/typed-array-constructor
Support typed array default values in extension API
2023-01-28 19:43:04 +01:00
George Marques
1c625befa3 Support typed array default values in extension API
The API JSON has changed syntax for default values of typed arrays. This
detects the new format and use initializer lists (currently empty since
the TypedArray class does not support initializer list construction and
default values are always empty arrays).
2023-01-28 14:01:27 -03:00
George Marques
64be8c1507 Use std type traits instead of intrinsics
This removes warnings and mimics what has been done in Godot itself.
2023-01-28 13:59:34 -03:00
Rémi Verschelde
a8d8485060 gdextension: Sync with upstream commit 518b9e5801a19229805fe837d7d0cf92920ad413 (4.0-beta16) 2023-01-27 17:02:22 +01:00
Rémi Verschelde
ae1afba8d1 gdextension: Sync with upstream commit 4fa6edc888cfacd5346bf08afa14b5f5a9bd6d0c (4.0-beta15) 2023-01-25 08:34:39 +01:00
Mikael Hermansson
6b92eda819 Added missing string.hpp include in transform2d.cpp 2023-01-22 17:35:24 +01:00
Mikael Hermansson
d174b47e51 Update error macros to match core 2023-01-22 14:24:57 +01:00
Rémi Verschelde
1909113889 gdextension: Sync with upstream commit 28a24639c3c6a95b5b9828f5f02bf0dc2f5ce54b (4.0-beta14) 2023-01-20 23:03:13 +01:00
Rémi Verschelde
00b29630ba Merge pull request #1003 from akien-mga/fix-sign-0
Change behavior of Math::sign to match Godot builtin
2023-01-20 23:02:13 +01:00
Дмитрий Сальников
6528c7177f Fixed variant casting for enum and bitfield 2023-01-20 21:10:03 +03:00
Fabio Alessandrelli
860182fe01 Merge pull request #1006 from asmaloney/fix-sign-comparisons-class_db
Fix sign comparison warnings in class_db.cpp
2023-01-19 16:11:33 +01:00
Fabio Alessandrelli
12c6099737 Merge pull request #1005 from asmaloney/fix-sign-comparisons
Fix some sign comparison warnings
2023-01-19 15:50:06 +01:00
Andy Maloney
1ae0147aad Fix sign comparison warnings in class_db.cpp
Part of #999
2023-01-19 08:30:08 -05:00
Andy Maloney
e6b636cc51 Fix sign comparison warnings in method_bind.hpp
Part of #999
2023-01-19 08:26:02 -05:00
Rémi Verschelde
2a9b21e46a Merge pull request #1004 from asmaloney/remove-unused-ucaps
Remove unused ucaps header
2023-01-19 13:55:29 +01:00
Rémi Verschelde
07e2e20f7b Merge pull request #939 from bruvzg/gde_low_level_funcs_cpp
Expose some low level functions and String operators.
2023-01-19 13:55:24 +01:00
Rémi Verschelde
04731d2b78 Merge pull request #965 from WildRackoon/fix-GDCLASS-fwddeclaration
Fix GDCLASS needs explicit ClassDB fwd declaration
2023-01-19 13:55:14 +01:00
Rémi Verschelde
952bde1db3 Merge pull request #1002 from asmaloney/cmake-system-includes
{cmake} Add GODOT_CPP_SYSTEM_HEADERS option to mark includes as SYSTEM
2023-01-19 13:55:08 +01:00
Rémi Verschelde
b0f9ca7918 Merge pull request #808 from Calinou/readme-add-branch-warning
Add a more prominent warning about repository branches in README
2023-01-19 13:55:01 +01:00
Fabio Alessandrelli
2eb375e486 Merge pull request #998 from asmaloney/fix-virtual-destructor
"Wrapped" has virtual functions so it should have a virtual destructor.
2023-01-19 13:27:42 +01:00
Andy Maloney
67be0c95e1 Remove unused ucaps header
These static structs were being included in every file string.hpp was included in...

Part of #999
2023-01-19 07:15:40 -05:00
bruvzg
abca497b72 Expose some low level functions and String operators. 2023-01-19 13:12:21 +02:00
Andy Maloney
5dd2928790 "Wrapped" has virtual functions so it should have a virtual destructor.
Deleting an object through a pointer to a base class is undefined behaviour unless the destructor in the base class is virtual.
2023-01-19 05:57:17 -05:00
Fabio Alessandrelli
69b525494b Merge pull request #1001 from Faless/ext/basis_abs
Fix Basis::scaled_orthogonal using incorrect abs function.
2023-01-19 10:16:51 +01:00
Fabio Alessandrelli
3d74e661b7 Merge pull request #1000 from Faless/ext/variant_can_convert
Fix Variant::can_convert[_strict] returning gibberish.
2023-01-19 10:16:10 +01:00
Erik Abair
d3f17c1dca Change behavior of Math::sign to match Godot builtin
Fixes #551.
2023-01-19 09:47:13 +01:00
Andy Maloney
1351710a18 {cmake} Add GODOT_CPP_SYSTEM_HEADERS option to mark includes as SYSTEM
From the cmake docs:

"This may have effects such as suppressing warnings or skipping the contained headers in dependency calculations (see compiler documentation). Additionally, system include directories are searched after normal include directories regardless of the order specified."

Addresses part of #999
2023-01-18 21:15:34 -05:00
Fabio Alessandrelli
72a7c61750 Fix Basis::scaled_orthogonal using incorrect abs function. 2023-01-19 02:53:53 +01:00
Fabio Alessandrelli
d64d97cb17 Fix Variant::can_convert[_strict] returning gibberish.
An uninitialized value was being returned instead of the function return
value.
2023-01-19 02:17:53 +01:00
Rémi Verschelde
cf3d995e8c Merge pull request #997 from asmaloney/fix-shadow-eulerorder
Fix a shadowed enum (EulerOrder)
2023-01-18 18:36:21 +01:00
Rémi Verschelde
0dfe0d0166 Merge pull request #983 from rburing/variant_to_from_objectid
Add conversions between `Variant` and `ObjectID`
2023-01-18 11:41:57 +01:00
Andy Maloney
dbd43ac107 Fix a shadowed enum (EulerOrder)
Use the global constants.
2023-01-17 18:38:24 -05:00
Rémi Verschelde
cb15429e4a gdextension: Sync with upstream commit caacade569eb7a541aaa7a8cdc3eedffca1422d9 (4.0-beta13) 2023-01-17 18:52:05 +01:00
Rémi Verschelde
6f2bba3630 Merge pull request #991 from asmaloney/fix-spelling
Fix spelling in demo script
2023-01-17 11:32:58 +01:00
Rémi Verschelde
b21026e061 Merge pull request #950 from DmitriySalnikov/typed-ptr-method-call-support-and-ref-class-name
Added property info for Object's and Ref's and ported the implementation of the `check` method
2023-01-17 11:31:54 +01:00
Rémi Verschelde
151ea35c5f gdextension: Sync with upstream commit 3c9bf4bc210a8e6a208f30ca59de4d4d7e18c04d (4.0-beta12) 2023-01-13 17:07:21 +01:00
Дмитрий Сальников
0c6e26dabe Added property info for ptr and ref + ported the implementation of the check method 2023-01-13 15:56:51 +03:00
Andy Maloney
c721b62c2f Fix spelling in demo script 2023-01-10 12:02:46 -05:00
Rémi Verschelde
512ec5b236 Merge pull request #990 from akien-mga/ci-clang-format-15
CI: Use clang-format 15
2023-01-10 17:36:50 +01:00
Rémi Verschelde
51c79565e0 CI: Use clang-format 15
Seems like there's a slight inconsistency for the formatting of the
`delete[](pointer)` syntax.
2023-01-10 16:24:14 +01:00
Rémi Verschelde
734d9ef092 gdextension: Sync with upstream commit 91713ced81792b10fdc9367b7f355738e5d52777 (4.0-beta11) 2023-01-10 16:15:31 +01:00
Rémi Verschelde
931f1a3f34 Sync license copyright with upstream GH-70885 2023-01-10 16:15:31 +01:00
Rémi Verschelde
2b7094f342 Merge pull request #988 from rburing/precision=double
Rename `float=64` build option to `precision=double`
2023-01-10 16:09:02 +01:00
Fabio Alessandrelli
8ee9cab8f8 Merge pull request #989 from Faless/ext/4.x_objects_bind
Allow method binds to take Object subclasses as arguments
2023-01-10 14:28:26 +01:00
Fabio Alessandrelli
9fd33b5cde Allow method binds to take Object subclasses as arguments
As done in upstream Godot via GH-57205.

Add a test that ensures it works also for "gdextended" objects.
2023-01-10 12:55:41 +01:00
Rémi Verschelde
129c358a72 Merge pull request #968 from Faless/build/4.x_custom_paths
[SCons] Fix custom API file/dir relative paths.
2023-01-09 23:25:10 +01:00
Ricardo Buring
47140cdad0 Rename float=64 build option to precision=double
This makes the build system consistent with Godot again.
Also fix CMake build to define REAL_T_IS_DOUBLE when precision=double.
2023-01-09 23:22:03 +01:00
Fabio Alessandrelli
6877a0abcd [SCons] Fix custom API file/dir relative paths. 2023-01-09 21:09:49 +01:00
Rémi Verschelde
2f785c9da1 Merge pull request #987 from bruvzg/fix_enum_size
Fix enum return value size.
2023-01-07 12:20:41 +01:00
bruvzg
18eed144ca Fix enum return value size. 2023-01-07 00:48:40 +02:00
Ricardo Buring
d4e1dfe5dc Add conversions between Variant and ObjectID 2023-01-01 21:27:08 +01:00
Rémi Verschelde
3da6db4fe4 gdextension: Sync with upstream commit d0398f62f08ce0cfba80990b21c6af4181f93fe9 (4.0-beta10) 2022-12-23 23:37:22 +01:00
Rémi Verschelde
e75647056b Merge pull request #974 from akien-mga/add-gdignore
Add .gdignore file to godot-cpp, for use as submodule in Godot projects
2022-12-22 16:24:30 +01:00
Rémi Verschelde
f99aa47581 Add .gdignore file to godot-cpp, for use as submodule in Godot projects
.gdignore causes Godot to skip the folder when importing resources,
which is needed in particular to avoid importing compiled .obj files
from MSVC (which sadly share their extension with Wavefront OBJ meshes).

Closes #522.
2022-12-22 16:01:03 +01:00
Rémi Verschelde
99de0a872e Merge pull request #971 from Faless/build/4.x_default_gnu
[SCons] Platform agnostic default toolchain (GNU).
2022-12-20 18:02:49 +01:00
Fabio Alessandrelli
8d6982be3b [SCons] Platform agnostic default toolchain (GNU).
Create the SCons Environment with an empty PLATFORM variable to force
the default tools to use the GNU toolchain.

Platform specific toolchains are then setup in our custom tools.
2022-12-20 17:41:34 +01:00
Rémi Verschelde
104997e83e Merge pull request #961 from mihe/char-string-length
Fix incorrect length passed to `CharString`
2022-12-20 10:44:08 +01:00
Fabio Alessandrelli
c0eaadac86 Merge pull request #903 from PapyChacal/build_library
Make build_library=no usable at godot-cpp's root
2022-12-19 23:03:17 +01:00
Emilien Bauer
e52d4b6486 Remove gen from emitted files to solve circular dependency with build_library=no.
Use env variable to pass the output dir instead.
Add a CI step to guard regression on this. Clean the generated sources to avoid interfering with next steps.
2022-12-19 21:20:15 +00:00
Rémi Verschelde
0233683173 gdextension: Sync with upstream commit e780dc332a0a3f642a6daf8548cb211d79a2cc45 (4.0-beta9) 2022-12-19 16:10:14 +01:00
Rackoon
72d537fd95 Fix GDCLASS needs explicit ClassDB fwd declaration 2022-12-16 13:49:10 +01:00
Rémi Verschelde
91a4a03356 Merge pull request #962 from Bromeon/gdextension-const-correctness
Extension header: amend const correctness of `p_args` parameters
2022-12-14 17:13:40 +01:00
Jan Haller
fce753c05d Extension header: amend const correctness of p_args parameters 2022-12-14 15:47:42 +01:00
Mikael Hermansson
1f6b0118dc Fix incorrect length passed to CharString 2022-12-14 15:08:45 +01:00
Rémi Verschelde
a0b0560e20 Merge pull request #960 from akien-mga/godot-headers-is-dead-long-live-godot-headers
Rename godot-headers to gdextension, move header to top folder
2022-12-14 14:09:52 +01:00
Rémi Verschelde
bab247dcb6 Rename godot-headers to gdextension, move header to top folder
Changes the `<godot/gdextension_interface.h>` include to simply
`<gdextension_interface.h>`.

Refactor and better document the SCons and CMake logic around setting
the paths to the header and API JSON file.
2022-12-14 12:36:59 +01:00
Rémi Verschelde
1e8eb1c1f2 Merge pull request #958 from BastiaanOlij/improve_gdextension_virtual_ref
Fix virtual GDExtension method Ref<T> conversion
2022-12-14 12:36:12 +01:00
Rémi Verschelde
0d926a76a7 Merge pull request #959 from DmitriySalnikov/bitfield_int64
Use `int64_t` for `BitField` as in Godot itself
2022-12-13 12:13:46 +01:00
Rémi Verschelde
49a478a879 Merge pull request #949 from BastiaanOlij/fix_tests_refcounting
Change example code to properly test refcounted objects
2022-12-13 12:13:39 +01:00
Дмитрий Сальников
b7eeddcf52 Use int64_t for BitField as in Godot itself 2022-12-13 13:36:16 +03:00
Bastiaan Olij
992d85e6f8 Fix virtual GDExtension method Ref<T> conversion 2022-12-13 10:41:55 +11:00
Rémi Verschelde
c21705982e Merge pull request #952 from groud/rename_gdnative_to_gdextension
Rename GDNative to GDExtension
2022-12-12 18:58:39 +01:00
Gilles Roudière
c02e644679 Rename GDNative to GDExtension
Non-exhaustive list of case-sensitive renames:

GDExtension -> GDNative
GDNATIVE -> GDEXTENSION
gdextension -> gdnative
ExtensionExtension -> Extension (for where there was GDNativeExtension)
EXTENSION_EXTENSION -> EXTENSION (for where there was GDNATIVE_EXTENSION)
gdnlib -> gdextension
gdn_interface -> gde_interface
gdni -> gde_interface
2022-12-12 11:06:38 +01:00
Rémi Verschelde
c20ecea090 headers: Sync with upstream commit 45cac42c0 (4.0-beta8) 2022-12-09 18:00:49 +01:00
Rémi Verschelde
f74c472203 Merge pull request #948 from touilleMan/issue-946
Fix cast on PtrToArg::convert
2022-12-06 10:21:44 +01:00
Rémi Verschelde
9fb5b764af Add CODEOWNERS so GDExtension team gets assigned for reviews 2022-12-06 10:17:13 +01:00
Bastiaan Olij
f24ee56c5d Change example code to properly represent test cases with refcounted objects 2022-12-05 22:28:28 +11:00
Emmanuel Leblond
fe79449969 Fix cast on PtrToArg::convert 2022-12-05 03:30:50 +01:00
Rémi Verschelde
f9f9a1bab4 Merge pull request #947 from asmaloney/cmake-cleanup
{cmake} Updates for target-based approach
2022-12-04 23:58:15 +01:00
Andy Maloney
bb13b957de {cmake} Updates for target-based approach
- instead of setting globals which can effect other projects including this as a subdirectory, set them on the target if possible
- add "CONFIGURE_DEPENDS" to GLOBs to check for changes
- update required CMake version to 3.12 (still ancient - 2018) to support these
2022-12-04 17:37:38 -05:00
Emmanuel Leblond
32859ea25c Merge pull request #897 from touilleMan/gdextension-fix-gdnative-types-const-qualifier
Fix const qualifier for parameters in GDExtension api functions
2022-12-03 11:13:23 +01:00
Emmanuel Leblond
fe86a94dcf Fix const qualifier for parameters in GDExtension api functions 2022-12-03 00:27:07 +01:00
Rémi Verschelde
f1d501f977 headers: Sync with upstream commit 0ff874291 (4.0-beta7) 2022-12-01 18:17:11 +01:00
Rémi Verschelde
4c5cfe3876 Merge pull request #940 from touilleMan/fix-get_property_list-stringname-lifetime
Fix lifetime of StringName objects returned by Wrapped::_get_property_list
2022-11-29 22:37:57 +01:00
Emmanuel Leblond
fa405a8337 Fix lifetime of StringName objects returned by Wrapped::_get_property_list 2022-11-29 18:23:56 +01:00
Rémi Verschelde
576bd17285 headers: Sync with upstream commit 7f8ecffa5 (4.0-beta6) 2022-11-23 15:43:17 +01:00
Rémi Verschelde
12c022ee37 Merge pull request #927 from asmaloney/type-warnings
Fix some type warnings in example
2022-11-23 15:42:47 +01:00
Rémi Verschelde
4a4e2b0239 Merge pull request #930 from rune-scape/rune-missing-string-ops
Add missing String operators
2022-11-22 10:25:02 +01:00
Rémi Verschelde
6bebaa36bf Merge pull request #932 from Faless/build/4.x_msvc_runtime
[SCons] Link MSVC debug runtime for optimize=none|debug only.
2022-11-21 11:38:55 +01:00
Rémi Verschelde
17170fe23c Merge pull request #929 from asmaloney/static-analysis-fixes
Basic static analysis fixes
2022-11-21 11:38:37 +01:00
Fabio Alessandrelli
edf02f8319 [SCons] Link MSVC debug runtime for optimize=none|debug only.
Select windows runtime in "targets" tool, use "/MDd" flag only when
building with optimize="none" and optimize="debug".
2022-11-21 11:04:10 +01:00
rune-scape
d04ce481c4 Add missing String operators 2022-11-20 03:44:54 -05:00
Andy Maloney
c7e34c2f9d Basic static analysis fixes
- remove extraneous semicolons
- use "nullptr" instead of "0"
- remove "break" after "return"
- use <cstdio> instead of <stdio.h>
2022-11-18 17:46:13 -05:00
Andy Maloney
fbf7f7bc36 Fix some type warnings in example 2022-11-16 16:43:44 -05:00
Rémi Verschelde
6c2f9196d7 headers: Resync with actual 4.0-beta5 release build 2022-11-16 12:36:01 +01:00
Rémi Verschelde
00db31c4f0 headers: Sync with upstream commit 89a33d28f (4.0-beta5) 2022-11-16 10:36:25 +01:00
Rémi Verschelde
d9c72c6773 Fixup after 243ec87918 2022-11-16 10:33:39 +01:00
Rémi Verschelde
243ec87918 Sync gdnative_interface.h with upstream refactoring
Syncs with https://github.com/godotengine/godot/pull/68701.
Breaks compat slightly by reordering member variables.
2022-11-16 09:55:03 +01:00
Rémi Verschelde
dc38c72432 Merge pull request #924 from aaronfranke/color-names 2022-11-14 09:16:54 +01:00
Aaron Franke
1858e349c8 Update named colors to be in sync with the engine 2022-11-12 00:31:06 -06:00
Rémi Verschelde
bb5579d075 Merge pull request #920 from touilleMan/fix-using-godot-required
fix https://github.com/godotengine/godot-cpp/issues/918
2022-11-11 22:59:31 +01:00
Emmanuel Leblond
2745d341aa Fix broken namespace isolation in GDCLASS macro 2022-11-11 16:45:42 +01:00
Rémi Verschelde
10467e3062 Merge pull request #913 from bruvzg/mac_android 2022-11-11 13:14:05 +01:00
bruvzg
6e7a24d390 Fix Android build on macOS. 2022-11-10 15:20:15 +02:00
Emmanuel Leblond
ce3c08359a Merge pull request #896 from touilleMan/stringname-in-gdextension-api
Uses `StringName` in GDExtension perf critical instance creation & method/properties setter/getter
2022-11-08 23:00:42 +01:00
Emmanuel Leblond
ed4d3d36f9 Fix missing final newline in godot-headers/extension_api.json 2022-11-08 21:56:41 +01:00
Emmanuel Leblond
b6ba0dca13 StringName is working fine with demo \o/ 2022-11-08 21:44:33 +01:00
Emmanuel Leblond
3b82d5937b Correct GDNativeExtensionScriptInstanceToString 2022-11-08 21:44:32 +01:00
Emmanuel Leblond
d1963dc133 Correct __constant_get_bitfield_name with StringName 2022-11-08 21:44:32 +01:00
Emmanuel Leblond
a706a9ceb9 Remove now useless _alloc_and_copy_cstr 2022-11-08 21:44:31 +01:00
Emmanuel Leblond
e24b6b0e51 Use StringName in the whole GDExtension API instead of const char * 2022-11-08 21:44:31 +01:00
Emmanuel Leblond
0e81f89dd3 Uses StringName in GDExtension perf critical instance creation & method/properties setter/getter 2022-11-08 21:44:30 +01:00
Fabio Alessandrelli
73ad6717e9 Merge pull request #908 from Faless/build/4.x_cxxflags
[SCons] Remove bogus CCFLAGS from windows toolchain.
2022-11-04 09:12:22 +01:00
Rémi Verschelde
727673a043 headers: Sync with upstream commit e6751549c (4.0-beta4) 2022-11-03 13:53:27 +01:00
Fabio Alessandrelli
35ec1403dc [SCons] Remove bogus CCFLAGS from windows toolchain.
The c++ standard is added as part of the main SConstruct
2022-11-02 16:45:38 +01:00
Fabio Alessandrelli
adf4802f4b Merge pull request #895 from Faless/ext/add_missing_nativeptr
Add missing bindings for GDNativePtr<void>.
2022-10-20 20:47:48 +02:00
Fabio Alessandrelli
a9c341656d Add missing bindings for GDNativePtr<void>. 2022-10-20 18:08:15 +02:00
Rémi Verschelde
f33dfdbe26 Merge pull request #883 from rburing/abstract_class
Add support for virtual and abstract classes
2022-10-16 08:56:03 +02:00
Ricardo Buring
01960ffc9f Add support for virtual and abstract classes 2022-10-15 13:15:05 +02:00
Rémi Verschelde
1044251a9e headers: Sync with upstream commit 01ae26d31 (4.0-beta3) 2022-10-14 10:14:55 +02:00
Rémi Verschelde
3abd5e131f Merge pull request #888 from touilleMan/gdextension-typed-enum-in-struct 2022-10-13 14:22:03 +02:00
Emmanuel Leblond
b21931c4a3 Type GDNativePropertyInfo.type field as GDNativeVariantType 2022-10-13 14:04:54 +02:00
Rémi Verschelde
779eaba428 Merge pull request #891 from mihe/classdb-deinit
Fix use-after-free when deleting objects from extension terminator
2022-10-11 08:22:50 +02:00
Mikael Hermansson
cddaf50ff8 Fix use-after-free when deleting objects from extension terminator 2022-10-11 00:59:35 +02:00
Rémi Verschelde
6696bebfa6 Merge pull request #887 from aaronfranke/static-checks
Add more static checks and move to separate file to match main repo
2022-10-10 13:51:19 +02:00
Rémi Verschelde
16a3c32da9 Merge pull request #879 from touilleMan/fix-variant-type-in-extension-api-dump
Fix Variant types displayed as `Nil` in extension_api.json
2022-10-10 13:51:14 +02:00
Emmanuel Leblond
d17b256fdd Correct godot-headers/extension_api.json operator.right_type field Nil -> Variant 2022-10-10 00:56:35 +02:00
Emmanuel Leblond
5282009121 Fix Variant types displayed as Nil in extension_api.json 2022-10-10 00:56:35 +02:00
Aaron Franke
592bd15c7a Run scripts to format and make headers consistent 2022-10-09 01:47:07 -05:00
Aaron Franke
bcfa3bf320 Add more static checks and move to separate file to match main repo 2022-10-09 01:46:28 -05:00
Rémi Verschelde
f69f1bb58f Merge pull request #884 from akien-mga/update-makefile
Update Makefile after recent buildsystem changes
2022-10-07 22:25:58 +02:00
Rémi Verschelde
db8679443f Merge pull request #885 from aaronfranke/core-data-structs
Update core data structures to match the engine
2022-10-07 22:25:54 +02:00
Rémi Verschelde
0eba81ef79 Merge pull request #876 from Daylily-Zeleen/Daylily-Zeleen/master
Add detail infos for binding error message.
2022-10-07 22:25:49 +02:00
Rémi Verschelde
3f3253ec2f Merge pull request #881 from mihe/builtin-binds
Bind enums in built-in types and expose bindings for global constants
2022-10-07 22:25:44 +02:00
Aaron Franke
65eeb94f75 Update core data structures to match the engine 2022-10-07 11:27:41 -05:00
Rémi Verschelde
67c9b2f8f4 Update Makefile after recent buildsystem changes
Fixes #882.
2022-10-06 14:34:29 +02:00
Mikael Hermansson
40d181d2f3 Bind enums in built-in types and expose bindings for global constants 2022-10-06 11:16:17 +02:00
Rémi Verschelde
1507253bd5 Merge pull request #864 from Zylann/fix_passing_null
Fix passing null to functions taking Object parameters
2022-10-05 10:37:17 +02:00
Rémi Verschelde
50a534bf55 Merge pull request #880 from aaronfranke/struct
Use `struct` instead of `class` for core structures
2022-10-05 10:35:59 +02:00
Rémi Verschelde
91afc08de1 Merge pull request #855 from Zylann/fix_issue854_virtual_methods
Fix deriving a custom class with virtual methods
2022-10-05 10:35:54 +02:00
Aaron Franke
0455f72ede Use struct instead of class for core structures 2022-10-05 01:46:15 -05:00
Rémi Verschelde
4e5d0ee3a8 Merge pull request #867 from Faless/build/4.x_unify_targets
[SCons] Unify tools/target build type configuration
2022-10-04 16:39:51 +02:00
Rémi Verschelde
d25cae9b61 Merge pull request #859 from aaronfranke/basis-transform-quat
Update Basis/Transform3D/Quaternion to match the engine
2022-10-04 16:39:46 +02:00
Rémi Verschelde
047b08922d Merge pull request #857 from aaronfranke/you-just-got-vectored
Update Vector2/2i/3/3i/4/4i to match the engine
2022-10-04 16:39:42 +02:00
Fabio Alessandrelli
64b2c9be0b [SCons] Refactor targets, symbols, optimizations.
Now matches Godot `master` target names and supports the same flags with
the following notable exceptions:
- The default target is "template_debug", since it's compatible with
  editor builds (and TOOLS_ENABLED is never used internally).
- separate_debug_symbols is still not supported, and will be done in a
  separate commit.
2022-10-04 16:05:40 +02:00
Aaron Franke
fc879c04c8 Update Vector4/4i to match the engine 2022-10-01 21:09:05 -05:00
Aaron Franke
d479208a8f Update Vector2/2i/3/3i to match the engine 2022-10-01 21:09:05 -05:00
daylilyzeleen
3e91ec1729 Add detail infos for binding error message. 2022-09-30 15:16:43 +08:00
Rémi Verschelde
fa4d18f21c headers: Sync with upstream commit f8745f2f7 (4.0-beta2) 2022-09-29 09:12:41 +02:00
Rémi Verschelde
e51df8450c Merge pull request #870 from bruvzg/ts_wrapper 2022-09-28 11:29:13 +02:00
bruvzg
fb8253c912 Add wrapper function generation for built-in module ↔ godot-cpp interoperability. 2022-09-28 10:04:35 +03:00
Marc Gilleron
cd2232eddf Fix passing null to functions taking Object parameters 2022-09-23 21:20:37 +01:00
Rémi Verschelde
e40aa112ee Merge pull request #841 from bruvzg/typed_array
Implement support for typed arrays.
2022-09-23 09:19:37 +02:00
bruvzg
c001d0e5c7 Implement support for typed arrays. 2022-09-23 09:02:00 +03:00
Marc Gilleron
5de2c059d1 Fix deriving a custom class with virtual methods 2022-09-21 19:31:30 +01:00
Aaron Franke
e83d472c00 Update Basis/Transform3D/Quaternion to match the engine 2022-09-20 01:07:45 -05:00
Rémi Verschelde
8670305589 Merge pull request #856 from aaronfranke/rename-elements
Rename Transform2D and Basis `elements` to `columns` and `rows` respectively
2022-09-20 07:02:49 +02:00
Aaron Franke
e26a75cd0c Rename Basis "elements" to "rows"
https://github.com/godotengine/godot/pull/60627
2022-09-19 18:22:52 -05:00
Aaron Franke
e30c858c5d Rename Transform2D "elements" to "columns"
https://github.com/godotengine/godot/pull/60627
2022-09-19 18:22:52 -05:00
Fabio Alessandrelli
a330342e4f Merge pull request #853 from Faless/build/4.x_ci_cache
[CI] Add concurrency and scons caching.
2022-09-19 19:03:14 +02:00
Fabio Alessandrelli
d5e8675fd6 [CI] Add concurrency options and scons caching. 2022-09-19 16:56:29 +02:00
Rémi Verschelde
bef1fa091c Merge pull request #835 from Faless/build/4.x_opt_debug 2022-09-19 15:11:05 +02:00
Fabio Alessandrelli
0b87aaa74c Merge pull request #838 from PapyChacal/scons-caching
Add options to use scons caching for faster iteration.
2022-09-19 14:51:40 +02:00
Emilien Bauer
8e717acf48 Add options to use scons caching for faster iteration.
Sort the sets in source generation so they are generated consistently between runs; otherwise caching is useless.
2022-09-19 13:32:23 +02:00
Rémi Verschelde
aaee30e5c5 Merge pull request #852 from aaronfranke/math 2022-09-19 12:38:49 +02:00
Aaron Franke
7ba459ae7b Add integer posmod and rename range_lerp to remap
https://github.com/godotengine/godot/pull/23310
https://github.com/godotengine/godot/pull/65361
2022-09-19 03:09:59 -05:00
Aaron Franke
9a2e8d907b Add pingpong and fract methods to Math
https://github.com/godotengine/godot/pull/53819
2022-09-19 03:09:59 -05:00
Aaron Franke
b11ff9d876 Replace stepify with snapped
https://github.com/godotengine/godot/pull/44586
2022-09-19 03:09:59 -05:00
Aaron Franke
d20c4200db Update cubic interpolation methods to match core
https://github.com/godotengine/godot/pull/64924
https://github.com/godotengine/godot/pull/63602
https://github.com/godotengine/godot/pull/62458
2022-09-19 03:09:38 -05:00
Aaron Franke
942cd466ed Split is_equal_approx into float and double versions to match Godot
https://github.com/godotengine/godot/pull/48882
2022-09-19 02:47:27 -05:00
Rémi Verschelde
3450a1ab16 Merge pull request #847 from ninfur/issue-65997
Add missing Vector4 function bindings
2022-09-19 09:31:23 +02:00
Rémi Verschelde
03d1120d6a Merge pull request #850 from Zylann/transform_local
Add Transform3D `translated_local`, `rotated_local`, `scaled_local`
2022-09-19 09:30:11 +02:00
Rémi Verschelde
d910b72cb7 Merge pull request #851 from Zylann/quat_to_quaternion
Use `quaternion` instead of `quat` in method names
2022-09-19 09:29:57 +02:00
Rémi Verschelde
d4cef0bd43 Merge pull request #849 from Zylann/const_cast_to
cast_to` for `const Object*`
2022-09-19 09:29:51 +02:00
Rémi Verschelde
53b0892791 Merge pull request #848 from Zylann/fix_class_constants
Class constants should be static
2022-09-19 09:29:14 +02:00
Marc Gilleron
c543a3cbe1 Add Transform3D translated_local, rotated_local, scaled_local 2022-09-18 23:04:38 +01:00
Marc Gilleron
a35994ce7b Use quaternion instead of quat in method names 2022-09-18 22:44:18 +01:00
Marc Gilleron
99c004f689 Add Object::cast_to for const Object* 2022-09-18 22:23:49 +01:00
Marc Gilleron
f8f25980e1 Class constants should be static 2022-09-18 20:58:44 +01:00
Johannes Sinander
e7372cbe85 Add missing Vector4 function bindings 2022-09-18 11:27:49 +02:00
Rémi Verschelde
3276688c82 Merge pull request #844 from Zylann/fix_get_const
Fix issues with `_get` and `_get_property_list`
2022-09-16 08:48:00 +02:00
Marc Gilleron
6f3bdab090 Fix issues with _get and _get_property_list
`_get` was using `_set` internally, and should be `const`.
`_get_property_list` should be `const`.
2022-09-15 23:46:50 +01:00
Rémi Verschelde
f24cc8be03 Merge pull request #826 from bruvzg/string_info 2022-09-15 21:10:13 +02:00
Rémi Verschelde
16606cde39 Merge pull request #840 from TokageItLab/move-some-methods-to-animation-from-variant 2022-09-15 21:09:44 +02:00
Rémi Verschelde
be7ed4c775 headers: Sync with upstream commit 4ba934bf3 (4.0-beta1) 2022-09-15 10:38:32 +02:00
Silc Renew
440c4ed703 Mode some methods to Animation from Variant 2022-09-15 04:13:51 +09:00
bruvzg
36273baa7e Change PropertyInfo members to String. 2022-09-14 08:41:09 +03:00
Rémi Verschelde
420c86eb90 headers: Sync with upstream commit 22a09fef5 (4.0-alpha17) 2022-09-13 15:51:33 +02:00
Rémi Verschelde
7735ab48c4 CI: Make CMake builds use verbose output 2022-09-13 15:50:21 +02:00
Rémi Verschelde
e45234fbbc Merge pull request #839 from rburing/add_self_list 2022-09-13 12:29:08 +02:00
Ricardo Buring
3e97626b67 Add SelfList template 2022-09-13 11:33:12 +02:00
Fabio Alessandrelli
2bf983e638 [SCons] Add "optimize" and "debug_symbols" options
optimize = auto|none|debug|speed|size|0|1|2|3
debug_symbol = True|False

optimize == "auto" will produce:
- "debug" for "debug" builds
- "speed" for "release" builds
2022-09-12 16:52:05 +02:00
Fabio Alessandrelli
024b6d2d9e Merge pull request #819 from Faless/bump/hashfuncs
Update hashfuncs, add some missing math funcs.
2022-09-12 14:01:57 +02:00
Rémi Verschelde
dff13ff129 Merge pull request #836 from Faless/fix/4.x_file_list 2022-09-12 13:31:32 +02:00
Fabio Alessandrelli
081d425277 [MSVC] Add NOMINMAX flag to scons and cmake.
Ensures user inclusion of windows.h do not define "min" and "max"
macros.
2022-09-12 13:12:55 +02:00
Fabio Alessandrelli
e272d92827 [Test] Add minimal test for templates inclusion.
We probably want to test more than just them being able to compile, but
this is a start.
2022-09-12 13:12:55 +02:00
Fabio Alessandrelli
c263b3e38c Fix get_file_list not returning all generated files.
Adds a CI static check for it.
2022-09-11 21:39:06 +02:00
Fabio Alessandrelli
43cdc2e037 Update hashfuncs, add some missing math funcs. 2022-09-11 13:11:52 +02:00
Rémi Verschelde
204e504d68 Merge pull request #833 from aaronfranke/gitignore 2022-09-08 10:18:24 +02:00
Aaron Franke
91fcde48d4 Add Godot 3.x ignores to the .gitignore file 2022-09-07 22:59:04 -05:00
Rémi Verschelde
0d7da02dc4 headers: Sync with upstream commit 86dd3f312 (4.0-alpha16) 2022-09-07 13:17:32 +02:00
Rémi Verschelde
446cacde15 Merge pull request #817 from akien-mga/test-project-public-domain 2022-09-07 13:07:57 +02:00
Rémi Verschelde
f71c711646 Merge pull request #828 from aaronfranke/fix-constants 2022-09-04 20:39:16 +02:00
Aaron Franke
76ad89fe0b Generate constants in the bindings generator 2022-09-02 21:32:38 -05:00
Rémi Verschelde
862d1f1fdd Merge pull request #823 from Faless/fix/godot_namespace_requirement 2022-09-02 09:16:59 +02:00
Fabio Alessandrelli
02cdec2f91 Merge pull request #824 from clayjohn/updatea15
Update extension api to alpha 15
2022-09-01 22:07:09 +02:00
clayjohn
f64c049f0c Update extension api to alpha 15 2022-09-01 11:24:31 -07:00
Rémi Verschelde
162705fbed Merge pull request #822 from zhehangd/fix_basis 2022-09-01 09:36:55 +02:00
Fabio Alessandrelli
bcf27d8af4 Ensure GDCLASS can be used outside the godot namespace.
The `GDCLASS` macro should not assume to be called inside the `godot`
namespace and should thus prefix function calls for that namespace with
`::godot::` to ensure proper namespace referencing.
2022-09-01 04:11:23 +02:00
Zhehang Ding
6d1073d867 Basis constructor: row vectors -> column vectors
https://github.com/godotengine/godot-proposals/issues/5295
2022-08-31 19:06:07 -07:00
Rémi Verschelde
1863bd88ad Merge pull request #703 from AlphaSoftLLC/fix_struct_forward_declaration 2022-08-31 13:04:03 +02:00
Rémi Verschelde
24f97739a1 Merge pull request #816 from bruvzg/get_set_props 2022-08-23 21:38:16 +02:00
Rémi Verschelde
9220e9dd34 Relicense integration testing project under public domain/Unlicense
Fixes #813.
2022-08-22 18:20:11 +02:00
bruvzg
270ad28931 Add support for _notification, _set, _get, _get_property_list, _property_can_revert, _property_get_revert, and _to_string methods. 2022-08-22 12:59:38 +03:00
bruvzg
f454253005 Merge pull request #814 from YuriSizov/object-expose-property-revert
Add support for `property_*_revert` methods
2022-08-19 18:48:37 +03:00
Yuri Sizov
fa111d7078 Add support for property_*_revert methods 2022-08-18 16:43:01 +03:00
Rémi Verschelde
8498f64a50 headers: Sync with upstream commit 11abffbf1 2022-08-10 17:43:20 +02:00
Hugo Locurcio
624aeae2d3 Add a more prominent warning about repository branches in README 2022-08-10 15:10:05 +02:00
Rémi Verschelde
8ba1c059da Merge pull request #803 from RiederAlex/fix-export-not-working
Fix wrong specifiers & filepaths in .gdextension, breaking the export
2022-08-07 19:19:12 +02:00
Alexander Rieder
4c85682c9d Fix wrong filepaths in .gdextension, breaking the export 2022-08-07 16:48:00 +02:00
Rémi Verschelde
9e210c1a02 Merge pull request #799 from Kev/qualify-classdb-friend
Allow GDCLASS in own namespaces
2022-07-31 15:14:22 +02:00
Kevin Smith
fd8173f109 Allow GDCLASS in own namespaces
The unqualified ClassDB friending was causing (at least for me on
VS2022) an implicit forward declaration of ClassDB in the namespace
of my class, instead of using the godot namespaced one. By qualifying
the namespace, this compiles for me.

Test-Information:
My project builds now.
2022-07-31 11:54:40 +01:00
Fabio Alessandrelli
9aa129caab Merge pull request #796 from Kev/windows-debug-symbols
Add debug information to Windows builds
2022-07-29 15:46:46 +02:00
Rémi Verschelde
54e1385729 Merge pull request #798 from Faless/fix/4.x_no_memnew_cb 2022-07-29 13:51:05 +02:00
Fabio Alessandrelli
78cbae910d Fix "_instance_bindings != nullptr" for Wrapped objects.
This is an attempt to make the lifecycle of wrapped objects clearer.
Godot keeps track of bindings' userdata for each object it creates.
This allows allocating the memory of the wrapper only once per object
even if that object is passed multiple times between binding code and
godot code.

The binding information is composed of multiple functions, this includes
a callback for when the userdata is to be allocated (called once) and
for when the userdata is to be deallocated (again, called once).

When allocating data with "memnew" we set the object bindings during the
postinitialize phase, but surely we shouldn't do that when allocating
the userdata as a result of bindings callback themselves.

Additionally, since we let Godot handle (and track) raw memory
allocation and de-allocation, we need to manually call the deconstructor
of the wrapper class during the free callback, to ensure that its
non-trivial members are correctly de-initialized.
2022-07-29 02:36:12 +02:00
Fabio Alessandrelli
8d4de1b537 Merge pull request #677 from lukas-toenne/fix_object_ptr_args
Fixed pointer indirection in the PtrToArg template for Object arguments.
2022-07-29 01:17:34 +02:00
Kevin Smith
7f44a1b44e Add debug information to Windows builds
Previously, Windows builds were being produced without debug
information, leading to somewhat unhelpful backtraces etc.
without symbols.

This builds the symbols in (only for debug builds - I've
deliberately not touched release builds here) so gdextension
bugs are a little more tractable.

Test-Information:
Have been running this patch for weeks, and getting useful
traces out on the commandline, and useful debugging from
debuggers.
2022-07-28 20:37:44 +01:00
Rémi Verschelde
89ca5440a2 headers: Sync with upstream commit 7281f0f23 2022-07-28 13:09:47 +02:00
Rémi Verschelde
80a5c4f322 Merge pull request #797 from Faless/fix/4.x_android_ci 2022-07-28 09:34:18 +02:00
Fabio Alessandrelli
0943dfc34a [CI] Fix Android builds after GH container update. 2022-07-28 06:30:04 +02:00
Rémi Verschelde
59fca06354 headers: Sync with upstream commit cc5135959 2022-07-27 14:36:57 +02:00
Rémi Verschelde
e87eb347ae Git hooks: Remove reference to unused pre-commit-make-rst
Fixes #795.
2022-07-26 10:21:08 +02:00
Fabio Alessandrelli
dcd4460c88 Merge pull request #794 from DNKpp/master
Object::cast_to checks provided object for nullptr
2022-07-26 09:24:57 +02:00
DNKpp
95574c1b11 fix: Object::cast_to checks provided object for nullptr 2022-07-26 00:41:57 +02:00
Rémi Verschelde
3cc1409210 Merge pull request #793 from bruvzg/v4_v4i_proj 2022-07-25 11:14:45 +02:00
Rémi Verschelde
a0b6203854 Merge pull request #790 from bruvzg/mac_rename 2022-07-21 10:25:43 +02:00
bruvzg
91c56a0ad1 Add bindings for Vector4, Vector4i, Projection built-in types. 2022-07-21 09:36:38 +03:00
bruvzg
0ee980abae Rename OSX to macOS. 2022-07-20 11:01:47 +03:00
Rémi Verschelde
8772a7faca Merge pull request #686 from ondy-personal/patch-1 2022-07-18 15:48:17 +02:00
Rémi Verschelde
4bd0dab16b Merge pull request #687 from jtcooper10/cmake-default-build-type-fix 2022-07-18 13:59:29 +02:00
Joshua Cooper
165ad14b0f CMake: fix CMAKE_BUILD_TYPE and BITS check 2022-07-18 13:01:04 +02:00
Rémi Verschelde
9b4519280a CMake: Fixup build after #732 2022-07-18 12:58:50 +02:00
Rémi Verschelde
3c73d1a7a2 CMake: Don't use -fPIC on Windows (#732) 2022-07-18 11:55:30 +02:00
Rémi Verschelde
c7a30aec03 CI: Use setup-python@v4 2022-07-18 11:42:01 +02:00
Rémi Verschelde
c2b35fb226 Makefile: Dehardcode -j4, SCons defaults to max - 1
Follow-up to #788.
2022-07-18 11:40:52 +02:00
Rémi Verschelde
3ceb321b8e Merge pull request #788 from akien-mga/scons-num_jobs-default-max 2022-07-17 15:43:50 +02:00
Rémi Verschelde
cdcd473371 SCons: Default num_jobs to max CPUs minus 1 if not specified
This doesn't change the behavior when `--jobs`/`-j` is specified as a
command-line argument or in `SCONSFLAGS`.

The SCons hack used to know if `num_jobs` was set by the user is derived
from the MongoDB setup.

We use `os.cpu_count()` for portability (available since Python 3.4).

With 4 CPUs or less, we use the max. With more than 4 we use max - 1 to
preserve some bandwidth for the user's other programs.
2022-07-17 12:37:13 +02:00
Rémi Verschelde
17c1d1fd50 headers: Sync with upstream commit 9904a9db5 2022-07-15 09:57:17 +02:00
Rémi Verschelde
c0fead40e9 Merge pull request #774 from Naryosha/patch-1 2022-07-14 23:59:53 +02:00
Rémi Verschelde
cc1a2e1986 headers: Sync with upstream commit 2c11e6d9e (4.0-alpha12) 2022-07-14 23:51:09 +02:00
Rémi Verschelde
9fc3fd7196 Merge pull request #783 from bruvzg/bitfields 2022-07-14 23:49:27 +02:00
Fabio Alessandrelli
cdc8f74939 Merge pull request #782 from Kev/build/support-clang-cl
Add clang-cl support
2022-07-12 21:58:24 +02:00
Kevin Smith
b038fe556b Add clang-cl support
Visual C++ has a clang-based driver, available through the
clang-cl wrapper (which provides the same interface as
cl) - this generates objects binary-compatible with the
default (traditional) driver, and can then be linked in
the normal way. As such, this patch simply configures for
MSVCC and then overwrites the cl compiler with clang-cl
in the environment.

Clang gives (subjectively) much more understandable compiler warnings
and errors than MSVCC, which was my motivation for switching.

Test-Information:
Builds for me with VS2022, and my gdextension library
builds and links.
2022-07-12 18:13:25 +01:00
bruvzg
713b122b84 Add support for BitField hint, sync API files. 2022-07-11 15:00:17 +03:00
Rémi Verschelde
bffedfed1e Fix typo in static method binding generator
Co-authored-by: bruvzg <7645683+bruvzg@users.noreply.github.com>
2022-07-08 15:30:23 +02:00
Rémi Verschelde
666a378336 Merge pull request #781 from Faless/build/4.x_msvc_clang_scons_ver 2022-07-05 18:06:24 +02:00
Fabio Alessandrelli
7901986dcf [SCons] Fix msvc, linux-clang, add version check. 2022-07-04 18:00:29 +02:00
Fabio Alessandrelli
794dea0dd7 Merge pull request #778 from alessandrofama/4.x_fix_static_no_return
Fix crash when using static methods without return value due to uninitialized GDNativePropertyInfo struct members
2022-07-03 21:11:35 +02:00
Alessandro Famà
d894f48f25 Fix crash when using static methods without return value 2022-07-03 17:00:43 +02:00
Rémi Verschelde
d8a65edc4a headers: Sync with upstream commit afdae67cc (4.0-alpha11) 2022-07-01 10:16:08 +02:00
Rémi Verschelde
89786cf032 Merge pull request #762 from Faless/build/4.x_scons_tools
[SCons] Move toolchains logic to tools folder, various improvements.
2022-06-27 21:50:29 +02:00
Fabio Alessandrelli
7850785ccb [SCons] Add iOS OSXCross support, min version override. 2022-06-27 20:44:12 +02:00
Fabio Alessandrelli
8dbfe03d17 [SCons] Add OSXCross tool. 2022-06-27 20:44:12 +02:00
Fabio Alessandrelli
93f2091185 [SCons] Move toolchains logic to tools folder. 2022-06-27 20:44:12 +02:00
Fabio Alessandrelli
a0fcd8a735 Add windows x86_32 library to example gdextension. 2022-06-27 20:44:12 +02:00
Rémi Verschelde
7adc5360d7 Merge pull request #771 from Faless/fix/4.x_mingw_export 2022-06-27 14:10:30 +02:00
Naryosha
832e04b93b Update register initializer/terminator in README
Referencing https://github.com/godotengine/godot-cpp/pull/750
2022-06-26 16:25:42 +07:00
Fabio Alessandrelli
5bbcd42378 Fix GDN_EXPORT define with mingw.
This commit changes the platform detection order to detect mingw
compiling for windows (which defines `__GNUC__`).

This commit also wraps the definition around a guard so it can be
overridden via a define at build-time.
2022-06-18 14:38:18 +02:00
Fabio Alessandrelli
40f5bfda22 Merge pull request #767 from Faless/headers/sync_alpha10
headers: Sync to Godot 4.0 alpha10.
2022-06-15 17:18:09 +02:00
Fabio Alessandrelli
4d99c82327 headers: Sync to Godot 4.0 alpha10. 2022-06-15 15:59:21 +02:00
Fabio Alessandrelli
4bebac4372 Merge pull request #766 from Faless/build/4.x_fix_android_runner
[SCons] Fix Android builds with modern NDKs.
2022-06-15 01:50:43 +02:00
Fabio Alessandrelli
b8ae658981 [SCons] Fix Android builds with modern NDKs. 2022-06-15 00:00:36 +02:00
Rémi Verschelde
8dbaf5a7ff Merge pull request #761 from bruvzg/sync_containers 2022-06-06 13:30:27 +02:00
bruvzg
e3119e7d05 Sync containers with new HashMap/HashSet, sync API headers. 2022-06-06 12:18:07 +03:00
Fabio Alessandrelli
851ec2f923 Merge pull request #759 from aaronfranke/scons-cpu-arch
Unify bits, android_arch, macos_arch ios_arch into arch, support non-x86 Linux
2022-06-05 13:31:13 +02:00
Aaron Franke
e5c4351bc7 Unify bits, android_arch, macos_arch ios_arch into arch, support non-x86
Unify arguments and add support for ARM64 and RV64 Linux
2022-06-01 13:00:25 -05:00
Rémi Verschelde
eaaf941c10 Merge pull request #757 from pooroligarch/master 2022-05-17 08:32:52 +02:00
Teodor Potancok
5c32dc3948 Cast Variant::Type to GDNativeVariantType 2022-05-17 07:01:43 +02:00
Rémi Verschelde
95a2303e37 headers: Sync with upstream commit 917fd65 (4.0-alpha8) 2022-05-12 12:28:02 +02:00
Rémi Verschelde
6f8e2308d5 Merge pull request #752 from bruvzg/bind_imp 2022-05-06 14:55:39 +02:00
bruvzg
031a83b0ea [Method Bind] Add support for default argument values and static method binding. Sync headers. 2022-05-06 10:17:51 +03:00
Fabio Alessandrelli
24e4aeb2c6 Merge pull request #746 from NicholasShatokhin/master
Build javascript target on windows host
2022-05-04 15:59:36 +02:00
Rémi Verschelde
d00e46966d Merge pull request #728 from bruvzg/double_pr_build 2022-05-04 15:57:59 +02:00
bruvzg
e06d5cd414 Add double precision build support. 2022-05-04 15:56:35 +03:00
Rémi Verschelde
f262ae9a6f Merge pull request #750 from bruvzg/init_levels
Change registered initializers / terminators to the single function with level argument.
2022-05-04 11:00:42 +02:00
bruvzg
8bf5a532de Change registered initializers / terminators to the single function with level argument. 2022-05-04 11:14:51 +03:00
Rémi Verschelde
20a17eb71d Merge pull request #748 from Faless/build/4.x_deps 2022-05-03 11:56:30 +02:00
Fabio Alessandrelli
fa698ddd12 [Scons] Use builder to track bindings regeneration.
Using a scons Builder we now regenerate the bindings automatically
when the Godot API json or header has changed.

The option to force bindings regeneration (generate_bindings=yes) is
retained.
2022-05-03 10:48:23 +02:00
Rémi Verschelde
1ad24f1d5d Merge pull request #749 from Faless/ci/4.x_black 2022-05-03 09:19:42 +02:00
Fabio Alessandrelli
b47dfb6a5c [CI] Add python file format to static checks.
Uses the same version of `black` as godot.
2022-05-02 21:13:56 +02:00
Mykola Shatokhin
b2331e1f6d Build javascript target on windows host 2022-05-01 00:35:42 +03:00
Rémi Verschelde
0b050442da headers: Sync with upstream commit 3e9ead0 (4.0-alpha7) 2022-04-29 19:57:26 +02:00
Fabio Alessandrelli
2cf7cf1304 Merge pull request #743 from Faless/build/4.x_no_duplicates
[CI] Remove duplicate builds.
2022-04-27 17:49:00 +02:00
Fabio Alessandrelli
69aefe5c79 [CI] Remove duplicate builds.
Leftovers from the CI matrix PR.
2022-04-27 07:32:27 +02:00
Rémi Verschelde
6123a61a49 Merge pull request #738 from akien-mga/color-clarify-srgb-linear-conversions 2022-04-13 14:41:29 +02:00
Rémi Verschelde
24f5cd2d48 Color: Rename to_srgb/to_linear to include base color space
Counterpart to https://github.com/godotengine/godot/pull/60199.
Also syncs the extension API with that PR.
2022-04-13 12:50:21 +02:00
Rémi Verschelde
60037decc3 Merge pull request #737 from godotengine/dependabot/github_actions/actions/upload-artifact-3 2022-04-09 17:06:14 +02:00
dependabot[bot]
4963e6f3fc Bump actions/upload-artifact from 2 to 3
Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 2 to 3.
- [Release notes](https://github.com/actions/upload-artifact/releases)
- [Commits](https://github.com/actions/upload-artifact/compare/v2...v3)

---
updated-dependencies:
- dependency-name: actions/upload-artifact
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-04-08 19:14:25 +00:00
Rémi Verschelde
fad357bbe6 Merge pull request #734 from bruvzg/var_ret 2022-03-30 15:38:03 +02:00
bruvzg
057a771fda Add support for variadic method binds with the typed return. Sync headers. 2022-03-30 15:11:28 +03:00
Pxl
b7ade95edc Update CMakeLists.txt
fix compile fail when windows with llvm+ninja
2022-03-26 13:09:25 +08:00
Rémi Verschelde
5eb1c54116 Merge pull request #730 from bruvzg/static_no_return 2022-03-25 13:35:23 +01:00
bruvzg
d9d68550d9 Fix generating static methods without return value. 2022-03-25 14:13:45 +02:00
Rémi Verschelde
3d4d004fb6 Merge pull request #729 from bruvzg/static_methods
Add support for static method bindings.
2022-03-24 18:35:23 +01:00
bruvzg
28027394f5 Add support for static method bindings. 2022-03-22 16:06:13 +02:00
Rémi Verschelde
c6109fb08e Merge pull request #726 from bruvzg/fix_build_after_59140
Sync godot-headers and fix build after "Create GDExtension clases for PhysicsServer3D".
2022-03-16 19:48:34 +01:00
bruvzg
93de1b2b0b Sync godot-headers and fix build after "Create GDExtension clases for PhysicsServer3D". 2022-03-16 20:33:06 +02:00
Rémi Verschelde
7bcf579a37 Merge pull request #724 from bruvzg/fix-after-expose-more-gdextension 2022-03-16 10:39:40 +01:00
bruvzg
817efdd484 Fix build after "Discern between VIRTUAL and ABSTRACT class bindings". 2022-03-15 13:43:12 +02:00
Rémi Verschelde
13603e4050 Merge pull request #725 from akien-mga/remove-headers-submodule 2022-03-15 12:33:14 +01:00
Rémi Verschelde
c4f12ccc3c Remove godot-headers submodule, copy files directly
With the new GDExtension API, the headers are just two files, one of
which is generated and needs to always be kept in sync with the Godot
engine version.

So there's little practical use for using godot-headers as a submodule
anymore, and it only makes godot-cpp updates more cumbersome.

Custom headers (i.e. a custom API JSON) can still be used by passing
the `headers_dir` SCons option.
2022-03-15 10:19:07 +01:00
Rémi Verschelde
82bc102581 Sync misc/ scripts and hooks with upstream Godot 2022-03-15 10:18:33 +01:00
Rémi Verschelde
1632322ce0 Update copyright year 2022-03-15 10:17:53 +01:00
Rémi Verschelde
b869ef660f Merge pull request #717 from godotengine/dependabot/github_actions/actions/checkout-3 2022-03-09 17:51:39 +01:00
Rémi Verschelde
5f1030d119 Merge pull request #720 from bruvzg/get_instance 2022-03-09 17:51:32 +01:00
Rémi Verschelde
f4d2bfd77b Merge pull request #721 from bruvzg/fix_return_type_encoding 2022-03-09 17:51:02 +01:00
bruvzg
b8b9a2fad9 Fix return type encoding for ptrcall. 2022-03-09 17:18:21 +02:00
Rémi Verschelde
024f09e1ea Merge pull request #723 from akien-mga/ci-install-mingw-via-actions 2022-03-09 16:16:38 +01:00
Rémi Verschelde
3846201fbb CI: Install MinGW via egor-tensin/setup-mingw
Scoop install is being problematic since their 0.1.0 release.
2022-03-09 13:36:33 +01:00
Rémi Verschelde
b6c18d489d headers: Sync with upstream commit f470979 (4.0-alpha4) 2022-03-08 16:15:07 +01:00
bruvzg
b1385953fe Add ObjectDB::get_instance method to get wrapped Object * from ObjectID. 2022-03-08 10:17:33 +02:00
Rémi Verschelde
2f3ead0281 Merge pull request #719 from codecat/fix-method-bind-crash 2022-03-04 13:52:44 +01:00
Melissa Geels
d97dc518d3 Fixed crash on release builds due to missing argument type information 2022-03-02 14:44:23 +01:00
dependabot[bot]
73ef81a8de Bump actions/checkout from 2 to 3
Bumps [actions/checkout](https://github.com/actions/checkout) from 2 to 3.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v2...v3)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-03-01 19:09:09 +00:00
Rémi Verschelde
4368f14e9d Merge pull request #716 from godotengine/dependabot/github_actions/actions/setup-python-3 2022-03-01 01:53:52 +01:00
Rémi Verschelde
3b5ea2f423 Merge pull request #715 from groud/reorder_native_initialization 2022-03-01 01:53:25 +01:00
dependabot[bot]
0987fd6b0e Bump actions/setup-python from 2 to 3
Bumps [actions/setup-python](https://github.com/actions/setup-python) from 2 to 3.
- [Release notes](https://github.com/actions/setup-python/releases)
- [Commits](https://github.com/actions/setup-python/compare/v2...v3)

---
updated-dependencies:
- dependency-name: actions/setup-python
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-02-28 19:07:08 +00:00
Gilles Roudière
a94148ca4c Reorder native extension initialization steps 2022-02-28 15:44:54 +01:00
Rémi Verschelde
1cbf121b08 Merge pull request #712 from aaronfranke/black
[master] Run black format on SConstruct files and bindings generator
2022-02-26 23:44:54 +01:00
Aaron Franke
101d61b64a [master] Run black format on SConstruct files and bindings generator 2022-02-26 15:04:11 -06:00
Rémi Verschelde
8ead641b08 headers: Sync with upstream commit 256069e (4.0-alpha3) 2022-02-23 09:13:12 +01:00
Rémi Verschelde
d154ffbe86 Merge pull request #708 from Zylann/fix_inheriting_class_with_namespace 2022-02-21 11:27:31 +01:00
Rémi Verschelde
76bad22978 Merge pull request #701 from bruvzg/port_templates 2022-02-21 11:25:40 +01:00
Rémi Verschelde
1f03394643 Merge pull request #683 from nicoraf/test_cmake_windows 2022-02-21 00:16:16 +01:00
Nicolás Carrasco
df87396cf3 Merge branch 'master' of https://github.com/godotengine/godot-cpp into test_cmake_windows 2022-02-20 22:59:56 +01:00
Marc Gilleron
6fdcb18f6a Fix GDCLASS when inherited class is in another namespace 2022-02-20 19:33:00 +00:00
Rémi Verschelde
4d9fe6dfaa Merge pull request #707 from akien-mga/vec2-vec3-forward-declares 2022-02-20 13:28:57 +01:00
Rémi Verschelde
7e3321d1b2 Use forward declares for vector math types
Adds operators to convert from int vector types to float vector types
as done in the upstream engine implementations.
2022-02-20 12:04:08 +01:00
Rémi Verschelde
917b0c2ca3 Merge pull request #688 from zhehangd/master 2022-02-19 16:31:32 +01:00
bruvzg
e36180f377 Port a bunch of Godot container templates to GDExtension. 2022-02-18 21:07:53 +02:00
Rémi Verschelde
6a464b53f1 Merge pull request #706 from bruvzg/str_errors 2022-02-17 10:15:14 +01:00
bruvzg
65dc3e89c7 Add ERR_ macros variants using String messages. 2022-02-17 10:18:04 +02:00
Rémi Verschelde
6f9d3c31d0 Merge pull request #705 from bruvzg/fix_c_build 2022-02-16 14:31:26 +01:00
Rémi Verschelde
7fa81e798b Merge pull request #704 from bruvzg/fix_const_ptr 2022-02-16 13:29:29 +01:00
Rémi Verschelde
d9111350b9 Merge pull request #699 from bruvzg/enum_and_ptr_binds 2022-02-16 12:32:26 +01:00
bruvzg
3bb86f1e01 Use C++17 flag only for C++ files. 2022-02-16 13:12:10 +02:00
bruvzg
a8cd21ac07 Fix "const" NativePtr binds. 2022-02-16 11:35:13 +02:00
Nikita Parfenov
309db943e9 Native structures forward declaration fix 2022-02-16 15:29:01 +06:00
Rémi Verschelde
9bc489eb2a Merge pull request #695 from bruvzg/ptrs_and_stuff 2022-02-15 10:15:28 +01:00
bruvzg
7aaab11b0f Add Variant binders for the generated classes, structs and global enums 2022-02-15 10:47:12 +02:00
bruvzg
bf8fc4c53d Add ptr() / ptrw() to the arrays, add missing String methods, add missing CharString method implementations. 2022-02-14 23:17:21 +02:00
Rémi Verschelde
be34bcfff1 Merge pull request #696 from bruvzg/macos_demo_fw 2022-02-14 11:40:37 +01:00
bruvzg
b6b64bcd70 [macOS] Restore demo library output names. 2022-02-14 08:57:35 +02:00
Rémi Verschelde
63531a89b1 Merge pull request #690 from Faless/build/fix_suffix 2022-02-10 12:51:21 +01:00
Fabio Alessandrelli
f5172016b8 [Build] Fix exposed suffix, remove unused option. 2022-02-10 07:36:26 +01:00
Fabio Alessandrelli
9d5caf6baa Merge pull request #636 from Faless/build/tools_pr
Android/iOS build, Scons boilerplate for building projects.
2022-02-10 02:39:22 +01:00
Fabio Alessandrelli
90b7d056ee [CI] Use matrix for builds. 2022-02-10 01:44:48 +01:00
Fabio Alessandrelli
dcc52f4321 Library SCons boilerplate to build projects.
Works by executing project `SConstruct`s file in a cloned env (a bit
like Godot does for modules) so you don't have to worry about platform
and toolchain setup.

Convert the project test file to work as submodule, add it to CI

Run with:

```
scons build_projects=test,/path/to/other/project
```
2022-02-10 01:44:48 +01:00
Fabio Alessandrelli
cf3fcab6b4 Always require C++17. Shuold fix other platforms. 2022-02-10 00:19:01 +01:00
Rémi Verschelde
75b180d2cd headers: Sync with upstream commit 79077e6 (4.0-alpha2) 2022-02-09 16:46:48 +01:00
Zhehang Ding
df0e28fe43 Add missing Vector2::operator Vector2i() 2022-02-07 01:23:18 -08:00
Zhehang Ding
24c94e4af0 Add missing Vector3::operator Vector3i 2022-02-07 00:31:48 -08:00
ondy-personal
3d237fc7d7 Fixed crash when called methods return nullptr.
The returned value "ret" may be nullptr in which case the code would crash because "object_get_instance_binding" can't be called on nullptr input.

This should be very easy to reproduce, I encountered it pretty much any time I called a method that returned Ref<Something>. E.g.:

Ref<GeometryInstance3D> instance;
instance.instantiate();
instance.get_mesh();    // Crash because no mesh was set for the instance and the returned value was nullptr.
2022-01-31 17:12:45 -08:00
Hugo Locurcio
4dddd0b55b Merge pull request #685 from paddy-exe/master 2022-01-29 17:21:33 +01:00
Patrick Exner
31eddf9e87 Update README file for macos support 2022-01-29 17:03:35 +01:00
Bastiaan Olij
4e2411ad98 headers: Sync with upstream commit 9f5c18c 2022-01-27 09:56:46 +11:00
Nicolás Carrasco
f227a0179f Fix Test CMake project for Windows and parametrize paths 2022-01-26 20:12:05 +01:00
Hugo Locurcio
b9b606d271 Merge pull request #675 from Ivorforce/patch-2 2022-01-26 18:47:13 +01:00
Rémi Verschelde
2ce688d2ad headers: Sync with upstream commit 31a7ddb (4.0-alpha1) 2022-01-23 23:28:40 +01:00
Rémi Verschelde
dfa395c5ed Merge pull request #682 from bruvzg/macos_demo 2022-01-11 10:08:04 +01:00
bruvzg
a263344653 [Demo Project] Add macOS framework templates, update Scons build script and ".gdextension" file. 2022-01-11 10:42:04 +02:00
Rémi Verschelde
02d98387a1 headers: Sync with upstream commit fcc2648 2022-01-07 14:29:15 +01:00
Lukas Tönne
836cc4d3dc Fix for pointer indirection in the Ref<T> template.
Patch by Nana Sakisaka (saki7).
2022-01-07 09:20:05 +01:00
Rémi Verschelde
cfd3fa97d1 Merge pull request #668 from groud/fix_extension_instance_set 2022-01-06 17:44:29 +01:00
Lukas Tönne
5fa9b765dc Fixed pointer indirection in the PtrToArg template for Object arguments. 2022-01-02 17:10:32 +01:00
Ivorius
3475ad69b3 In CMakeLists, use the new FindPython3 instead of FindPython 2021-12-29 15:02:38 +01:00
O01eg
c5fd3d00d2 Test CMake project with CI (#518) 2021-12-24 01:29:21 +01:00
Rémi Verschelde
e07d3b9a97 Merge pull request #672 from bradc6/bugfix/NormalizedNorspaceInMacros 2021-12-20 15:45:07 +01:00
Bradley Clemetson
76c4adb7f8 Normalized additional macros to ensure that everything works without client code needing using 2021-12-18 15:16:14 -08:00
Rémi Verschelde
f3315aeff6 Merge pull request #671 from bradc6/bugfix/ConsistentNamespace 2021-12-16 10:45:59 +01:00
Rémi Verschelde
f32d95b6d9 Merge pull request #670 from bradc6/bugfix/CmakeGenerator 2021-12-13 10:54:01 +01:00
Bradley Clemetson
37938a1761 Fix namespace to be consistent with the previous ADD functions 2021-12-12 18:23:33 -08:00
Bradley Clemetson
c608277bcf Require at least python 3 2021-12-11 15:32:49 -08:00
Gilles Roudière
adbbf1a3a1 Fix object_set_instance being wrongly called for built-in wrapped classes 2021-12-06 15:40:19 +01:00
Rémi Verschelde
f58a2f25a2 Merge pull request #663 from groud/move_godot_object_init_to_extension 2021-12-03 16:24:42 +01:00
Gilles Roudière
3fcb8a4d1e Make extension instances create the corresponding godot object in their constructor 2021-12-03 15:37:49 +01:00
Bastiaan Olij
50512f0dee Merge pull request #659 from groud/fix_null_init
Avoid crash in Variant constructor from nullptr Object*
2021-11-25 11:16:55 +11:00
Rémi Verschelde
d619c612d5 Merge pull request #661 from Calinou/scons-warn-unknown-variables 2021-11-24 14:50:02 +01:00
Hugo Locurcio
1e2eafe777 Print a warning with unknown SCons variables to ease troubleshooting 2021-11-23 22:41:52 +01:00
Gilles Roudière
55ba2602db Avoid crash in Variant constructor from nullptr Object* 2021-11-23 11:01:49 +01:00
Rémi Verschelde
adbc0bfe00 Merge pull request #656 from BastiaanOlij/dictionary_index 2021-11-23 10:07:07 +01:00
Bastiaan Olij
b008810c01 Implementing dictionary operators 2021-11-23 19:44:53 +11:00
Rémi Verschelde
5cacce7a26 Merge pull request #650 from BastiaanOlij/fix_compile_warnings 2021-11-22 12:22:24 +01:00
Bastiaan Olij
94efe3d410 Fixing compiler warnings around implicit type casting loosing precision 2021-11-22 21:48:20 +11:00
Rémi Verschelde
8d25e04d28 Merge pull request #627 from BastiaanOlij/array_operator 2021-11-17 11:04:32 +01:00
Bastiaan Olij
c2b690439f Implement index operators for Arrays 2021-11-12 14:29:54 +11:00
Rémi Verschelde
271e33658d Merge pull request #649 from RedwanFox/windows_fix_cmake_configuration 2021-11-11 13:58:26 +01:00
Nickolai Korshunov
5336c7e97b synced windows compile definitions with scons configuration
df9164b9bd
2021-11-11 15:19:16 +03:00
Rémi Verschelde
fd76008f63 Merge pull request #646 from BastiaanOlij/add_array_make 2021-11-10 08:53:24 +01:00
Rémi Verschelde
7d01234211 headers: Sync with upstream commit 3abb5a9 2021-11-04 15:43:03 +01:00
Rémi Verschelde
b3c7581cf9 Add .gitignore for test, ignore potential log files
(cherry picked from commit 1070a29d77)
2021-11-04 15:42:27 +01:00
Bastiaan Olij
957f86c3e3 Add Array:make macro 2021-11-02 00:20:19 +11:00
Rémi Verschelde
b1dbaad396 Merge pull request #644 from BastiaanOlij/rename_interface 2021-10-28 11:12:07 +02:00
Bastiaan Olij
ef528d3a86 Rename interface to gdn_interface because it's a defined keyword under windows 2021-10-28 19:44:20 +11:00
Bastiaan Olij
5148aad3d4 headers: Sync with upstream commit 92a2380 2021-10-25 20:27:03 +11:00
Rémi Verschelde
c7fc804112 headers: Sync with upstream commit a4e1a07 2021-10-16 17:36:37 +02:00
Rémi Verschelde
d9e643db2b Merge pull request #639 from Shatur/rework-cmake-debug-flags 2021-10-04 09:14:18 +02:00
Hennadii Chernyshchyk
2f92b4a37d Rework debug flags for CMake
* Attach debug flags to the target and mark as `PUBLIC`. This will allow all
  projects that use bindings not to add the same defines manually.
* Use generator-expressions to support multiconfig generators (such as
  MSVC).
* Remove excplitic `NDEBUG` and `_DEBUG` flags, CMake handles it
  automatically.
2021-10-03 17:30:37 +03:00
Rémi Verschelde
230fd4bc08 Merge pull request #634 from Faless/osx/universal 2021-10-01 07:37:42 +02:00
Fabio Alessandrelli
480ad9ffed [CI] Make OSX universal build instead 2 builds. 2021-09-29 22:35:09 +02:00
Fabio Alessandrelli
67f9109d1f [OSX] Add universal build support. 2021-09-29 22:31:12 +02:00
Rémi Verschelde
ad11bbb584 Merge pull request #632 from BastiaanOlij/debug_and_release 2021-09-29 08:10:05 +02:00
Bastiaan Olij
0f47ba54ee Setup for building both debug and release build for side by side deployment 2021-09-29 10:47:08 +10:00
Rémi Verschelde
6a720e5c7c Merge pull request #631 from Faless/ext/ref_casting_2 2021-09-28 16:14:45 +02:00
Fabio Alessandrelli
3cebc33414 Merge pull request #625 from Faless/ext/pointers
Add pointers support for virtual methods.
2021-09-28 16:01:38 +02:00
Fabio Alessandrelli
b28853aff1 Add test for Reference passing/returning. 2021-09-28 15:49:53 +02:00
Fabio Alessandrelli
b90d0ac555 Add Ref<T> binding support.
Added PtrToArg and GetTypeInfo adapted from Godot.
2021-09-28 15:49:08 +02:00
Rémi Verschelde
5826fd5259 Merge pull request #626 from Shatur/use-default 2021-09-28 09:11:39 +02:00
Hennadii Chernyshchyk
1f96a0d16c Use default destructor for Object 2021-09-28 09:59:17 +03:00
Fabio Alessandrelli
80fdb9146f Add pointers support for virtual methods.
As introduced in godot for virtual methods.
Custom structs are not yet supported.
2021-09-27 16:13:24 +02:00
Bastiaan Olij
a44e9aa3f9 Merge pull request #602 from vnen/gdnative-extensions
Bindings for the new extension system
2021-09-27 23:26:31 +10:00
Bastiaan Olij
d5e0fc8e7c Temporary fix for issue in JSON export with NIL in operators 2021-09-27 23:08:12 +10:00
Bastiaan Olij
92d25bcda6 Update readme to include new info 2021-09-27 23:08:12 +10:00
Bastiaan Olij
68ebc9b2a8 Changed over to proper godot-headers 2021-09-27 23:08:12 +10:00
Bastiaan Olij
cbf52c2764 Removed init.cpp that I overlooked in rebase 2021-09-27 23:08:12 +10:00
Bastiaan Olij
0e3bc393d5 Fully register class on register_class call 2021-09-27 23:08:12 +10:00
Bastiaan Olij
fad6329699 Implement Ref copy constructor 2021-09-27 23:08:12 +10:00
Fabio Alessandrelli
ea7324afe8 Fix encoding/decoding of null objects. 2021-09-27 23:08:12 +10:00
Fabio Alessandrelli
59d38a4119 Add test for extended object creation/deletion. 2021-09-27 23:08:12 +10:00
Fabio Alessandrelli
42dd64f22f Fix binding of function that takes Object * parameters. 2021-09-27 23:08:11 +10:00
Fabio Alessandrelli
b4632e317d Fix creation (and godot-side deletion) of extended objects.
Proper initialization for godot-cpp classes with memnew.

Extension classes (i.e. the `GDCLASS` macro) behave differently from
regular wrapped classes, and requires Godot to initialize them during
object construction.

This commit update the GDCLASS macro to not create/destroy the instance
during the bindings callback, but during the extension callbacks.

When setting the object instance, the bindings instance is set to the
pointer of the extension instance so that it can later be retrieved
normally via `object_get_instance_bindings`.
2021-09-27 23:08:11 +10:00
Fabio Alessandrelli
cc88df05e7 Fix PtrToArg encoding for Object *.
It didn't set the return value at all, changing the local value instead.
Now instead correctly sets it as a generic pointer type from `_owner`.
2021-09-27 23:08:11 +10:00
Hennadii Chernyshchyk
2b1100c878 Use default initialization
{ 0 } initializes only first element with zero explicitly and other
elements with their default value (zeros too). Technically it will work
the same, but will be more correct.
2021-09-27 23:08:11 +10:00
Bastiaan Olij
7a2a7ea9e4 Add virtual destructor to Object class 2021-09-27 23:08:11 +10:00
Bastiaan Olij
b21069c573 _err_print_error only output p_message so swapped parameters around 2021-09-27 23:08:11 +10:00
Bastiaan Olij
fab017c91a Fix some clang format things 2021-09-27 23:08:11 +10:00
George Marques
38ee8bfcf7 Change constructor/destructor management of extension classes
This makes sure custom constructors are always called on extension
classes. However, note that constructors should not take any parameters,
since Godot doesn't support that. Parameters are ignore in memnew macro.

Use memnew(MyClass()) instead of memnew(MyClass) since it now needs a
value instead of a class name. This macro calls MyClass::_new() (define
in GDCLASS macro) which ultimately calls Godot to create the object,
ensuring that both the Godot and the extension instances are created.

Non Godot classes (that don't derive godot::Object) are constructed as
usual an can have parameters.

memdelete is also changed for the same reason, as it needs to destroy
the Godot object as well, and that automatically frees the bound
extension instance.
2021-09-27 23:08:11 +10:00
Bastiaan Olij
e839199848 Add support for property groups 2021-09-27 23:08:11 +10:00
Bastiaan Olij
02802b1d0e Add in driver types and rejig code to make it easier to extend 2021-09-27 23:08:11 +10:00
George Marques
aef0f1e248 Change initialization to allow custom level callbacks
Now it needs a callback for each level so custom logic (like loading
singletons) can be performed.
2021-09-27 23:08:10 +10:00
George Marques
dfa526ce16 Fix formatting of files 2021-09-27 23:08:10 +10:00
George Marques
f5858ef6c6 Fix calling of native functions that return object types 2021-09-27 23:08:10 +10:00
Bastiaan Olij
46c63af715 Re-introduce build-in type code for core types 2021-09-27 23:08:10 +10:00
Bastiaan Olij
3a5bd21092 Always convert float to double 2021-09-27 23:08:10 +10:00
Hennadii Chernyshchyk
50774cf0fb Add alias 2021-09-27 23:08:10 +10:00
Hennadii Chernyshchyk
f24dcf4ff9 Specify project languages 2021-09-27 23:08:10 +10:00
Hennadii Chernyshchyk
3b40a38c66 Remove Generating Bindings message
Bindings are generated using `generate_bindings` and the command contains the `COMMENT` parameter, which will display a message about the generation.
2021-09-27 23:08:10 +10:00
George Marques
8eb6f129f8 Set initialization level to CORE
This should eventually be configurable with user callbacks, but for now
assume the lowest level to ensure the initialization is called.
2021-09-27 23:08:10 +10:00
Hennadii Chernyshchyk
e8030ed1cf Fix print file list 2021-09-27 23:08:10 +10:00
Hennadii Chernyshchyk
b7f03837a2 Fix return type check for variadic functions 2021-09-27 23:08:09 +10:00
Hennadii Chernyshchyk
6daaeb6dba Do not override build path 2021-09-27 23:08:09 +10:00
Hennadii Chernyshchyk
a904518075 Fix OUTPUT for add_custom_command 2021-09-27 23:08:09 +10:00
Bastiaan Olij
b07559882c Silence delete compile warning in memory.h/cpp on Windows 2021-09-27 23:08:09 +10:00
Bastiaan Olij
dd72ce151a Remove unused import that breaks on windows 2021-09-27 23:08:09 +10:00
George Marques
9d4e51011a Properly encode numeric POD types 2021-09-27 23:08:09 +10:00
George Marques
f19bb9f57c Add copy/move constructors and assignment op to builtin types 2021-09-27 23:08:09 +10:00
George Marques
3a9ff8de7a Add support for engine singletons
Use, e.g. Engine::get_singleton() to get the singleton object();
2021-09-27 23:08:09 +10:00
George Marques
feafe0da36 Fix build with native structs 2021-09-27 23:08:09 +10:00
Bastiaan Olij
df9164b9bd Added TYPED_METHOD_BIND and c++17 flags to windows build and moved test project files 2021-09-27 23:08:09 +10:00
George Marques
f3dea4b752 Add readme file (stub) 2021-09-27 23:08:08 +10:00
George Marques
5615c92173 Define the {de,}initialization functions in the bindings
The extension creators then don't need to create those just to redirect
to the bindings.
2021-09-27 23:08:08 +10:00
George Marques
a0634cca3f Auto-bind virtual method overrides 2021-09-27 23:08:08 +10:00
George Marques
b3a4a2cf93 Add sample test project 2021-09-27 23:08:08 +10:00
George Marques
8bcf32a619 Fix issues with method calls 2021-09-27 23:08:08 +10:00
George Marques
e4ed48976a Replace bindgins to work with extensions 2021-09-27 23:08:08 +10:00
Rémi Verschelde
ee70866894 Merge pull request #622 from akien-mga/ci-disable-tests-4.0 2021-09-27 14:43:28 +02:00
Rémi Verschelde
bd82460780 CI: Disable test build to prepare for 4.0 extensions merge
It can't pass and fixing it in the heavily WIP extensions implementation
would be a hassle, it's better to readd tests once things are working.
2021-09-27 14:37:36 +02:00
Rémi Verschelde
bfdf55afd9 Merge pull request #620 from akien-mga/bindgen-fix-NodePath-escape 2021-09-27 12:51:07 +02:00
Rémi Verschelde
b8658d3733 Merge pull request #619 from BastiaanOlij/update_godot_3_info 2021-09-27 12:43:50 +02:00
Rémi Verschelde
83ef64079b bindgen: Properly escape NodePath in default args 2021-09-27 12:41:46 +02:00
Bastiaan Olij
74cee6e6b7 Updating readme for new branch info 2021-09-27 20:28:16 +10:00
Rémi Verschelde
4e8508ad53 Fixup style after #563 2021-09-27 12:26:32 +02:00
Rémi Verschelde
407710b622 Merge pull request #513 from beroso/fix/windows_cpp_17 2021-09-27 11:50:12 +02:00
Rémi Verschelde
907d35126e Merge pull request #538 from anunknowperson/patch-1 2021-09-27 11:44:43 +02:00
Rémi Verschelde
228014bec8 Merge pull request #547 from piiertho/hotfix/add-android-missing-toolchain-elements 2021-09-27 11:42:39 +02:00
Rémi Verschelde
3de367920f Merge pull request #563 from LinwoodCloud/master 2021-09-27 11:41:41 +02:00
Rémi Verschelde
055f3141f8 Merge pull request #588 from aaronfranke/signal-no-arg 2021-09-27 11:34:08 +02:00
Rémi Verschelde
7a693df988 Merge pull request #601 from colugomusic/fix-string-args-constness 2021-09-27 11:31:56 +02:00
Rémi Verschelde
0fba89df67 Merge pull request #595 from Calinou/add-license-headers 2021-09-27 11:31:31 +02:00
Rémi Verschelde
c109d4e5dc Merge pull request #607 from samsface/master 2021-09-27 11:24:07 +02:00
Rémi Verschelde
654836a135 Merge pull request #587 from Faless/fix/osx_names 2021-09-27 11:22:13 +02:00
Rémi Verschelde
402e33a7dc headers: Track tag godot-3.3.3-stable 2021-09-26 13:20:50 +02:00
Rémi Verschelde
e96e49e63b Merge pull request #618 from akien-mga/ci-tests-godot-3.3.3 2021-09-26 13:16:24 +02:00
Rémi Verschelde
d9477fd0aa CI: Run tests with Godot 3.3.3 2021-09-26 12:43:41 +02:00
Rémi Verschelde
6e013e415d Merge pull request #617 from akien-mga/ci-linux-ubuntu-18.04 2021-09-26 12:40:46 +02:00
Rémi Verschelde
4b6ab10c5d CI: Update Linux runner to Ubuntu 18.04
Also cleanup needlessly specific dependencies.
2021-09-26 12:15:19 +02:00
Bastiaan Olij
1bb06e8507 Merge pull request #616 from raulsntos/fix-enum-params
Escape parameters named `enum`.
2021-09-23 09:54:33 +10:00
Raul Santos
54c2d23572 Escape parameters named enum.
Prefix parameters named `enum` with an underscore like all the other
reserved keywords.
2021-09-22 16:07:23 +02:00
Fabio Alessandrelli
466f2cdebf Merge pull request #590 from Faless/generator/fix_byte_array_default
Fix binding when default parameter is a PoolByteArray.
2021-09-07 20:08:56 +02:00
Bastiaan Olij
6e1af3bedb Merge pull request #594 from Calinou/error-list-remove-extraneous-values
Remove extraneous Error enum values that were removed in Godot 3.0
2021-09-04 23:31:38 +10:00
BoomerDev
8efe619e3a Fix typo in README.md (#608) 2021-09-03 16:43:01 +02:00
Sam
6b31e67dd3 Fix Clang 11 build failure over -Wabsolute-value 2021-09-01 23:08:30 +01:00
Colugo
bba8393af7 Fix argument constness in String::begins_with, String::ends_with 2021-08-22 16:02:14 +01:00
Hugo Locurcio
cf5428e103 Add license headers to all source and header files
This is consistent with the core Godot source code, and ensures the
license isn't detached from its original code when individual files
are distributed.
2021-08-02 18:34:58 +02:00
Hugo Locurcio
abab0715a0 Remove extraneous Error enum values that were removed in Godot 3.0 2021-08-02 18:23:41 +02:00
Hugo Locurcio
b56df8f6da Merge pull request #593 from maiself/fix-crash-cond
Fix typo in CRASH_COND leading to unexpected continuation after fail
2021-08-02 18:07:23 +02:00
Mai Lavelle
2f534ddd88 Fix typo in CRASH_COND leading to unexpected continuation after fail 2021-08-01 17:20:39 -04:00
Fabio Alessandrelli
024ffef50f Fix binding when default parameter is a PoolByteArray.
Like done for the other pool array types.
2021-07-17 18:06:50 +02:00
Aaron Franke
95ff72706d Add ability to easily register signals with no arguments 2021-07-10 19:23:36 -04:00
Fabio Alessandrelli
1db7630d01 Fix OSX library name for arm64.
Was always `.64`, it's now `.arm64` for M1.
2021-07-10 19:02:52 +02:00
Fabio Alessandrelli
e08ecdc28c Merge pull request #584 from Faless/build/osx_arm64
Add OSX arm64 build target.
2021-07-09 16:03:49 +02:00
Fabio Alessandrelli
784103f676 Merge pull request #581 from Faless/build/optimization_flags
Add optimization flags for android and javascript.
2021-07-09 16:01:47 +02:00
Fabio Alessandrelli
98124aafe8 Merge pull request #580 from Faless/js/fix_suffix
Fix JavaScript library suffix.
2021-07-09 15:51:51 +02:00
Fabio Alessandrelli
5b8bcb7164 Add OSX arm64 build target.
New "macos_arch" to specify the desired arch, and "macos_sdk_path" to
override the default SDK path.
2021-07-07 11:08:33 +02:00
Fabio Alessandrelli
e5279d3d0f Add optimization flags for android and javascript. 2021-07-05 15:53:52 +02:00
Fabio Alessandrelli
26d4df4e17 Fix JavaScript library suffix.
Also add `.bc` files to `.gitignore`
2021-07-05 15:47:49 +02:00
dependabot[bot]
dbf3a13d0f Bump actions/upload-artifact from 2.2.3 to 2.2.4 (#571)
Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 2.2.3 to 2.2.4.
- [Release notes](https://github.com/actions/upload-artifact/releases)
- [Commits](https://github.com/actions/upload-artifact/compare/v2.2.3...v2.2.4)

---
updated-dependencies:
- dependency-name: actions/upload-artifact
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-06-16 21:41:21 +02:00
Marc
fda7ddd158 Merge pull request #567 from DhruvMaroo/string
added String's move constructor and move assignment operator
2021-06-01 23:35:46 +01:00
DhruvMaroo
7a1890345b edited according to clang-format 2021-06-01 23:16:09 +05:30
Marc
59959b1a5b Merge pull request #566 from DhruvMaroo/master
added inverse trigonometric functions in Math.hpp
2021-06-01 18:08:59 +01:00
DhruvMaroo
67e2c6145c used godot_string_new_copy to copy 2021-05-31 09:31:11 +05:30
DhruvMaroo
b44b98a94c removed _deleted class member 2021-05-31 09:10:59 +05:30
DhruvMaroo
cd05371ce8 added class member, safety check in the destructor 2021-05-31 00:52:36 +05:30
DhruvMaroo
492285f681 changed spaces to tabs 2021-05-30 22:29:41 +05:30
DhruvMaroo
6e662223aa changed spaces to tabs 2021-05-30 22:15:37 +05:30
DhruvMaroo
bdc5674ace added move assignment operator 2021-05-30 12:33:40 +05:30
DhruvMaroo
689b5fb98b added mover constructor 2021-05-30 12:30:11 +05:30
DhruvMaroo
c296e9210b Revert "Revert "added inverse trigonometric functions in Math.hpp""
This reverts commit 8ef2e4f139.
2021-05-30 12:23:39 +05:30
DhruvMaroo
8ef2e4f139 Revert "added inverse trigonometric functions in Math.hpp"
This reverts commit 5128858b1e.
2021-05-30 12:22:45 +05:30
DhruvMaroo
5128858b1e added inverse trigonometric functions in Math.hpp 2021-05-30 11:45:47 +05:30
Rémi Verschelde
dfee6f0ca4 headers: Track tag godot-3.3.2-stable 2021-05-25 15:01:57 +02:00
Rémi Verschelde
f298d36c86 Merge pull request #557 from godotengine/dependabot/github_actions/actions/upload-artifact-2.2.3
Bump actions/upload-artifact from 2.2.2 to 2.2.3
2021-05-25 15:00:35 +02:00
kb1000
3fe276c02f Stop including iostream in Variant.hpp (to produce smaller binaries) 2021-05-23 16:28:11 +02:00
Hristo Stamenov
c629200b93 Update string(TOLOWER ...) to take string versions of CMake variables (#561)
On some generators (MSVC) there is the issue that this line produces cause by the variable being expanded and not being surrounded by quotes.
2021-05-20 14:47:20 +02:00
Hristo Stamenov
476a870d6c Fix CMake generation on Windows (#536) 2021-05-15 22:57:05 +02:00
dependabot[bot]
eb8ae9dd51 Bump actions/upload-artifact from 2.2.2 to 2.2.3
Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 2.2.2 to 2.2.3.
- [Release notes](https://github.com/actions/upload-artifact/releases)
- [Commits](https://github.com/actions/upload-artifact/compare/v2.2.2...v2.2.3)

Signed-off-by: dependabot[bot] <support@github.com>
2021-05-12 05:48:34 +00:00
Rémi Verschelde
d68e629a7c Merge pull request #552 from BastiaanOlij/update_33
Move godot-headers forward to 3.3-stable
2021-05-04 08:43:17 +02:00
Bastiaan Olij
87e97cb85e Move godot-headers forward to 3.3-stable 2021-05-04 12:18:34 +10:00
Marc
1637975a0b Merge pull request #550 from abaire/master
Populates incorrect constants for Vector2 and 3 types.
2021-05-03 15:26:54 +01:00
Erik Abair
2ccc5e08f2 Populates incorrect constants for Vector2 and 3 types. 2021-05-02 15:35:21 -07:00
Pierre-Thomas Meisels
f579039a0a Fix: add missing toolchain elements for android 2021-04-25 21:24:38 +02:00
anunknowperson
a3f1175f1c Update godot version in README.MD
3.2.4 -> 3.3
2021-03-25 12:42:52 +07:00
George Marques
d7c55b1ab2 Merge pull request #530 from Faless/js/scons_and_readme
Add JavaScript platform support (emcc, wasm).
2021-03-22 09:57:45 -03:00
George Marques
6e4a13beec Merge pull request #400 from portaloffreedom/cmake-gen-fix
Fixed cmake source file generation
2021-03-12 12:58:49 -03:00
Fabio Alessandrelli
f6899e190f Add JavaScript platform support (emcc, wasm).
Includes update to `README.md` with instructions on how to build a
GDNative library for webassembly.
2021-03-11 05:11:13 +01:00
Matteo De Carlo
0c8dd096c4 Fix cmake source file generation 2021-03-03 19:40:54 +01:00
Rémi Verschelde
55c0a2ea03 Merge pull request #525 from vnen/update-clang-format
Update clang-format to version 11
2021-03-01 16:28:58 +01:00
George Marques
cee79bb7a6 Merge pull request #517 from SeleDreams/master
Added freebsd specific configuration to SConstruct
2021-03-01 11:56:37 -03:00
George Marques
87f7e061a0 Merge pull request #492 from o01eg/fix-python-detect
Search correct python interpeter in case missing default "python"
2021-03-01 11:47:07 -03:00
George Marques
6c56bfdc8f Merge pull request #497 from godotengine/dependabot/github_actions/actions/upload-artifact-v2.2.2
Bump actions/upload-artifact from v2.2.1 to v2.2.2
2021-03-01 11:10:40 -03:00
George Marques
a65a340329 Merge pull request #507 from Zylann/bindings_auto_gen
Generate bindings if they are not found
2021-03-01 09:47:45 -03:00
dependabot[bot]
ba526df7bd Bump actions/upload-artifact from v2.2.1 to v2.2.2
Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from v2.2.1 to v2.2.2.
- [Release notes](https://github.com/actions/upload-artifact/releases)
- [Commits](https://github.com/actions/upload-artifact/compare/v2.2.1...e448a9b857ee2131e752b06002bf0e093c65e571)

Signed-off-by: dependabot[bot] <support@github.com>
2021-03-01 12:46:57 +00:00
oleg
52f786b923 Search correct python interpeter in case missing default "python" 2021-03-01 15:46:11 +03:00
George Marques
aa2792528e Merge pull request #456 from API-Beast/master
Fix compiling using CMake and GCC
2021-03-01 09:37:54 -03:00
George Marques
cba90d6301 Update clang-format to version 11
This is taken from the Godot repository, so formatting is similar. This
updates the style rules as well.

Also fix style in files to conform with this version.
2021-02-28 16:57:34 -03:00
SeleDreams
45fef69aca Added freebsd specific configuration to fix issues of detection on freebsd 2021-02-21 00:23:06 +01:00
André Sousa
5f24388b04 Add -std:c++17 flag on test windows build 2021-02-14 20:41:59 -03:00
Marc Gilleron
f669380811 Generate bindings if they are not found 2021-02-03 22:48:58 +00:00
Manuel Riecke
2989a385d7 GENERATE_TEMPLATE_GET_NODE option for CMake 2020-09-20 12:18:42 +02:00
Manuel Riecke
73f1f90bf7 Fix godot-cpp not compiling because of -Wlong-long 2020-09-19 13:42:00 +02:00
Manuel Riecke
2007e6f81e Fix CMake failing to generate the bindings.
A new parameter was added to the binding_generator python file,
but the CMake file was not adjusted.
2020-09-19 13:42:00 +02:00
214 changed files with 320510 additions and 12753 deletions

View File

@@ -1,31 +1,40 @@
# Commented out parameters are those with the same value as base LLVM style
# Commented out parameters are those with the same value as base LLVM style.
# We can uncomment them if we want to change their value, or enforce the
# chosen value in case the base style changes (last sync: Clang 6.0.1).
# chosen value in case the base style changes (last sync: Clang 14.0).
---
### General config, applies to all languages ###
BasedOnStyle: LLVM
AccessModifierOffset: -4
AlignAfterOpenBracket: DontAlign
# AlignConsecutiveAssignments: false
# AlignConsecutiveDeclarations: false
# AlignArrayOfStructures: None
# AlignConsecutiveMacros: None
# AlignConsecutiveAssignments: None
# AlignConsecutiveBitFields: None
# AlignConsecutiveDeclarations: None
# AlignEscapedNewlines: Right
# AlignOperands: true
AlignOperands: DontAlign
AlignTrailingComments: false
# AllowAllArgumentsOnNextLine: true
AllowAllParametersOfDeclarationOnNextLine: false
# AllowShortBlocksOnASingleLine: false
AllowShortCaseLabelsOnASingleLine: true
AllowShortFunctionsOnASingleLine: Inline
AllowShortIfStatementsOnASingleLine: true
# AllowShortEnumsOnASingleLine: true
# AllowShortBlocksOnASingleLine: Never
# AllowShortCaseLabelsOnASingleLine: false
# AllowShortFunctionsOnASingleLine: All
# AllowShortLambdasOnASingleLine: All
# AllowShortIfStatementsOnASingleLine: Never
# AllowShortLoopsOnASingleLine: false
# AlwaysBreakAfterDefinitionReturnType: None
# AlwaysBreakAfterReturnType: None
# AlwaysBreakBeforeMultilineStrings: false
# AlwaysBreakTemplateDeclarations: false
# AlwaysBreakTemplateDeclarations: MultiLine
# AttributeMacros:
# - __capability
# BinPackArguments: true
# BinPackParameters: true
# BraceWrapping:
# AfterCaseLabel: false
# AfterClass: false
# AfterControlStatement: false
# AfterControlStatement: Never
# AfterEnum: false
# AfterFunction: false
# AfterNamespace: false
@@ -35,32 +44,44 @@ AllowShortIfStatementsOnASingleLine: true
# AfterExternBlock: false
# BeforeCatch: false
# BeforeElse: false
# BeforeLambdaBody: false
# BeforeWhile: false
# IndentBraces: false
# SplitEmptyFunction: true
# SplitEmptyRecord: true
# SplitEmptyNamespace: true
# BreakBeforeBinaryOperators: None
# BreakBeforeConceptDeclarations: true
# BreakBeforeBraces: Attach
# BreakBeforeInheritanceComma: false
BreakBeforeTernaryOperators: false
# BreakInheritanceList: BeforeColon
# BreakBeforeTernaryOperators: true
# BreakConstructorInitializersBeforeComma: false
BreakConstructorInitializers: AfterColon
# BreakStringLiterals: true
ColumnLimit: 0
# CommentPragmas: '^ IWYU pragma:'
# QualifierAlignment: Leave
# CompactNamespaces: false
ConstructorInitializerAllOnOneLineOrOnePerLine: true
ConstructorInitializerIndentWidth: 8
ContinuationIndentWidth: 8
Cpp11BracedListStyle: false
# DeriveLineEnding: true
# DerivePointerAlignment: false
# DisableFormat: false
# EmptyLineAfterAccessModifier: Never
# EmptyLineBeforeAccessModifier: LogicalBlock
# ExperimentalAutoDetectBinPacking: false
# PackConstructorInitializers: BinPack
ConstructorInitializerAllOnOneLineOrOnePerLine: true
# AllowAllConstructorInitializersOnNextLine: true
# FixNamespaceComments: true
# ForEachMacros:
# - foreach
# - Q_FOREACH
# - BOOST_FOREACH
# IfMacros:
# - KJ_IF_MAYBE
# IncludeBlocks: Preserve
IncludeCategories:
- Regex: '".*"'
@@ -70,13 +91,21 @@ IncludeCategories:
- Regex: '^<.*'
Priority: 3
# IncludeIsMainRegex: '(Test)?$'
# IncludeIsMainSourceRegex: ''
# IndentAccessModifiers: false
IndentCaseLabels: true
# IndentCaseBlocks: false
# IndentGotoLabels: true
# IndentPPDirectives: None
# IndentExternBlock: AfterExternBlock
# IndentRequires: false
IndentWidth: 4
# IndentWrappedFunctionNames: false
# InsertTrailingCommas: None
# JavaScriptQuotes: Leave
# JavaScriptWrapImports: true
# KeepEmptyLinesAtTheStartOfBlocks: true
KeepEmptyLinesAtTheStartOfBlocks: false
# LambdaBodyIndentation: Signature
# MacroBlockBegin: ''
# MacroBlockEnd: ''
# MaxEmptyLinesToKeep: 1
@@ -85,42 +114,86 @@ IndentWidth: 4
# PenaltyBreakBeforeFirstCallParameter: 19
# PenaltyBreakComment: 300
# PenaltyBreakFirstLessLess: 120
# PenaltyBreakOpenParenthesis: 0
# PenaltyBreakString: 1000
# PenaltyBreakTemplateDeclaration: 10
# PenaltyExcessCharacter: 1000000
# PenaltyReturnTypeOnItsOwnLine: 60
# PenaltyIndentedWhitespace: 0
# PointerAlignment: Right
# RawStringFormats:
# - Delimiter: pb
# Language: TextProto
# BasedOnStyle: google
# PPIndentWidth: -1
# ReferenceAlignment: Pointer
# ReflowComments: true
# SortIncludes: true
# RemoveBracesLLVM: false
# SeparateDefinitionBlocks: Leave
# ShortNamespaceLines: 1
# SortIncludes: CaseSensitive
# SortJavaStaticImport: Before
# SortUsingDeclarations: true
# SpaceAfterCStyleCast: false
# SpaceAfterLogicalNot: false
# SpaceAfterTemplateKeyword: true
# SpaceBeforeAssignmentOperators: true
# SpaceBeforeCaseColon: false
# SpaceBeforeCpp11BracedList: false
# SpaceBeforeCtorInitializerColon: true
# SpaceBeforeInheritanceColon: true
# SpaceBeforeParens: ControlStatements
# SpaceBeforeParensOptions:
# AfterControlStatements: true
# AfterForeachMacros: true
# AfterFunctionDefinitionName: false
# AfterFunctionDeclarationName: false
# AfterIfMacros: true
# AfterOverloadedOperator: false
# BeforeNonEmptyParentheses: false
# SpaceAroundPointerQualifiers: Default
# SpaceBeforeRangeBasedForLoopColon: true
# SpaceInEmptyBlock: false
# SpaceInEmptyParentheses: false
# SpacesBeforeTrailingComments: 1
# SpacesInAngles: false
# SpacesInAngles: Never
# SpacesInConditionalStatement: false
# SpacesInContainerLiterals: true
# SpacesInCStyleCastParentheses: false
## Godot TODO: We'll want to use a min of 1, but we need to see how to fix
## our comment capitalization at the same time.
SpacesInLineCommentPrefix:
Minimum: 0
Maximum: -1
# SpacesInParentheses: false
# SpacesInSquareBrackets: false
# SpaceBeforeSquareBrackets: false
# BitFieldColonSpacing: Both
# StatementAttributeLikeMacros:
# - Q_EMIT
# StatementMacros:
# - Q_UNUSED
# - QT_REQUIRE_VERSION
TabWidth: 4
# UseCRLF: false
UseTab: Always
# WhitespaceSensitiveMacros:
# - STRINGIZE
# - PP_STRINGIZE
# - BOOST_PP_STRINGIZE
# - NS_SWIFT_NAME
# - CF_SWIFT_NAME
---
### C++ specific config ###
Language: Cpp
Standard: Cpp03
Standard: c++17
---
### ObjC specific config ###
Language: ObjC
# ObjCBinPackProtocolList: Auto
ObjCBlockIndentWidth: 4
# ObjCBreakBeforeNestedBlockParam: true
# ObjCSpaceAfterProperty: false
# ObjCSpaceBeforeProtocolList: true
---
### Java specific config ###
Language: Java
# BreakAfterJavaFieldAnnotations: false
JavaImportGroups: ['org.godotengine', 'android', 'androidx', 'com.android', 'com.google', 'java', 'javax']
...

0
.gdignore Normal file
View File

6
.github/CODEOWNERS vendored Normal file
View File

@@ -0,0 +1,6 @@
# Lines starting with '#' are comments.
# Each line is a file pattern followed by one or more owners.
# Owners can be @users, @org/teams or emails
* @godotengine/gdextension
.github/ @godotengine/buildsystem

71
.github/ISSUE_TEMPLATE/bug_report.yml vendored Normal file
View File

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

14
.github/ISSUE_TEMPLATE/config.yml vendored Normal file
View File

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

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

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

View File

@@ -1,161 +1,251 @@
name: Continuous integration
on: [push, pull_request]
env:
# Only used for the cache key. Increment version to force clean build.
GODOT_BASE_BRANCH: master
concurrency:
group: ci-${{github.actor}}-${{github.head_ref || github.run_number}}-${{github.ref}}
cancel-in-progress: true
jobs:
linux:
name: Build (Linux, GCC)
runs-on: ubuntu-16.04
build:
name: ${{ matrix.name }}
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
include:
- name: 🐧 Linux (GCC)
os: ubuntu-20.04
platform: linux
artifact-name: godot-cpp-linux-glibc2.27-x86_64-release
artifact-path: bin/libgodot-cpp.linux.template_release.x86_64.a
run-tests: true
cache-name: linux-x86_64
- name: 🐧 Linux (GCC, Double Precision)
os: ubuntu-20.04
platform: linux
artifact-name: godot-cpp-linux-glibc2.27-x86_64-double-release
artifact-path: bin/libgodot-cpp.linux.template_release.double.x86_64.a
flags: precision=double
run-tests: false
cache-name: linux-x86_64-f64
- name: 🏁 Windows (x86_64, MSVC)
os: windows-2019
platform: windows
artifact-name: godot-cpp-windows-msvc2019-x86_64-release
artifact-path: bin/libgodot-cpp.windows.template_release.x86_64.lib
run-tests: false
cache-name: windows-x86_64-msvc
- name: 🏁 Windows (x86_64, MinGW)
os: windows-2019
platform: windows
artifact-name: godot-cpp-linux-mingw-x86_64-release
artifact-path: bin/libgodot-cpp.windows.template_release.x86_64.a
flags: use_mingw=yes
run-tests: false
cache-name: windows-x86_64-mingw
- name: 🍎 macOS (universal)
os: macos-11
platform: macos
artifact-name: godot-cpp-macos-universal-release
artifact-path: bin/libgodot-cpp.macos.template_release.universal.a
flags: arch=universal
run-tests: false
cache-name: macos-universal
- name: 🤖 Android (arm64)
os: ubuntu-20.04
platform: android
artifact-name: godot-cpp-android-arm64-release
artifact-path: bin/libgodot-cpp.android.template_release.arm64.a
flags: arch=arm64
run-tests: false
cache-name: android-arm64
- name: 🍏 iOS (arm64)
os: macos-11
platform: ios
artifact-name: godot-cpp-ios-arm64-release
artifact-path: bin/libgodot-cpp.ios.template_release.arm64.a
flags: arch=arm64
run-tests: false
cache-name: ios-arm64
- name: 🌐 Web (wasm32)
os: ubuntu-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@v2.3.4
uses: actions/checkout@v4
with:
submodules: recursive
- name: Set up Python (for SCons)
uses: actions/setup-python@v2
- name: Setup Godot build cache
uses: ./.github/actions/godot-cache
with:
python-version: '3.9.1'
cache-name: ${{ matrix.cache-name }}
continue-on-error: true
- name: Set up Python (for SCons)
uses: actions/setup-python@v4
with:
python-version: '3.x'
- 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@v13
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: Generate godot-cpp sources only
run: |
scons platform=${{ matrix.platform }} build_library=no ${{ matrix.flags }}
scons -c
- name: Build godot-cpp (debug)
run: |
scons platform=${{ matrix.platform }} 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
- name: Build test and godot-cpp (release)
run: |
cd test
scons platform=${{ matrix.platform }} target=template_release ${{ matrix.flags }}
- name: Download latest Godot artifacts
uses: dsnopek/action-download-artifact@1322f74e2dac9feed2ee76a32d9ae1ca3b4cf4e9
if: ${{ matrix.run-tests }}
with:
repo: godotengine/godot
branch: master
event: push
workflow: linux_builds.yml
workflow_conclusion: success
name: linux-editor-mono
search_artifacts: true
check_artifacts: true
ensure_latest: true
path: godot-artifacts
- name: Run tests
if: ${{ matrix.run-tests }}
run: |
chmod +x ./godot-artifacts/godot.linuxbsd.editor.x86_64.mono
./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 && (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
uses: actions/upload-artifact@v3
with:
name: ${{ matrix.artifact-name }}
path: ${{ matrix.artifact-path }}
if-no-files-found: error
linux-cmake:
name: 🐧 Build (Linux, GCC, CMake)
runs-on: ubuntu-20.04
steps:
- name: Checkout
uses: actions/checkout@v4
with:
submodules: recursive
- name: Install dependencies
run: |
sudo apt-get update -qq
sudo apt-get install -qqq build-essential pkg-config
python -m pip install scons
curl -LO https://downloads.tuxfamily.org/godotengine/3.2.3/Godot_v3.2.3-stable_linux_server.64.zip
unzip Godot_v3.2.3-stable_linux_server.64.zip
sudo apt-get install -qqq build-essential pkg-config cmake
- name: Build godot-cpp
run: |
scons target=release generate_bindings=yes -j $(nproc)
cmake -DCMAKE_BUILD_TYPE=Release .
make -j $(nproc) VERBOSE=1
- name: Upload artifact
uses: actions/upload-artifact@v2.2.1
- name: Build test GDExtension library
run: |
cd test && cmake -DCMAKE_BUILD_TYPE=Release -DGODOT_HEADERS_PATH="../godot-headers" -DCPP_BINDINGS_PATH=".." .
make -j $(nproc) VERBOSE=1
linux-cmake-ninja:
name: 🐧 Build (Linux, GCC, CMake Ninja)
runs-on: ubuntu-20.04
steps:
- name: Checkout
uses: actions/checkout@v4
with:
name: godot-cpp-linux-glibc2.23-x86_64-release
path: bin/libgodot-cpp.linux.release.64.a
if-no-files-found: error
submodules: recursive
- name: Build test GDNative library
- name: Install dependencies
run: |
scons target=release platform=linux bits=64 -j $(nproc) -C test
sudo apt-get update -qq
sudo apt-get install -qqq build-essential pkg-config cmake ninja-build
- name: Run test GDNative library
- name: Build godot-cpp
run: |
./Godot_v3.2.3-stable_linux_server.64 --path test -s script.gd
cmake -DCMAKE_BUILD_TYPE=Release -GNinja .
cmake --build . -j $(nproc) --verbose
windows-msvc:
name: Build (Windows, MSVC)
- name: Build test GDExtension library
run: |
cd test && cmake -DCMAKE_BUILD_TYPE=Release -DGODOT_HEADERS_PATH="../godot-headers" -DCPP_BINDINGS_PATH=".." -GNinja .
cmake --build . -j $(nproc) --verbose
windows-msvc-cmake:
name: 🏁 Build (Windows, MSVC, CMake)
runs-on: windows-2019
steps:
- name: Checkout
uses: actions/checkout@v2.3.4
uses: actions/checkout@v4
with:
submodules: recursive
- name: Set up Python (for SCons)
uses: actions/setup-python@v2
with:
python-version: '3.9.1'
- name: Install dependencies
run: |
python -m pip install scons
- name: Build godot-cpp
run: |
scons target=release generate_bindings=yes -j $env:NUMBER_OF_PROCESSORS
cmake -DCMAKE_BUILD_TYPE=Release -G"Visual Studio 16 2019" .
cmake --build . --verbose
- name: Upload artifact
uses: actions/upload-artifact@v2.2.1
with:
name: godot-cpp-windows-msvc2019-x86_64-release
path: bin/libgodot-cpp.windows.release.64.lib
if-no-files-found: error
windows-mingw:
name: Build (Windows, MinGW)
runs-on: windows-2019
steps:
- name: Checkout
uses: actions/checkout@v2.3.4
with:
submodules: recursive
- name: Set up Python (for SCons)
uses: actions/setup-python@v2
with:
python-version: '3.9.1'
- name: Install dependencies
- name: Build test GDExtension library
run: |
python -m pip install scons
- name: Build godot-cpp
# Install GCC from Scoop as the default supplied GCC doesn't work ("Error 1").
run: |
Invoke-Expression (New-Object System.Net.WebClient).DownloadString('https://get.scoop.sh')
scoop install gcc
g++ --version
gcc --version
scons target=release generate_bindings=yes use_mingw=yes -j $env:NUMBER_OF_PROCESSORS
- name: Upload artifact
uses: actions/upload-artifact@v2.2.1
with:
name: godot-cpp-linux-mingw-x86_64-release
path: bin/libgodot-cpp.windows.release.64.a
if-no-files-found: error
macos:
name: Build (macOS, Clang)
runs-on: macos-10.15
steps:
- name: Checkout
uses: actions/checkout@v2.3.4
with:
submodules: recursive
- name: Set up Python (for SCons)
uses: actions/setup-python@v2
with:
python-version: '3.9.1'
- name: Install dependencies
run: |
python -m pip install scons
curl -LO https://downloads.tuxfamily.org/godotengine/3.2.3/Godot_v3.2.3-stable_osx.64.zip
unzip Godot_v3.2.3-stable_osx.64.zip
- name: Build godot-cpp
run: |
scons target=release generate_bindings=yes -j $(sysctl -n hw.logicalcpu)
- name: Upload artifact
uses: actions/upload-artifact@v2.2.1
with:
name: godot-cpp-macos-x86_64-release
path: bin/libgodot-cpp.osx.release.64.a
if-no-files-found: error
- name: Build test GDNative library
run: |
scons target=release platform=osx bits=64 -j $(sysctl -n hw.logicalcpu) -C test
- name: Run test GDNative library
run: |
./Godot.app/Contents/MacOS/Godot --path test -s script.gd
static-checks:
name: Static Checks (clang-format)
runs-on: ubuntu-16.04
steps:
- name: Checkout
uses: actions/checkout@v2.3.4
- name: Install dependencies
run: |
sudo apt-get install clang-format-8
- name: Style checks via clang-format
run: |
bash ./misc/scripts/clang_format.sh
cd test && cmake -DCMAKE_BUILD_TYPE=Release -DGODOT_HEADERS_PATH="../godot-headers" -DCPP_BINDINGS_PATH=".." -G"Visual Studio 16 2019" .
cmake --build . --verbose

54
.github/workflows/static_checks.yml vendored Normal file
View File

@@ -0,0 +1,54 @@
name: 📊 Static Checks
on: [push, pull_request]
concurrency:
group: ci-${{github.actor}}-${{github.head_ref || github.run_number}}-${{github.ref}}-static
cancel-in-progress: true
jobs:
static-checks:
name: Format (clang-format, black format, file format)
runs-on: ubuntu-20.04
steps:
- name: Checkout
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
run: |
sudo rm -f /etc/apt/sources.list.d/*
sudo cp -f misc/ci/sources.list /etc/apt/sources.list
wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add -
sudo apt-add-repository "deb http://apt.llvm.org/focal/ llvm-toolchain-focal-15 main"
sudo apt-get update
- name: Install dependencies
run: |
sudo apt-get install -qq dos2unix recode clang-format-15 libxml2-utils python3-pip moreutils
sudo update-alternatives --remove-all clang-format || true
sudo update-alternatives --install /usr/bin/clang-format clang-format /usr/bin/clang-format-15 100
sudo pip3 install black==22.3.0 pygments pytest==7.1.2 mypy==0.971
- name: File formatting checks (file_format.sh)
run: |
bash ./misc/scripts/file_format.sh
- name: Header guards formatting checks (header_guards.sh)
run: |
bash ./misc/scripts/header_guards.sh
- name: Python style checks via black (black_format.sh)
run: |
bash ./misc/scripts/black_format.sh
- name: Python scripts static analysis (mypy_check.sh)
run: |
bash ./misc/scripts/mypy_check.sh
- name: Bindings generation checks (ensures get_file_list returns all generated files)
run: |
python ./misc/scripts/check_get_file_list.py
- name: Style checks via clang-format (clang_format.sh)
run: |
bash ./misc/scripts/clang_format.sh

25
.gitignore vendored
View File

@@ -1,11 +1,29 @@
# Godot auto generated files
*.gen.*
.import/
.godot/
/gen/
# Godot 3.x ignores
include/gen
src/gen
# Build configuarion.
/custom.py
# Misc
logs/*
*.log
# The default cache directory
cache/
# Binaries
*.o
*.os
*.so
*.obj
*.bc
*.pyc
*.dblite
*.pdb
@@ -16,6 +34,7 @@ bin
*.creator.user
*.files
*.includes
*.idb
# Gprof output
gmon.out
@@ -81,7 +100,7 @@ AppPackages/
# Others
sql/
*.Cache
*.[Cc]ache
ClientBin/
[Ss]tyle[Cc]op.*
~$*
@@ -172,3 +191,7 @@ godot.creator.*
# compile commands (https://clang.llvm.org/docs/JSONCompilationDatabase.html)
compile_commands.json
# Python development
.venv
venv

3
.gitmodules vendored
View File

@@ -1,3 +0,0 @@
[submodule "godot-headers"]
path = godot-headers
url = https://github.com/godotengine/godot-headers

View File

@@ -1,80 +1,93 @@
# cmake arguments
# CMAKE_BUILD_TYPE: Compilation target (Debug or Release defaults to Debug)
#
#
# godot-cpp cmake arguments
# GODOT_HEADERS_DIR: This is where the gdnative include folder is (godot_source/modules/gdnative/include)
# GODOT_CUSTOM_API_FILE: This is if you have another path for the godot_api.json
#
# GODOT_GDEXTENSION_DIR: Path to the directory containing GDExtension interface header and API JSON file
# GODOT_CPP_SYSTEM_HEADERS Mark the header files as SYSTEM. This may be useful to supress warnings in projects including this one.
# GODOT_CPP_WARNING_AS_ERROR Treat any warnings as errors
# GODOT_CUSTOM_API_FILE: Path to a custom GDExtension API JSON file (takes precedence over `gdextension_dir`)
# FLOAT_PRECISION: Floating-point precision level ("single", "double")
#
# Android cmake arguments
# CMAKE_TOOLCHAIN_FILE: The path to the android cmake toolchain ($ANDROID_NDK/build/cmake/android.toolchain.cmake)
# ANDROID_NDK: The path to the android ndk root folder
# ANDROID_TOOLCHAIN_NAME: The android toolchain (arm-linux-androideabi-4.9 or aarch64-linux-android-4.9 or x86-4.9 or x86_64-4.9)
# ANDROID_PLATFORM: The android platform version (android-23)
# More info here: https://godot.readthedocs.io/en/latest/development/compiling/compiling_for_android.html
#
#
# Examples
#
#
# Builds a debug version:
# cmake .
# cmake --build .
#
#
# Builds a release version with clang
# CC=/usr/bin/clang CXX=/usr/bin/clang++ cmake -DCMAKE_BUILD_TYPE=Release -G "Unix Makefiles" .
# cmake --build .
#
#
# Builds an android armeabi-v7a debug version:
# cmake -DCMAKE_TOOLCHAIN_FILE=$ANDROID_NDK/build/cmake/android.toolchain.cmake -DANDROID_NDK=$ANDROID_NDK \
# -DANDROID_TOOLCHAIN_NAME=arm-linux-androideabi-4.9 -DANDROID_PLATFORM=android-23 -DCMAKE_BUILD_TYPE=Debug .
# cmake --build .
#
#
# Protip
# Generate the buildfiles in a sub directory to not clutter the root directory with build files:
# mkdir build && cd build && cmake -G "Unix Makefiles" .. && cmake --build .
#
#
# Todo
# Test build for Windows, Mac and mingw.
project(godot-cpp)
cmake_minimum_required(VERSION 3.6)
cmake_minimum_required(VERSION 3.12)
project(godot-cpp LANGUAGES CXX)
# Change the output directory to the bin directory
set(BUILD_PATH ${CMAKE_SOURCE_DIR}/bin)
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${BUILD_PATH}")
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${BUILD_PATH}")
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${BUILD_PATH}")
SET(CMAKE_RUNTIME_OUTPUT_DIRECTORY_DEBUG "${BUILD_PATH}")
SET(CMAKE_RUNTIME_OUTPUT_DIRECTORY_RELEASE "${BUILD_PATH}")
SET(CMAKE_LIBRARY_OUTPUT_DIRECTORY_DEBUG "${BUILD_PATH}")
SET(CMAKE_LIBRARY_OUTPUT_DIRECTORY_RELEASE "${BUILD_PATH}")
SET(CMAKE_ARCHIVE_OUTPUT_DIRECTORY_DEBUG "${BUILD_PATH}")
SET(CMAKE_ARCHIVE_OUTPUT_DIRECTORY_RELEASE "${BUILD_PATH}")
option(GENERATE_TEMPLATE_GET_NODE "Generate a template version of the Node class's get_node." ON)
option(GODOT_CPP_SYSTEM_HEADERS "Expose headers as SYSTEM." ON)
option(GODOT_CPP_WARNING_AS_ERROR "Treat warnings as errors" OFF)
# 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>" )
set( compiler_is_msvc "$<CXX_COMPILER_ID:MSVC>" )
# Default build type is Debug in the SConstruct
if(CMAKE_BUILD_TYPE STREQUAL "")
if("${CMAKE_BUILD_TYPE}" STREQUAL "")
set(CMAKE_BUILD_TYPE Debug)
endif()
if(CMAKE_BUILD_TYPE MATCHES Debug)
add_definitions(-D_DEBUG)
else()
add_definitions(-DNDEBUG)
endif(CMAKE_BUILD_TYPE MATCHES Debug)
if(NOT DEFINED BITS)
set(BITS 32)
if(CMAKE_SIZEOF_VOID_P EQUAL 8)
set(BITS 64)
endif(CMAKE_SIZEOF_VOID_P EQUAL 8)
endif()
# Set the c++ standard to c++14
set(CMAKE_CXX_STANDARD 14)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)
# 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 "")
# Input from user for godot headers and the api file
set(GODOT_HEADERS_DIR "godot-headers" CACHE STRING "")
set(GODOT_CUSTOM_API_FILE "godot-headers/api.json" CACHE STRING "")
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 )
set(GODOT_LINKER_FLAGS )
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
# using Visual Studio C++
set(GODOT_COMPILE_FLAGS "/EHsc /WX") # /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
@@ -84,98 +97,131 @@ if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
string(REPLACE "/RTC1" "" CMAKE_CXX_FLAGS_DEBUG ${CMAKE_CXX_FLAGS_DEBUG})
endif(CMAKE_BUILD_TYPE MATCHES Debug)
# Disable conversion warning, trunkation, unreferenced var, signed missmatch
set(GODOT_COMPILE_FLAGS "${GODOT_COMPILE_FLAGS} /wd4244 /wd4305 /wd4101 /wd4018 /wd4267")
# Todo: Check if needed.
add_definitions(-DWIN32_LEAN_AND_MEAN -D_CRT_SECURE_NO_WARNINGS)
# Unkomment for warning level 4
#if(CMAKE_CXX_FLAGS MATCHES "/W[0-4]")
# string(REGEX REPLACE "/W[0-4]" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
#endif()
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} -Wlong-long -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()
add_definitions(-DNOMINMAX)
else() # GCC/Clang
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 ON "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
message(STATUS "Generating Bindings")
execute_process(COMMAND "python" "-c" "import binding_generator; binding_generator.generate_bindings(\"${GODOT_CUSTOM_API_FILE}\")"
find_package(Python3 3.4 REQUIRED) # pathlib should be present
if(GENERATE_TEMPLATE_GET_NODE)
set(GENERATE_BINDING_PARAMETERS "True")
else()
set(GENERATE_BINDING_PARAMETERS "False")
endif()
execute_process(COMMAND "${Python3_EXECUTABLE}" "-c" "import binding_generator; binding_generator.print_file_list(\"${GODOT_GDEXTENSION_API_FILE}\", \"${CMAKE_CURRENT_BINARY_DIR}\", headers=True, sources=True)"
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
RESULT_VARIABLE GENERATION_RESULT
OUTPUT_VARIABLE GENERATION_OUTPUT)
message(STATUS ${GENERATION_RESULT} ${GENERATION_OUTPUT})
# Get Sources
file(GLOB_RECURSE SOURCES src/*.c**)
file(GLOB_RECURSE HEADERS include/*.h**)
# Define our godot-cpp library
add_library(${PROJECT_NAME} ${SOURCES} ${HEADERS})
target_include_directories(${PROJECT_NAME}
PUBLIC
include
include/core
include/gen
OUTPUT_VARIABLE GENERATED_FILES_LIST
OUTPUT_STRIP_TRAILING_WHITESPACE
)
# Put godot headers as SYSTEM PUBLIC to exclude warnings from irrelevant headers
target_include_directories(${PROJECT_NAME}
SYSTEM PUBLIC
${GODOT_HEADERS_DIR}
add_custom_command(OUTPUT ${GENERATED_FILES_LIST}
COMMAND "${Python3_EXECUTABLE}" "-c" "import binding_generator; binding_generator.generate_bindings(\"${GODOT_GDEXTENSION_API_FILE}\", \"${GENERATE_BINDING_PARAMETERS}\", \"${BITS}\", \"${FLOAT_PRECISION}\", \"${CMAKE_CURRENT_BINARY_DIR}\")"
VERBATIM
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
MAIN_DEPENDENCY ${GODOT_GDEXTENSION_API_FILE}
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/binding_generator.py
COMMENT "Generating bindings"
)
# Get Sources
file(GLOB_RECURSE SOURCES CONFIGURE_DEPENDS src/*.c**)
file(GLOB_RECURSE HEADERS CONFIGURE_DEPENDS include/*.h**)
# Define our godot-cpp library
add_library(${PROJECT_NAME} STATIC
${SOURCES}
${HEADERS}
${GENERATED_FILES_LIST}
)
add_library(godot::cpp ALIAS ${PROJECT_NAME})
include(GodotCompilerWarnings)
# Treat warnings as errors if we are building ourself
if(GODOT_CPP_BUILDING_SELF)
unset( GODOT_CPP_WARNING_AS_ERROR CACHE )
set_warning_as_error()
endif()
target_compile_features(${PROJECT_NAME}
PRIVATE
cxx_std_17
)
target_compile_definitions(${PROJECT_NAME} PUBLIC
$<$<CONFIG:Debug>:
DEBUG_ENABLED
DEBUG_METHODS_ENABLED
>
$<${compiler_is_msvc}:
TYPED_METHOD_BIND
>
)
target_link_options(${PROJECT_NAME} PRIVATE
$<$<NOT:${compiler_is_msvc}>:
-static-libgcc
-static-libstdc++
-Wl,-R,'$$ORIGIN'
>
)
# Optionally mark headers as SYSTEM
set(GODOT_CPP_SYSTEM_HEADERS_ATTRIBUTE "")
if (GODOT_CPP_SYSTEM_HEADERS)
set(GODOT_CPP_SYSTEM_HEADERS_ATTRIBUTE SYSTEM)
endif ()
target_include_directories(${PROJECT_NAME} ${GODOT_CPP_SYSTEM_HEADERS_ATTRIBUTE} PUBLIC
include
${CMAKE_CURRENT_BINARY_DIR}/gen/include
${GODOT_GDEXTENSION_DIR}
)
# Add the compile flags
set_property(TARGET ${PROJECT_NAME} APPEND_STRING PROPERTY COMPILE_FLAGS ${GODOT_COMPILE_FLAGS})
set_property(TARGET ${PROJECT_NAME} APPEND_STRING PROPERTY LINK_FLAGS ${GODOT_LINKER_FLAGS})
# Create the correct name (godot.os.build_type.system_bits)
set(BITS 32)
if(CMAKE_SIZEOF_VOID_P EQUAL 8)
set(BITS 64)
endif(CMAKE_SIZEOF_VOID_P EQUAL 8)
string(TOLOWER ${CMAKE_SYSTEM_NAME} SYSTEM_NAME)
string(TOLOWER ${CMAKE_BUILD_TYPE} BUILD_TYPE)
string(TOLOWER "${CMAKE_SYSTEM_NAME}" SYSTEM_NAME)
string(TOLOWER "${CMAKE_BUILD_TYPE}" BUILD_TYPE)
if(ANDROID)
# Added the android abi after system name
set(SYSTEM_NAME ${SYSTEM_NAME}.${ANDROID_ABI})
# Android does not have the bits at the end if you look at the main godot repo build
set_property(TARGET ${PROJECT_NAME} PROPERTY OUTPUT_NAME "godot-cpp.${SYSTEM_NAME}.${BUILD_TYPE}")
set(OUTPUT_NAME "godot-cpp.${SYSTEM_NAME}.${BUILD_TYPE}")
else()
set_property(TARGET ${PROJECT_NAME} PROPERTY OUTPUT_NAME "godot-cpp.${SYSTEM_NAME}.${BUILD_TYPE}.${BITS}")
set(OUTPUT_NAME "godot-cpp.${SYSTEM_NAME}.${BUILD_TYPE}.${BITS}")
endif()
set_target_properties(${PROJECT_NAME}
PROPERTIES
CXX_EXTENSIONS OFF
POSITION_INDEPENDENT_CODE ON
ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/bin"
LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/bin"
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/bin"
OUTPUT_NAME "${OUTPUT_NAME}"
)

View File

@@ -1,6 +1,6 @@
# MIT License
Copyright (c) 2017-2021 Godot Engine contributors.
Copyright (c) 2017-present Godot Engine contributors.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal

View File

@@ -1,17 +1,17 @@
GENERATE_BINDINGS = no
HEADERS = godot-headers
TARGET = debug
USE_CLANG = no
TARGET = template_debug
BASE = scons use_llvm=$(USE_CLANG) generate_bindings=$(GENERATE_BINDINGS) target=$(TARGET) headers=$(HEADERS) -j4
BASE = scons target=$(TARGET) $(EXTRA_ARGS)
LINUX = $(BASE) platform=linux
WINDOWS = $(BASE) platform=windows
OSX = $(BASE) platform=osx
MACOS = $(BASE) platform=macos
all:
make linux
make windows
.PHONY: usage
usage:
@echo -e "Specify one of the available targets:\n"
# https://stackoverflow.com/a/26339924
@LC_ALL=C $(MAKE) -pRrq -f $(lastword $(MAKEFILE_LIST)) : 2>/dev/null | awk -v RS= -F: '/(^|\n)# Files(\n|$$)/,/(^|\n)# Finished Make data base/ {if ($$1 !~ "^[#.]") {print $$1}}' | sort | grep -E -v -e '^[^[:alnum:]]' -e '^$@$$'
@echo -e "\nDefine the SCons target with TARGET, and pass extra SCons arguments with EXTRA_ARGS."
linux:
@@ -19,10 +19,10 @@ linux:
make linux64
linux32: SConstruct
$(LINUX) bits=32
$(LINUX) arch=x86_32
linux64: SConstruct
$(LINUX) bits=64
$(LINUX) arch=x86_64
windows:
@@ -30,18 +30,11 @@ windows:
make windows64
windows32: SConstruct
$(WINDOWS) bits=32
$(WINDOWS) arch=x86_32
windows64: SConstruct
$(WINDOWS) bits=64
$(WINDOWS) arch=x86_64
osx:
make osx32
make osx64
osx32: SConstruct
$(OSX) bits=32
osx64: SConstruct
$(OSX) bits=64
macos: SConstruct
$(MACOS)

433
README.md
View File

@@ -1,349 +1,144 @@
# godot-cpp
**C++ bindings for the Godot script API.**
> **Warning**
>
> This repository's `master` branch is only usable with
> [GDExtension](https://godotengine.org/article/introducing-gd-extensions)
> from Godot's `master` branch.
>
> For users of stable branches, switch to the branch matching your target Godot version:
> - [`4.2`](https://github.com/godotengine/godot-cpp/tree/4.2)
> - [`4.1`](https://github.com/godotengine/godot-cpp/tree/4.1)
> - [`4.0`](https://github.com/godotengine/godot-cpp/tree/4.0)
>
> Or check out the Git tag matching your Godot version (e.g. `godot-4.1.1-stable`).
>
> 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.
The instructions below feature the new NativeScript 1.1 class structure and will only work for modules created for Godot 3.1 and later. Use the following branches for older implementations:
Version | Branch
--- | ---
**Godot 3.0 Nativescript 1.0** | [3.0](https://github.com/godotengine/godot-cpp/tree/3.0)
**Godot 3.1 Nativescript 1.0** | [nativescript-1.0](https://github.com/godotengine/godot-cpp/tree/nativescript-1.0)
## Table of contents
This repository contains the *C++ bindings* for the [**Godot Engine**](https://github.com/godotengine/godot)'s GDExtensions API.
- [**Versioning**](#versioning)
- [**Compatibility**](#compatibility)
- [**Contributing**](#contributing)
- [**Getting Started**](#getting-started)
- [**Creating a simple class**](#creating-a-simple-class)
- [**Getting started**](#getting-started)
- [**Included example**](#included-example)
## Versioning
This repositories follows the same branch versioning as the main [Godot Engine
repository](https://github.com/godotengine/godot):
- `master` tracks the current GDExtension development branch for the next Godot
4.x minor release.
- `3.x` tracks the development of the GDNative plugin for the next 3.x minor
release.
- Other versioned branches (e.g. `4.0`, `3.5`) track the latest stable release
in the corresponding branch.
Stable releases are also tagged on this repository:
[**Tags**](https://github.com/godotengine/godot-cpp/tags).
**For any project built against a stable release of Godot, we recommend using
this repository as a Git submodule, checking out the specific tag matching your
Godot version.**
> As the `master` branch of Godot is constantly getting updated, if you are
> using `godot-cpp` against a more current version of Godot, see the instructions
> in the `gdextension` folder to update the relevant files.
## Compatibility
**Warning:** The GDExtension API is brand new in Godot 4.0, and is still
considered in **beta** stage, despite Godot 4.0 itself being released.
This applies to both the GDExtension interface header, the API JSON, and this
first-party `godot-cpp` extension.
Some compatibility breakage is to be expected as GDExtension and `godot-cpp`
get more used, documented, and critical issues get resolved. See the
[Godot issue tracker](https://github.com/godotengine/godot/issues?q=is%3Aissue+is%3Aopen+label%3Atopic%3Agdextension)
and the [godot-cpp issue tracker](https://github.com/godotengine/godot/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
We greatly appreciate help in maintaining and extending this project. If you
wish to help out, ensure you have an account on GitHub and create a "fork" of
this repository. Rémi "Akien" Verschelde wrote an excellent bit of documentation
for the main Godot project on this:
[Pull request workflow](https://docs.godotengine.org/en/3.0/community/contributing/pr_workflow.html)
this repository. See [Pull request workflow](https://docs.godotengine.org/en/stable/community/contributing/pr_workflow.html)
for instructions.
Please install clang-format and copy the files in `misc/hooks` into `.git/hooks`
so formatting is done before your changes are submitted.
## Getting Started
## Getting started
| **Build latest version of Godot** | [**GitHub**](https://github.com/godotengine/godot) | [**Docs**](https://godot.readthedocs.io/en/latest/development/compiling/index.html) |
| --- | --- | --- |
It's a bit similar to what it was for 3.x but also a bit different.
This new approach is much more akin to how core Godot modules are structured.
### Setting up a new project
Compiling this repository generates a static library to be linked with your shared lib,
just like before.
We recommend using Git for managing your project. The instructions below assume
you're using Git. Alternatively, you can download the source code directly from
GitHub. In this case, you need to download both
[godot-cpp](https://github.com/godotengine/godot-cpp) and
[godot-headers](https://github.com/godotengine/godot-headers).
To use the shared lib in your Godot project you'll need a `.gdextension`
file, which replaces what was the `.gdnlib` before.
See [example.gdextension](test/project/example.gdextension) used in the test project:
```bash
mkdir SimpleLibrary
cd SimpleLibrary
mkdir bin
mkdir src
git clone --recursive https://github.com/godotengine/godot-cpp
```ini
[configuration]
entry_symbol = "example_library_init"
compatibility_minimum = "4.1"
[libraries]
macos.debug = "res://bin/libgdexample.macos.debug.framework"
macos.release = "res://bin/libgdexample.macos.release.framework"
windows.debug.x86_64 = "res://bin/libgdexample.windows.debug.x86_64.dll"
windows.release.x86_64 = "res://bin/libgdexample.windows.release.x86_64.dll"
linux.debug.x86_64 = "res://bin/libgdexample.linux.debug.x86_64.so"
linux.release.x86_64 = "res://bin/libgdexample.linux.release.x86_64.so"
# Repeat for other architectures to support arm64, rv64, etc.
```
If you wish to use a specific branch, add the -b option to the clone command:
```bash
git clone --recursive https://github.com/godotengine/godot-cpp -b 3.0
```
If your project is an existing repository, use a Git submodule instead:
```bash
git submodule add https://github.com/godotengine/godot-cpp
git submodule update --init --recursive
```
Right now, our directory structure should look like this:
```text
SimpleLibrary/
├─godot-cpp/
| └─godot-headers/
├─bin/
└─src/
```
### Updating the `api.json` file
Our `api.json` file contains metadata for all the classes that are part of the
Godot core. This metadata is required to generate the C++ binding classes for
use in GDNative modules.
This file is supplied with our
[godot-headers](https://github.com/godotengine/godot-headers) repository
for your convenience. However, if you're running a custom build of Godot and
need access to classes that have recent changes, you must generate a new
`api.json` file. You do this by starting your Godot executable with the
following parameters:
```bash
godot --gdnative-generate-json-api api.json
```
Now copy the `api.json` file into your folder structure to make it easier to
access.
See the remark below for the extra ```custom_api_file``` SCons argument, which
is required to tell SCons where to find your file.
### Compiling the C++ bindings library
The final step is to compile our C++ bindings library:
```bash
cd godot-cpp
scons platform=<your platform> generate_bindings=yes
cd ..
```
Replace `<your platform>` with either `windows`, `linux`, `osx` or `android`. If
you leave out `platform`, the target platform will automatically be detected
from the host platform.
The resulting library will be created in `godot-cpp/bin/`, take note of its name
as it'll differ depending on the target platform.
#### Compiling for Android
Download the latest [Android NDK](https://developer.android.com/ndk/downloads)
and set the NDK path.
```bash
scons platform=android generate_bindings=yes ANDROID_NDK_ROOT="/PATH-TO-ANDROID-NDK/" android_arch=<arch>
```
The value of `android_arch` can be `armv7, arm64v8, x86, x86_64`. Most Android
devices in use nowadays use an ARM architecture, so compiling for `armv7` and
`arm64v8` is often enough when distributing an application.
`ANDROID_NDK_ROOT` can also be set in the environment variables of your PC if
you don't want to include it in your SCons call.
#### Compilation options
You can optionally add the following options to the SCons command line:
- When targeting Linux, add `use_llvm=yes` to use Clang instead of GCC.
- When targeting Windows, add `use_mingw=yes` to use MinGW instead of MSVC.
- When targeting Windows, include `target=runtime` to build a runtime build.
- To use an alternative `api.json` file, add `use_custom_api_file=yes
custom_api_file=../api.json`. Be sure to specify the correct location where
you placed your file (it can be a relative or absolute path).
## Creating a simple class
Create `init.cpp` under `SimpleLibrary/src/` and add the following code:
The `entry_symbol` is the name of the function that initializes
your library. It should be similar to following layout:
```cpp
#include <Godot.hpp>
#include <Reference.hpp>
extern "C" {
// Initialization.
GDExtensionBool GDE_EXPORT example_library_init(GDExtensionInterfaceGetProcAddress p_get_proc_address, GDExtensionClassLibraryPtr p_library, GDExtensionInitialization *r_initialization) {
godot::GDExtensionBinding::InitObject init_obj(p_get_proc_address, p_library, r_initialization);
init_obj.register_initializer(initialize_example_module);
init_obj.register_terminator(uninitialize_example_module);
init_obj.set_minimum_library_initialization_level(MODULE_INITIALIZATION_LEVEL_SCENE);
return init_obj.init();
}
}
```
The `initialize_example_module()` should register the classes in ClassDB, very like a Godot module would do.
```cpp
using namespace godot;
class SimpleClass : public Reference {
GODOT_CLASS(SimpleClass, Reference);
public:
SimpleClass() { }
/** `_init` must exist as it is called by Godot. */
void _init() { }
void test_void_method() {
Godot::print("This is test");
}
Variant method(Variant arg) {
Variant ret;
ret = arg;
return ret;
}
static void _register_methods() {
register_method("method", &SimpleClass::method);
/**
* The line below is equivalent to the following GDScript export:
* export var _name = "SimpleClass"
**/
register_property<SimpleClass, String>("base/name", &SimpleClass::_name, String("SimpleClass"));
/** Alternatively, with getter and setter methods: */
register_property<SimpleClass, int>("base/value", &SimpleClass::set_value, &SimpleClass::get_value, 0);
/** Registering a signal: **/
// register_signal<SimpleClass>("signal_name");
// register_signal<SimpleClass>("signal_name", "string_argument", GODOT_VARIANT_TYPE_STRING)
}
String _name;
int _value;
void set_value(int p_value) {
_value = p_value;
}
int get_value() const {
return _value;
}
};
/** GDNative Initialize **/
extern "C" void GDN_EXPORT godot_gdnative_init(godot_gdnative_init_options *o) {
godot::Godot::gdnative_init(o);
}
/** GDNative Terminate **/
extern "C" void GDN_EXPORT godot_gdnative_terminate(godot_gdnative_terminate_options *o) {
godot::Godot::gdnative_terminate(o);
}
/** NativeScript Initialize **/
extern "C" void GDN_EXPORT godot_nativescript_init(void *handle) {
godot::Godot::nativescript_init(handle);
godot::register_class<SimpleClass>();
void initialize_example_module(ModuleInitializationLevel p_level) {
if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
return;
}
ClassDB::register_class<Example>();
}
```
### Compiling the GDNative library
Any node and resource you register will be available in the corresponding `Create...` dialog. Any class will be available to scripting as well.
Once you've compiled the GDNative C++ bindings (see above), you can compile the GDNative library we've just created.
## Examples and templates
#### Linux
See the [godot-cpp-template](https://github.com/godotengine/godot-cpp-template) project for a
generic reusable template.
```bash
cd SimpleLibrary
clang++ -fPIC -o src/init.o -c src/init.cpp -g -O3 -std=c++14 -Igodot-cpp/include -Igodot-cpp/include/core -Igodot-cpp/include/gen -Igodot-cpp/godot-headers
clang++ -o bin/libtest.so -shared src/init.o -Lgodot-cpp/bin -l<name of the godot-cpp>
```
You'll need to replace `<name of the godot-cpp>` with the file that was created in [**Compiling the cpp bindings library**](#compiling-the-cpp-bindings-library).
This creates the file `libtest.so` in your `SimpleLibrary/bin` directory.
#### Windows
```bash
cd SimpleLibrary
cl /Fosrc/init.obj /c src/init.cpp /nologo -EHsc -DNDEBUG /MDd /Igodot-cpp\include /Igodot-cpp\include\core /Igodot-cpp\include\gen /Igodot-cpp\godot-headers
link /nologo /dll /out:bin\libtest.dll /implib:bin\libsimple.lib src\init.obj godot-cpp\bin\<name of the godot-cpp>
```
You'll need to replace `<name of the godot-cpp>` with the file that was created
in [**Compiling the cpp bindingslibrary**](#compiling-the-cpp-bindings-library).
Replace `/MDd` with `/MD` to create a release build, which will run faster and
be smaller.
This creates the file `libtest.dll` in your `SimpleLibrary/bin` directory.
#### macOS
For macOS, you'll need to find out which compiler flags need to be used. These
are likely similar to Linux when using Clang, but may not be identical.
If you find suitable compiler flags for this example library, feel free to
submit a pull request :slightly_smiling_face:
#### Android
```bash
cd SimpleLibrary
aarch64-linux-android29-clang++ -fPIC -o src/init.o -c src/init.cpp -g -O3 -std=c++14 -Igodot-cpp/include -Igodot-cpp/include/core -Igodot-cpp/include/gen -Igodot-cpp/godot-headers
aarch64-linux-android29-clang++ -o bin/libtest.so -shared src/init.o -Lgodot-cpp/bin -l<name of the godot-cpp>
```
You'll need to replace `<name of the godot-cpp>` with the file that was created in [**Compiling the cpp bindings library**](#compiling-the-cpp-bindings-library). The command above targets `arm64v8`. To target `armv7`, use `armv7a-linux-androideabi29-clang++` instead of `aarch64-linux-android29-clang++`.
This creates the file `libtest.so` in your `SimpleLibrary/bin` directory.
#### iOS
GDNative isn't supported on iOS yet. This is because iOS only allows linking
static libraries, not dynamic libraries. In theory, it would be possible to link
a GDNative library statically, but some of GDNative's convenience would be lost
in the process as one would have to recompile the engine on every change. See
[issue #30](https://github.com/godotengine/godot-headers/issues/30) in the
Godot headers repository for more information.
#### HTML5
GDNative isn't supported on the HTML5 platform yet. Support is being tracked on
[issue #12243](https://github.com/godotengine/godot/issues/12243) in the main
Godot repository.
### Creating `.gdnlib` and `.gdns` files
Follow the instructions in
[godot-headers/README.md](https://github.com/godotengine/godot-headers/blob/master/README.md#how-do-i-use-native-scripts-from-the-editor)
to create the `.gdns` file. This file contains paths to GDNative libraries for
various platforms. This makes the library usable from Godot in a
platform-independent manner.
### Implementing with GDScript
Once your GDNative library is compiled and referenced in a `.gdns` file, you can use it in GDScript or C#. Here's an example with GDScript:
```gdscript
var simpleclass = load("res://simpleclass.gdns").new()
simpleclass.method("Test argument")
```
### Using Godot classes in C++
Godot expects you to manage its classes the same way the engine does. These rules apply to all Godot classes, including your NativeScripts, but not to any normal C++ classes used in your library.
- Instantiate Objects using `_new()`, not C++'s `new` operator.
```cpp
Sprite *sprite = Sprite::_new();
```
- Destroy Nodes using `queue_free()`, not C++'s `delete` operator.
```cpp
some_old_node->queue_free();
```
- Wrap References in `Ref` instead of passing around raw pointers. They are reference-counted and don't need to be freed manually.
```cpp
Ref<Texture> texture = resource_loader->load("res://icon.png");
```
- Pass core types that do *not* inherit Object by value. The containers (Array, Dictionary, PoolArray, String) manage their own memory and do not need to be explicitly initialized or freed.
```cpp
Array ints;
ints.append(123);
return ints;
```
- Initialize your NativeScript classes in their `_init()` method, not their constructor. The constructor can't access the base class's methods.
- Cast objects using `Object::cast_to`, not unsafe C-style casts or `static_cast`.
```cpp
MeshInstance *m = Object::cast_to<MeshInstance>(get_node("ChildNode"));
// `m` will be null if it's not a MeshInstance
if (m) { ... }
```
- **Never** use Godot types in static or global variables. The Godot API isn't loaded until after their constructors are called.
```cpp
String s; // crashes
class SomeClass {
static Dictionary d; // crashes
static Node *node_a = NULL; // fine, it's just a pointer
static Node *node_b = Node::_new(); // crashes
};
```
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).

View File

@@ -1,415 +1,56 @@
#!/usr/bin/env python
import os
import platform
import sys
import subprocess
if sys.version_info < (3,):
def decode_utf8(x):
return x
else:
import codecs
def decode_utf8(x):
return codecs.utf_8_decode(x)[0]
# Workaround for MinGW. See:
# http://www.scons.org/wiki/LongCmdLinesOnWin32
if (os.name=="nt"):
import subprocess
def mySubProcess(cmdline,env):
#print "SPAWNED : " + cmdline
startupinfo = subprocess.STARTUPINFO()
startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW
proc = subprocess.Popen(cmdline, stdin=subprocess.PIPE, stdout=subprocess.PIPE,
stderr=subprocess.PIPE, startupinfo=startupinfo, shell = False, env = env)
data, err = proc.communicate()
rv = proc.wait()
if rv:
print("=====")
print(err.decode("utf-8"))
print("=====")
return rv
def mySpawn(sh, escape, cmd, args, env):
newargs = ' '.join(args[1:])
cmdline = cmd + " " + newargs
rv=0
if len(cmdline) > 32000 and cmd.endswith("ar") :
cmdline = cmd + " " + args[1] + " " + args[2] + " "
for i in range(3,len(args)) :
rv = mySubProcess( cmdline + args[i], env )
if rv :
break
else:
rv = mySubProcess( cmdline, env )
return rv
def add_sources(sources, dir, extension):
for f in os.listdir(dir):
if f.endswith('.' + extension):
sources.append(dir + '/' + f)
from binding_generator import scons_generate_bindings, scons_emit_files
# Try to detect the host platform automatically.
# This is used if no `platform` argument is passed
if sys.platform.startswith('linux'):
host_platform = 'linux'
elif sys.platform == 'darwin':
host_platform = 'osx'
elif sys.platform == 'win32' or sys.platform == 'msys':
host_platform = 'windows'
else:
raise ValueError(
'Could not detect platform automatically, please specify with '
'platform=<platform>'
)
EnsureSConsVersion(4, 0)
env = Environment(ENV = os.environ)
is64 = sys.maxsize > 2**32
if (
env['TARGET_ARCH'] == 'amd64' or
env['TARGET_ARCH'] == 'emt64' or
env['TARGET_ARCH'] == 'x86_64' or
env['TARGET_ARCH'] == 'arm64-v8a'
):
is64 = True
try:
Import("env")
except:
# Default tools with no platform defaults to gnu toolchain.
# We apply platform specific toolchains via our custom tools.
env = Environment(tools=["default"], PLATFORM="")
opts = Variables([], ARGUMENTS)
opts.Add(EnumVariable(
'platform',
'Target platform',
host_platform,
allowed_values=('linux', 'osx', 'windows', 'android', 'ios'),
ignorecase=2
))
opts.Add(EnumVariable(
'bits',
'Target platform bits',
'64' if is64 else '32',
('32', '64')
))
opts.Add(BoolVariable(
'use_llvm',
'Use the LLVM compiler - only effective when targeting Linux',
False
))
opts.Add(BoolVariable(
'use_mingw',
'Use the MinGW compiler instead of MSVC - only effective on Windows',
False
))
# Must be the same setting as used for cpp_bindings
opts.Add(EnumVariable(
'target',
'Compilation target',
'debug',
allowed_values=('debug', 'release'),
ignorecase=2
))
opts.Add(PathVariable(
'headers_dir',
'Path to the directory containing Godot headers',
'godot-headers',
PathVariable.PathIsDir
))
opts.Add(PathVariable(
'custom_api_file',
'Path to a custom JSON API file',
None,
PathVariable.PathIsFile
))
opts.Add(BoolVariable(
'generate_bindings',
'Generate GDNative API bindings',
False
))
opts.Add(EnumVariable(
'android_arch',
'Target Android architecture',
'armv7',
['armv7','arm64v8','x86','x86_64']
))
opts.Add(
'macos_deployment_target',
'macOS deployment target',
'default'
)
opts.Add(EnumVariable(
'ios_arch',
'Target iOS architecture',
'arm64',
['armv7', 'arm64', 'x86_64']
))
opts.Add(BoolVariable(
'ios_simulator',
'Target iOS Simulator',
False
))
opts.Add(
'IPHONEPATH',
'Path to iPhone toolchain',
'/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain',
)
opts.Add(
'android_api_level',
'Target Android API level',
'18' if ARGUMENTS.get("android_arch", 'armv7') in ['armv7', 'x86'] else '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)
)
opts.Add(BoolVariable(
'generate_template_get_node',
"Generate a template version of the Node class's get_node.",
True
))
env.PrependENVPath("PATH", os.getenv("PATH"))
# 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):
customs.append(profile)
elif os.path.isfile(profile + ".py"):
customs.append(profile + ".py")
opts = Variables(customs, ARGUMENTS)
cpp_tool = Tool("godotcpp", toolpath=["tools"])
cpp_tool.options(opts, env)
opts.Update(env)
Help(opts.GenerateHelpText(env))
# This makes sure to keep the session environment variables on Windows.
# This way, you can run SCons in a Visual Studio 2017 prompt and it will find
# all the required tools
if host_platform == 'windows' and env['platform'] != 'android':
if env['bits'] == '64':
env = Environment(TARGET_ARCH='amd64')
elif env['bits'] == '32':
env = Environment(TARGET_ARCH='x86')
# Detect and print a warning listing unknown SCons variables to ease troubleshooting.
unknown = opts.UnknownVariables()
if unknown:
print("WARNING: Unknown SCons variables were passed and will be ignored:")
for item in unknown.items():
print(" " + item[0] + "=" + item[1])
opts.Update(env)
scons_cache_path = os.environ.get("SCONS_CACHE")
if scons_cache_path is not None:
CacheDir(scons_cache_path)
Decider("MD5")
if env['platform'] == 'linux':
if env['use_llvm']:
env['CXX'] = 'clang++'
cpp_tool.generate(env)
library = env.GodotCPP()
env.Append(CCFLAGS=['-fPIC', '-std=c++14', '-Wwrite-strings'])
env.Append(LINKFLAGS=["-Wl,-R,'$$ORIGIN'"])
if env['target'] == 'debug':
env.Append(CCFLAGS=['-Og', '-g'])
elif env['target'] == 'release':
env.Append(CCFLAGS=['-O3'])
if env['bits'] == '64':
env.Append(CCFLAGS=['-m64'])
env.Append(LINKFLAGS=['-m64'])
elif env['bits'] == '32':
env.Append(CCFLAGS=['-m32'])
env.Append(LINKFLAGS=['-m32'])
elif env['platform'] == 'osx':
# Use Clang on macOS by default
env['CXX'] = 'clang++'
if env['bits'] == '32':
raise ValueError(
'Only 64-bit builds are supported for the macOS target.'
)
env.Append(CCFLAGS=['-std=c++14', '-arch', 'x86_64'])
if env['macos_deployment_target'] != 'default':
env.Append(CCFLAGS=['-mmacosx-version-min=' + env['macos_deployment_target']])
env.Append(LINKFLAGS=[
'-arch',
'x86_64',
'-framework',
'Cocoa',
'-Wl,-undefined,dynamic_lookup',
])
if env['target'] == 'debug':
env.Append(CCFLAGS=['-Og', '-g'])
elif env['target'] == 'release':
env.Append(CCFLAGS=['-O3'])
elif env['platform'] == 'ios':
if env['ios_simulator']:
sdk_name = 'iphonesimulator'
env.Append(CCFLAGS=['-mios-simulator-version-min=10.0'])
env['LIBSUFFIX'] = ".simulator" + env['LIBSUFFIX']
else:
sdk_name = 'iphoneos'
env.Append(CCFLAGS=['-miphoneos-version-min=10.0'])
try:
sdk_path = decode_utf8(subprocess.check_output(['xcrun', '--sdk', sdk_name, '--show-sdk-path']).strip())
except (subprocess.CalledProcessError, OSError):
raise ValueError("Failed to find SDK path while running xcrun --sdk {} --show-sdk-path.".format(sdk_name))
compiler_path = env['IPHONEPATH'] + '/usr/bin/'
env['ENV']['PATH'] = env['IPHONEPATH'] + "/Developer/usr/bin/:" + env['ENV']['PATH']
env['CC'] = compiler_path + 'clang'
env['CXX'] = compiler_path + 'clang++'
env['AR'] = compiler_path + 'ar'
env['RANLIB'] = compiler_path + 'ranlib'
env.Append(CCFLAGS=['-std=c++14', '-arch', env['ios_arch'], '-isysroot', sdk_path])
env.Append(LINKFLAGS=[
'-arch',
env['ios_arch'],
'-framework',
'Cocoa',
'-Wl,-undefined,dynamic_lookup',
'-isysroot', sdk_path,
'-F' + sdk_path
])
if env['target'] == 'debug':
env.Append(CCFLAGS=['-Og', '-g'])
elif env['target'] == 'release':
env.Append(CCFLAGS=['-O3'])
elif env['platform'] == 'windows':
if host_platform == 'windows' and not env['use_mingw']:
# MSVC
env.Append(LINKFLAGS=['/WX'])
if env['target'] == 'debug':
env.Append(CCFLAGS=['/Z7', '/Od', '/EHsc', '/D_DEBUG', '/MDd'])
elif env['target'] == 'release':
env.Append(CCFLAGS=['/O2', '/EHsc', '/DNDEBUG', '/MD'])
elif host_platform == 'linux' or host_platform == 'osx':
# Cross-compilation using MinGW
if env['bits'] == '64':
env['CXX'] = 'x86_64-w64-mingw32-g++'
env['AR'] = "x86_64-w64-mingw32-ar"
env['RANLIB'] = "x86_64-w64-mingw32-ranlib"
env['LINK'] = "x86_64-w64-mingw32-g++"
elif env['bits'] == '32':
env['CXX'] = 'i686-w64-mingw32-g++'
env['AR'] = "i686-w64-mingw32-ar"
env['RANLIB'] = "i686-w64-mingw32-ranlib"
env['LINK'] = "i686-w64-mingw32-g++"
elif host_platform == 'windows' and env['use_mingw']:
# Don't Clone the environment. Because otherwise, SCons will pick up msvc stuff.
env = Environment(ENV = os.environ, tools=["mingw"])
opts.Update(env)
#env = env.Clone(tools=['mingw'])
env["SPAWN"] = mySpawn
# Native or cross-compilation using MinGW
if host_platform == 'linux' or host_platform == 'osx' or env['use_mingw']:
# These options are for a release build even using target=debug
env.Append(CCFLAGS=['-O3', '-std=c++14', '-Wwrite-strings'])
env.Append(LINKFLAGS=[
'--static',
'-Wl,--no-undefined',
'-static-libgcc',
'-static-libstdc++',
])
elif env['platform'] == 'android':
if host_platform == 'windows':
# Don't Clone the environment. Because otherwise, SCons will pick up msvc stuff.
env = Environment(ENV = os.environ, tools=["mingw"])
opts.Update(env)
#env = env.Clone(tools=['mingw'])
env["SPAWN"] = mySpawn
# Verify NDK root
if not 'ANDROID_NDK_ROOT' in env:
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.")
# Validate API level
api_level = int(env['android_api_level'])
if env['android_arch'] in ['x86_64', 'arm64v8'] and api_level < 21:
print("WARN: 64-bit Android architectures require an API level of at least 21; setting android_api_level=21")
env['android_api_level'] = '21'
api_level = 21
# Setup toolchain
toolchain = env['ANDROID_NDK_ROOT'] + "/toolchains/llvm/prebuilt/"
if host_platform == "windows":
toolchain += "windows"
import platform as pltfm
if pltfm.machine().endswith("64"):
toolchain += "-x86_64"
elif host_platform == "linux":
toolchain += "linux-x86_64"
elif host_platform == "osx":
toolchain += "darwin-x86_64"
env.PrependENVPath('PATH', toolchain + "/bin") # This does nothing half of the time, but we'll put it here anyways
# Get architecture info
arch_info_table = {
"armv7" : {
"march":"armv7-a", "target":"armv7a-linux-androideabi", "tool_path":"arm-linux-androideabi", "compiler_path":"armv7a-linux-androideabi",
"ccflags" : ['-mfpu=neon']
},
"arm64v8" : {
"march":"armv8-a", "target":"aarch64-linux-android", "tool_path":"aarch64-linux-android", "compiler_path":"aarch64-linux-android",
"ccflags" : []
},
"x86" : {
"march":"i686", "target":"i686-linux-android", "tool_path":"i686-linux-android", "compiler_path":"i686-linux-android",
"ccflags" : ['-mstackrealign']
},
"x86_64" : {"march":"x86-64", "target":"x86_64-linux-android", "tool_path":"x86_64-linux-android", "compiler_path":"x86_64-linux-android",
"ccflags" : []
}
}
arch_info = arch_info_table[env['android_arch']]
# Setup tools
env['CC'] = toolchain + "/bin/clang"
env['CXX'] = toolchain + "/bin/clang++"
env['AR'] = toolchain + "/bin/" + arch_info['tool_path'] + "-ar"
env.Append(CCFLAGS=['--target=' + arch_info['target'] + env['android_api_level'], '-march=' + arch_info['march'], '-fPIC'])#, '-fPIE', '-fno-addrsig', '-Oz'])
env.Append(CCFLAGS=arch_info['ccflags'])
env.Append(CPPPATH=[
'.',
env['headers_dir'],
'include',
'include/gen',
'include/core',
])
# Generate bindings?
json_api_file = ''
if 'custom_api_file' in env:
json_api_file = env['custom_api_file']
else:
json_api_file = os.path.join(os.getcwd(), env['headers_dir'], 'api.json')
if env['generate_bindings']:
# Actually create the bindings here
import binding_generator
binding_generator.generate_bindings(json_api_file, env['generate_template_get_node'])
# Sources to compile
sources = []
add_sources(sources, 'src/core', 'cpp')
add_sources(sources, 'src/gen', 'cpp')
arch_suffix = env['bits']
if env['platform'] == 'android':
arch_suffix = env['android_arch']
if env['platform'] == 'ios':
arch_suffix = env['ios_arch']
library = env.StaticLibrary(
target='bin/' + 'libgodot-cpp.{}.{}.{}{}'.format(
env['platform'],
env['target'],
arch_suffix,
env['LIBSUFFIX']
), source=sources
)
Default(library)
Return("env")

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,94 @@
# Add warnings based on compiler & version
# Set some helper variables for readability
set( compiler_less_than_v8 "$<VERSION_LESS:$<CXX_COMPILER_VERSION>,8>" )
set( compiler_greater_than_or_equal_v9 "$<VERSION_GREATER_EQUAL:$<CXX_COMPILER_VERSION>,9>" )
set( compiler_greater_than_or_equal_v11 "$<VERSION_GREATER_EQUAL:$<CXX_COMPILER_VERSION>,11>" )
set( compiler_less_than_v11 "$<VERSION_LESS:$<CXX_COMPILER_VERSION>,11>" )
set( compiler_greater_than_or_equal_v12 "$<VERSION_GREATER_EQUAL:$<CXX_COMPILER_VERSION>,12>" )
# These compiler options reflect what is in godot/SConstruct.
target_compile_options( ${PROJECT_NAME} PRIVATE
# MSVC only
$<${compiler_is_msvc}:
/W4
# Disable warnings which we don't plan to fix.
/wd4100 # C4100 (unreferenced formal parameter): Doesn't play nice with polymorphism.
/wd4127 # C4127 (conditional expression is constant)
/wd4201 # C4201 (non-standard nameless struct/union): Only relevant for C89.
/wd4244 # C4244 C4245 C4267 (narrowing conversions): Unavoidable at this scale.
/wd4245
/wd4267
/wd4305 # C4305 (truncation): double to float or real_t, too hard to avoid.
/wd4514 # C4514 (unreferenced inline function has been removed)
/wd4714 # C4714 (function marked as __forceinline not inlined)
/wd4820 # C4820 (padding added after construct)
>
# Clang and GNU common options
$<$<OR:${compiler_is_clang},${compiler_is_gnu}>:
-Wall
-Wctor-dtor-privacy
-Wextra
-Wno-unused-parameter
-Wnon-virtual-dtor
-Wwrite-strings
>
# Clang only
$<${compiler_is_clang}:
-Wimplicit-fallthrough
-Wno-ordered-compare-function-pointers
>
# GNU only
$<${compiler_is_gnu}:
-Walloc-zero
-Wduplicated-branches
-Wduplicated-cond
-Wno-misleading-indentation
-Wplacement-new=1
-Wshadow-local
-Wstringop-overflow=4
>
$<$<AND:${compiler_is_gnu},${compiler_less_than_v8}>:
# Bogus warning fixed in 8+.
-Wno-strict-overflow
>
$<$<AND:${compiler_is_gnu},${compiler_greater_than_or_equal_v9}>:
-Wattribute-alias=2
>
$<$<AND:${compiler_is_gnu},${compiler_greater_than_or_equal_v11}>:
# Broke on MethodBind templates before GCC 11.
-Wlogical-op
>
$<$<AND:${compiler_is_gnu},${compiler_less_than_v11}>:
# Regression in GCC 9/10, spams so much in our variadic templates that we need to outright disable it.
-Wno-type-limits
>
$<$<AND:${compiler_is_gnu},${compiler_greater_than_or_equal_v12}>:
# False positives in our error macros, see GH-58747.
-Wno-return-type
>
)
# Treat warnings as errors
function( set_warning_as_error )
message( STATUS "[${PROJECT_NAME}] Treating warnings as errors")
if ( CMAKE_VERSION VERSION_GREATER_EQUAL "3.24" )
set_target_properties( ${PROJECT_NAME}
PROPERTIES
COMPILE_WARNING_AS_ERROR ON
)
else()
target_compile_options( ${PROJECT_NAME}
PRIVATE
$<${compiler_is_msvc}:/WX>
$<$<OR:${compiler_is_clang},${compiler_is_gnu}>:-Werror>
)
endif()
endfunction()
if ( GODOT_CPP_WARNING_AS_ERROR )
set_warning_as_error()
endif()

20
gdextension/README.md Normal file
View File

@@ -0,0 +1,20 @@
# GDExtension header and API
This repository contains the C header and API JSON for
[**Godot Engine**](https://github.com/godotengine/godot)'s *GDExtensions* API.
## Updating header and API
If the current branch is not up-to-date for your needs, or if you want to sync
the header and API JSON with your own modified version of Godot, here is the
update procedure used to sync this repository with upstream releases:
- Compile [Godot Engine](https://github.com/godotengine/godot) at the specific
version/commit which you are using.
* Or if you use an official release, download that version of the Godot editor.
- Use the compiled or downloaded executable to generate the `extension_api.json`
and `gdextension_interface.h` files with:
```
godot --dump-extension-api --dump-gdextension-interface
```

283797
gdextension/extension_api.json Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

Submodule godot-headers deleted from 815f34e1e9

View File

@@ -1,82 +0,0 @@
#ifndef AABB_H
#define AABB_H
#include "Vector3.hpp"
#include "Plane.hpp"
#include <cstdlib>
namespace godot {
class AABB {
public:
Vector3 position;
Vector3 size;
real_t get_area() const; /// get area
inline bool has_no_area() const {
return (size.x <= CMP_EPSILON || size.y <= CMP_EPSILON || size.z <= CMP_EPSILON);
}
inline bool has_no_surface() const {
return (size.x <= CMP_EPSILON && size.y <= CMP_EPSILON && size.z <= CMP_EPSILON);
}
inline const Vector3 &get_position() const { return position; }
inline void set_position(const Vector3 &p_position) { position = p_position; }
inline const Vector3 &get_size() const { return size; }
inline void set_size(const Vector3 &p_size) { size = p_size; }
bool operator==(const AABB &p_rval) const;
bool operator!=(const AABB &p_rval) const;
bool intersects(const AABB &p_aabb) const; /// Both AABBs overlap
bool intersects_inclusive(const AABB &p_aabb) const; /// Both AABBs (or their faces) overlap
bool encloses(const AABB &p_aabb) const; /// p_aabb is completely inside this
AABB merge(const AABB &p_with) const;
void merge_with(const AABB &p_aabb); ///merge with another AABB
AABB intersection(const AABB &p_aabb) const; ///get box where two intersect, empty if no intersection occurs
bool intersects_segment(const Vector3 &p_from, const Vector3 &p_to, Vector3 *r_clip = nullptr, Vector3 *r_normal = nullptr) const;
bool intersects_ray(const Vector3 &p_from, const Vector3 &p_dir, Vector3 *r_clip = nullptr, Vector3 *r_normal = nullptr) const;
bool smits_intersect_ray(const Vector3 &from, const Vector3 &p_dir, real_t t0, real_t t1) const;
bool intersects_convex_shape(const Plane *p_plane, int p_plane_count) const;
bool intersects_plane(const Plane &p_plane) const;
bool has_point(const Vector3 &p_point) const;
Vector3 get_support(const Vector3 &p_normal) const;
Vector3 get_longest_axis() const;
int get_longest_axis_index() const;
real_t get_longest_axis_size() const;
Vector3 get_shortest_axis() const;
int get_shortest_axis_index() const;
real_t get_shortest_axis_size() const;
AABB grow(real_t p_by) const;
void grow_by(real_t p_amount);
void get_edge(int p_edge, Vector3 &r_from, Vector3 &r_to) const;
Vector3 get_endpoint(int p_point) const;
AABB expand(const Vector3 &p_vector) const;
void project_range_in_plane(const Plane &p_plane, real_t &r_min, real_t &r_max) const;
void expand_to(const Vector3 &p_vector); /** expand to contain a point if necesary */
operator String() const;
inline AABB() {}
inline AABB(const Vector3 &p_pos, const Vector3 &p_size) {
position = p_pos;
size = p_size;
}
};
} // namespace godot
#endif // RECT3_H

View File

@@ -1,161 +0,0 @@
#ifndef ARRAY_H
#define ARRAY_H
#include <gdnative/array.h>
#include "String.hpp"
namespace godot {
namespace helpers {
template <typename T, typename ValueT>
T append_all(T appendable, ValueT value) {
appendable.append(value);
return appendable;
}
template <typename T, typename ValueT, typename... Args>
T append_all(T appendable, ValueT value, Args... args) {
appendable.append(value);
return append_all(appendable, args...);
}
template <typename T>
T append_all(T appendable) {
return appendable;
}
template <typename KV, typename KeyT, typename ValueT>
KV add_all(KV kv, KeyT key, ValueT value) {
kv[key] = value;
return kv;
}
template <typename KV, typename KeyT, typename ValueT, typename... Args>
KV add_all(KV kv, KeyT key, ValueT value, Args... args) {
kv[key] = value;
return add_all(kv, args...);
}
template <typename KV>
KV add_all(KV kv) {
return kv;
}
} // namespace helpers
class Variant;
class PoolByteArray;
class PoolIntArray;
class PoolRealArray;
class PoolStringArray;
class PoolVector2Array;
class PoolVector3Array;
class PoolColorArray;
class Object;
class Array {
godot_array _godot_array;
friend class Variant;
friend class Dictionary;
friend class String;
inline explicit Array(const godot_array &other) {
_godot_array = other;
}
public:
Array();
Array(const Array &other);
Array &operator=(const Array &other);
Array(const PoolByteArray &a);
Array(const PoolIntArray &a);
Array(const PoolRealArray &a);
Array(const PoolStringArray &a);
Array(const PoolVector2Array &a);
Array(const PoolVector3Array &a);
Array(const PoolColorArray &a);
template <class... Args>
static Array make(Args... args) {
return helpers::append_all(Array(), args...);
}
Variant &operator[](const int idx);
const Variant &operator[](const int idx) const;
void append(const Variant &v);
void clear();
int count(const Variant &v);
bool empty() const;
void erase(const Variant &v);
Variant front() const;
Variant back() const;
int find(const Variant &what, const int from = 0) const;
int find_last(const Variant &what) const;
bool has(const Variant &what) const;
uint32_t hash() const;
void insert(const int pos, const Variant &value);
void invert();
bool is_shared() const;
Variant pop_back();
Variant pop_front();
void push_back(const Variant &v);
void push_front(const Variant &v);
void remove(const int idx);
int size() const;
void resize(const int size);
int rfind(const Variant &what, const int from = -1) const;
void sort();
void sort_custom(Object *obj, const String &func);
int bsearch(const Variant &value, const bool before = true);
int bsearch_custom(const Variant &value, const Object *obj,
const String &func, const bool before = true);
Array duplicate(const bool deep = false) const;
Variant max() const;
Variant min() const;
void shuffle();
~Array();
};
} // namespace godot
#endif // ARRAY_H

View File

@@ -1,428 +0,0 @@
#ifndef BASIS_H
#define BASIS_H
#include <gdnative/basis.h>
#include "Defs.hpp"
#include "Vector3.hpp"
namespace godot {
class Quat;
class Basis {
private:
static const Basis IDENTITY;
static const Basis FLIP_X;
static const Basis FLIP_Y;
static const Basis FLIP_Z;
// This helper template is for mimicking the behavior difference between the engine
// and script interfaces that logically script sees matrices as column major, while
// the engine stores them in row major to efficiently take advantage of SIMD
// instructions in case of matrix-vector multiplications.
// With this helper template native scripts see the data as if it was column major
// without actually transposing the basis matrix at the script-engine boundary.
template <int column>
class ColumnVector3 {
private:
template <int column1, int component>
class ColumnVectorComponent {
private:
Vector3 elements[3];
protected:
inline ColumnVectorComponent<column1, component> &operator=(const ColumnVectorComponent<column1, component> &p_value) {
return *this = real_t(p_value);
}
inline ColumnVectorComponent(const ColumnVectorComponent<column1, component> &p_value) {
*this = real_t(p_value);
}
inline ColumnVectorComponent<column1, component> &operator=(const real_t &p_value) {
elements[component][column1] = p_value;
return *this;
}
inline operator real_t() const {
return elements[component][column1];
}
};
public:
enum Axis {
AXIS_X,
AXIS_Y,
AXIS_Z,
};
union {
ColumnVectorComponent<column, 0> x;
ColumnVectorComponent<column, 1> y;
ColumnVectorComponent<column, 2> z;
Vector3 elements[3]; // Not for direct access, use [] operator instead
};
inline ColumnVector3<column> &operator=(const ColumnVector3<column> &p_value) {
return *this = Vector3(p_value);
}
inline ColumnVector3(const ColumnVector3<column> &p_value) {
*this = Vector3(p_value);
}
inline ColumnVector3<column> &operator=(const Vector3 &p_value) {
elements[0][column] = p_value.x;
elements[1][column] = p_value.y;
elements[2][column] = p_value.z;
return *this;
}
inline operator Vector3() const {
return Vector3(elements[0][column], elements[1][column], elements[2][column]);
}
// Unfortunately, we also need to replicate the other interfaces of Vector3 in
// order for being able to directly operate on these "meta-Vector3" objects without
// an explicit cast or an intermediate assignment to a real Vector3 object.
inline const real_t &operator[](int p_axis) const {
return elements[p_axis][column];
}
inline real_t &operator[](int p_axis) {
return elements[p_axis][column];
}
inline ColumnVector3<column> &operator+=(const Vector3 &p_v) {
return *this = *this + p_v;
}
inline Vector3 operator+(const Vector3 &p_v) const {
return Vector3(*this) + p_v;
}
inline ColumnVector3<column> &operator-=(const Vector3 &p_v) {
return *this = *this - p_v;
}
inline Vector3 operator-(const Vector3 &p_v) const {
return Vector3(*this) - p_v;
}
inline ColumnVector3<column> &operator*=(const Vector3 &p_v) {
return *this = *this * p_v;
}
inline Vector3 operator*(const Vector3 &p_v) const {
return Vector3(*this) * p_v;
}
inline ColumnVector3<column> &operator/=(const Vector3 &p_v) {
return *this = *this / p_v;
}
inline Vector3 operator/(const Vector3 &p_v) const {
return Vector3(*this) / p_v;
}
inline ColumnVector3<column> &operator*=(real_t p_scalar) {
return *this = *this * p_scalar;
}
inline Vector3 operator*(real_t p_scalar) const {
return Vector3(*this) * p_scalar;
}
inline ColumnVector3<column> &operator/=(real_t p_scalar) {
return *this = *this / p_scalar;
}
inline Vector3 operator/(real_t p_scalar) const {
return Vector3(*this) / p_scalar;
}
inline Vector3 operator-() const {
return -Vector3(*this);
}
inline bool operator==(const Vector3 &p_v) const {
return Vector3(*this) == p_v;
}
inline bool operator!=(const Vector3 &p_v) const {
return Vector3(*this) != p_v;
}
inline bool operator<(const Vector3 &p_v) const {
return Vector3(*this) < p_v;
}
inline bool operator<=(const Vector3 &p_v) const {
return Vector3(*this) <= p_v;
}
inline Vector3 abs() const {
return Vector3(*this).abs();
}
inline Vector3 ceil() const {
return Vector3(*this).ceil();
}
inline Vector3 cross(const Vector3 &b) const {
return Vector3(*this).cross(b);
}
inline Vector3 linear_interpolate(const Vector3 &p_b, real_t p_t) const {
return Vector3(*this).linear_interpolate(p_b, p_t);
}
inline Vector3 cubic_interpolate(const Vector3 &b, const Vector3 &pre_a, const Vector3 &post_b, const real_t t) const {
return Vector3(*this).cubic_interpolate(b, pre_a, post_b, t);
}
inline Vector3 bounce(const Vector3 &p_normal) const {
return Vector3(*this).bounce(p_normal);
}
inline real_t length() const {
return Vector3(*this).length();
}
inline real_t length_squared() const {
return Vector3(*this).length_squared();
}
inline real_t distance_squared_to(const Vector3 &b) const {
return Vector3(*this).distance_squared_to(b);
}
inline real_t distance_to(const Vector3 &b) const {
return Vector3(*this).distance_to(b);
}
inline real_t dot(const Vector3 &b) const {
return Vector3(*this).dot(b);
}
inline real_t angle_to(const Vector3 &b) const {
return Vector3(*this).angle_to(b);
}
inline Vector3 floor() const {
return Vector3(*this).floor();
}
inline Vector3 inverse() const {
return Vector3(*this).inverse();
}
inline bool is_normalized() const {
return Vector3(*this).is_normalized();
}
inline Basis outer(const Vector3 &b) const {
return Vector3(*this).outer(b);
}
inline int max_axis() const {
return Vector3(*this).max_axis();
}
inline int min_axis() const {
return Vector3(*this).min_axis();
}
inline void normalize() {
Vector3 v = *this;
v.normalize();
*this = v;
}
inline Vector3 normalized() const {
return Vector3(*this).normalized();
}
inline Vector3 reflect(const Vector3 &by) const {
return Vector3(*this).reflect(by);
}
inline Vector3 rotated(const Vector3 &axis, const real_t phi) const {
return Vector3(*this).rotated(axis, phi);
}
inline void rotate(const Vector3 &p_axis, real_t p_phi) {
Vector3 v = *this;
v.rotate(p_axis, p_phi);
*this = v;
}
inline Vector3 slide(const Vector3 &by) const {
return Vector3(*this).slide(by);
}
inline void snap(real_t p_val) {
Vector3 v = *this;
v.snap(p_val);
*this = v;
}
inline Vector3 snapped(const float by) {
return Vector3(*this).snapped(by);
}
inline operator String() const {
return String(Vector3(*this));
}
};
public:
union {
ColumnVector3<0> x;
ColumnVector3<1> y;
ColumnVector3<2> z;
Vector3 elements[3]; // Not for direct access, use [] operator instead
};
inline Basis(const Basis &p_basis) {
elements[0] = p_basis.elements[0];
elements[1] = p_basis.elements[1];
elements[2] = p_basis.elements[2];
}
inline Basis &operator=(const Basis &p_basis) {
elements[0] = p_basis.elements[0];
elements[1] = p_basis.elements[1];
elements[2] = p_basis.elements[2];
return *this;
}
Basis(const Quat &p_quat); // euler
Basis(const Vector3 &p_euler); // euler
Basis(const Vector3 &p_axis, real_t p_phi);
Basis(const Vector3 &row0, const Vector3 &row1, const Vector3 &row2);
Basis(real_t xx, real_t xy, real_t xz, real_t yx, real_t yy, real_t yz, real_t zx, real_t zy, real_t zz);
Basis();
const Vector3 operator[](int axis) const {
return get_axis(axis);
}
ColumnVector3<0> &operator[](int axis) {
// We need to do a little pointer magic to get this to work, because the
// ColumnVector3 template takes the axis as a template parameter.
// Don't touch this unless you're sure what you're doing!
return (reinterpret_cast<Basis *>(reinterpret_cast<real_t *>(this) + axis))->x;
}
void invert();
bool isequal_approx(const Basis &a, const Basis &b) const;
bool is_orthogonal() const;
bool is_rotation() const;
void transpose();
Basis inverse() const;
Basis transposed() const;
real_t determinant() const;
Vector3 get_axis(int p_axis) const;
void set_axis(int p_axis, const Vector3 &p_value);
void rotate(const Vector3 &p_axis, real_t p_phi);
Basis rotated(const Vector3 &p_axis, real_t p_phi) const;
void scale(const Vector3 &p_scale);
Basis scaled(const Vector3 &p_scale) const;
Vector3 get_scale() const;
Basis slerp(Basis b, float t) const;
Vector3 get_euler_xyz() const;
void set_euler_xyz(const Vector3 &p_euler);
Vector3 get_euler_yxz() const;
void set_euler_yxz(const Vector3 &p_euler);
inline Vector3 get_euler() const { return get_euler_yxz(); }
inline void set_euler(const Vector3 &p_euler) { set_euler_yxz(p_euler); }
// transposed dot products
real_t tdotx(const Vector3 &v) const;
real_t tdoty(const Vector3 &v) const;
real_t tdotz(const Vector3 &v) const;
bool operator==(const Basis &p_matrix) const;
bool operator!=(const Basis &p_matrix) const;
Vector3 xform(const Vector3 &p_vector) const;
Vector3 xform_inv(const Vector3 &p_vector) const;
void operator*=(const Basis &p_matrix);
Basis operator*(const Basis &p_matrix) const;
void operator+=(const Basis &p_matrix);
Basis operator+(const Basis &p_matrix) const;
void operator-=(const Basis &p_matrix);
Basis operator-(const Basis &p_matrix) const;
void operator*=(real_t p_val);
Basis operator*(real_t p_val) const;
int get_orthogonal_index() const; // down below
void set_orthogonal_index(int p_index); // down below
operator String() const;
void get_axis_and_angle(Vector3 &r_axis, real_t &r_angle) const;
/* create / set */
void set(real_t xx, real_t xy, real_t xz, real_t yx, real_t yy, real_t yz, real_t zx, real_t zy, real_t zz);
Vector3 get_column(int i) const;
Vector3 get_row(int i) const;
Vector3 get_main_diagonal() const;
void set_row(int i, const Vector3 &p_row);
Basis transpose_xform(const Basis &m) const;
void orthonormalize();
Basis orthonormalized() const;
bool is_symmetric() const;
Basis diagonalize();
operator Quat() const;
};
} // namespace godot
#endif // BASIS_H

View File

@@ -1,96 +0,0 @@
#ifndef CAMERA_MATRIX_H
#define CAMERA_MATRIX_H
#include "Defs.hpp"
#include "Math.hpp"
#include "Plane.hpp"
#include "Rect2.hpp"
#include "Transform.hpp"
#include <vector>
namespace {
using namespace godot;
} // namespace
struct CameraMatrix {
enum Planes {
PLANE_NEAR,
PLANE_FAR,
PLANE_LEFT,
PLANE_TOP,
PLANE_RIGHT,
PLANE_BOTTOM
};
real_t matrix[4][4];
void set_identity();
void set_zero();
void set_light_bias();
void set_light_atlas_rect(const Rect2 &p_rect);
void set_perspective(real_t p_fovy_degrees, real_t p_aspect, real_t p_z_near, real_t p_z_far, bool p_flip_fov = false);
void set_perspective(real_t p_fovy_degrees, real_t p_aspect, real_t p_z_near, real_t p_z_far, bool p_flip_fov, int p_eye, real_t p_intraocular_dist, real_t p_convergence_dist);
void set_for_hmd(int p_eye, real_t p_aspect, real_t p_intraocular_dist, real_t p_display_width, real_t p_display_to_lens, real_t p_oversample, real_t p_z_near, real_t p_z_far);
void set_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);
void set_orthogonal(real_t p_size, real_t p_aspect, real_t p_znear, real_t p_zfar, bool p_flip_fov = false);
void set_frustum(real_t p_left, real_t p_right, real_t p_bottom, real_t p_top, real_t p_near, real_t p_far);
void set_frustum(real_t p_size, real_t p_aspect, Vector2 p_offset, real_t p_near, real_t p_far, bool p_flip_fov = false);
static real_t get_fovy(real_t p_fovx, real_t p_aspect) {
return Math::rad2deg(atan(p_aspect * tan(Math::deg2rad(p_fovx) * 0.5)) * 2.0);
}
static inline double absd(double g) {
union {
double d;
uint64_t i;
} u;
u.d = g;
u.i &= (uint64_t)9223372036854775807ll;
return u.d;
}
real_t get_z_far() const;
real_t get_z_near() const;
real_t get_aspect() const;
real_t get_fov() const;
bool is_orthogonal() const;
std::vector<Plane> get_projection_planes(const Transform &p_transform) const;
bool get_endpoints(const Transform &p_transform, Vector3 *p_8points) const;
Vector2 get_viewport_half_extents() const;
void invert();
CameraMatrix inverse() const;
CameraMatrix operator*(const CameraMatrix &p_matrix) const;
Plane xform4(const Plane &p_vec4) const;
inline Vector3 xform(const Vector3 &p_vec3) const;
operator String() const;
void scale_translate_to_fit(const AABB &p_aabb);
void make_scale(const Vector3 &p_scale);
int get_pixels_per_meter(int p_for_pixel_width) const;
operator Transform() const;
CameraMatrix();
CameraMatrix(const Transform &p_transform);
~CameraMatrix();
};
Vector3 CameraMatrix::xform(const Vector3 &p_vec3) const {
Vector3 ret;
ret.x = matrix[0][0] * p_vec3.x + matrix[1][0] * p_vec3.y + matrix[2][0] * p_vec3.z + matrix[3][0];
ret.y = matrix[0][1] * p_vec3.x + matrix[1][1] * p_vec3.y + matrix[2][1] * p_vec3.z + matrix[3][1];
ret.z = matrix[0][2] * p_vec3.x + matrix[1][2] * p_vec3.y + matrix[2][2] * p_vec3.z + matrix[3][2];
real_t w = matrix[0][3] * p_vec3.x + matrix[1][3] * p_vec3.y + matrix[2][3] * p_vec3.z + matrix[3][3];
return ret / w;
}
#endif

View File

@@ -1,143 +0,0 @@
#ifndef COLOR_H
#define COLOR_H
#include <gdnative/color.h>
#include <cmath>
#include "Defs.hpp"
#include "String.hpp"
namespace godot {
struct Color {
private:
// static float _parse_col(const String& p_str, int p_ofs);
public:
union {
struct {
float r;
float g;
float b;
float a;
};
float components[4];
};
inline bool operator==(const Color &p_color) const { return (r == p_color.r && g == p_color.g && b == p_color.b && a == p_color.a); }
inline bool operator!=(const Color &p_color) const { return (r != p_color.r || g != p_color.g || b != p_color.b || a != p_color.a); }
uint32_t to_32() const;
uint32_t to_ARGB32() const;
uint32_t to_ABGR32() const;
uint64_t to_ABGR64() const;
uint64_t to_ARGB64() const;
uint32_t to_RGBA32() const;
uint64_t to_RGBA64() const;
float gray() const;
uint8_t get_r8() const;
uint8_t get_g8() const;
uint8_t get_b8() const;
uint8_t get_a8() const;
float get_h() const;
float get_s() const;
float get_v() const;
void set_hsv(float p_h, float p_s, float p_v, float p_alpha = 1.0);
Color darkened(const float amount) const;
Color lightened(const float amount) const;
Color from_hsv(float p_h, float p_s, float p_v, float p_a = 1.0) const;
inline float &operator[](int idx) {
return components[idx];
}
inline const float &operator[](int idx) const {
return components[idx];
}
Color operator+(const Color &p_color) const;
void operator+=(const Color &p_color);
Color operator-() const;
Color operator-(const Color &p_color) const;
void operator-=(const Color &p_color);
Color operator*(const Color &p_color) const;
Color operator*(const real_t &rvalue) const;
void operator*=(const Color &p_color);
void operator*=(const real_t &rvalue);
Color operator/(const Color &p_color) const;
Color operator/(const real_t &rvalue) const;
void operator/=(const Color &p_color);
void operator/=(const real_t &rvalue);
void invert();
void contrast();
Color inverted() const;
Color contrasted() const;
Color linear_interpolate(const Color &p_b, float p_t) const;
Color blend(const Color &p_over) const;
Color to_linear() const;
static Color hex(uint32_t p_hex);
static Color html(const String &p_color);
static bool html_is_valid(const String &p_color);
String to_html(bool p_alpha = true) const;
bool operator<(const Color &p_color) const; //used in set keys
operator String() const;
/**
* No construct parameters, r=0, g=0, b=0. a=255
*/
inline Color() {
r = 0;
g = 0;
b = 0;
a = 1.0;
}
/**
* RGB / RGBA construct parameters. Alpha is optional, but defaults to 1.0
*/
inline Color(float p_r, float p_g, float p_b, float p_a = 1.0) {
r = p_r;
g = p_g;
b = p_b;
a = p_a;
}
};
} // namespace godot
#endif // COLOR_H

View File

@@ -1,26 +0,0 @@
#ifndef CORETYPES_H
#define CORETYPES_H
#include "Defs.hpp"
#include "AABB.hpp"
#include "Array.hpp"
#include "Basis.hpp"
#include "Color.hpp"
#include "Dictionary.hpp"
#include "NodePath.hpp"
#include "Plane.hpp"
#include "PoolArrays.hpp"
#include "Quat.hpp"
#include "RID.hpp"
#include "Rect2.hpp"
#include "String.hpp"
#include "Transform.hpp"
#include "Transform2D.hpp"
#include "Variant.hpp"
#include "Vector2.hpp"
#include "Vector3.hpp"
#include "Wrapped.hpp"
#endif // CORETYPES_H

View File

@@ -1,270 +0,0 @@
#ifndef DEFS_H
#define DEFS_H
namespace godot {
enum class Error {
OK,
FAILED, ///< Generic fail error
ERR_UNAVAILABLE, ///< What is requested is unsupported/unavailable
ERR_UNCONFIGURED, ///< The object being used hasnt been properly set up yet
ERR_UNAUTHORIZED, ///< Missing credentials for requested resource
ERR_PARAMETER_RANGE_ERROR, ///< Parameter given out of range (5)
ERR_OUT_OF_MEMORY, ///< Out of memory
ERR_FILE_NOT_FOUND,
ERR_FILE_BAD_DRIVE,
ERR_FILE_BAD_PATH,
ERR_FILE_NO_PERMISSION, // (10)
ERR_FILE_ALREADY_IN_USE,
ERR_FILE_CANT_OPEN,
ERR_FILE_CANT_WRITE,
ERR_FILE_CANT_READ,
ERR_FILE_UNRECOGNIZED, // (15)
ERR_FILE_CORRUPT,
ERR_FILE_MISSING_DEPENDENCIES,
ERR_FILE_EOF,
ERR_CANT_OPEN, ///< Can't open a resource/socket/file
ERR_CANT_CREATE, // (20)
ERR_QUERY_FAILED,
ERR_ALREADY_IN_USE,
ERR_LOCKED, ///< resource is locked
ERR_TIMEOUT,
ERR_CANT_CONNECT, // (25)
ERR_CANT_RESOLVE,
ERR_CONNECTION_ERROR,
ERR_CANT_AQUIRE_RESOURCE,
ERR_CANT_FORK,
ERR_INVALID_DATA, ///< Data passed is invalid (30)
ERR_INVALID_PARAMETER, ///< Parameter passed is invalid
ERR_ALREADY_EXISTS, ///< When adding, item already exists
ERR_DOES_NOT_EXIST, ///< When retrieving/erasing, it item does not exist
ERR_DATABASE_CANT_READ, ///< database is full
ERR_DATABASE_CANT_WRITE, ///< database is full (35)
ERR_COMPILATION_FAILED,
ERR_METHOD_NOT_FOUND,
ERR_LINK_FAILED,
ERR_SCRIPT_FAILED,
ERR_CYCLIC_LINK, // (40)
ERR_INVALID_DECLARATION,
ERR_DUPLICATE_SYMBOL,
ERR_PARSE_ERROR,
ERR_BUSY,
ERR_SKIP, // (45)
ERR_HELP, ///< user requested help!!
ERR_BUG, ///< a bug in the software certainly happened, due to a double check failing or unexpected behavior.
ERR_PRINTER_ON_FIRE, /// the parallel port printer is engulfed in flames
ERR_OMFG_THIS_IS_VERY_VERY_BAD, ///< shit happens, has never been used, though
ERR_WTF = ERR_OMFG_THIS_IS_VERY_VERY_BAD ///< short version of the above
};
} // namespace godot
#include <GodotGlobal.hpp>
// alloca() is non-standard. When using MSVC, it's in malloc.h.
#if defined(__linux__) || defined(__APPLE__)
#include <alloca.h>
#else
#include <malloc.h>
#endif
typedef float real_t;
// This epsilon should match the one used by Godot for consistency.
// Using `f` when `real_t` is float.
#define CMP_EPSILON 0.00001f
#define CMP_EPSILON2 (CMP_EPSILON * CMP_EPSILON)
#define Math_PI 3.1415926535897932384626433833
#define Math_TAU 6.2831853071795864769252867666
#define _PLANE_EQ_DOT_EPSILON 0.999
#define _PLANE_EQ_D_EPSILON 0.0001
#ifdef __GNUC__
#define likely(x) __builtin_expect(!!(x), 1)
#define unlikely(x) __builtin_expect(!!(x), 0)
#else
#define likely(x) x
#define unlikely(x) x
#endif
// Don't use this directly; instead, use any of the CRASH_* macros
#ifdef _MSC_VER
#define GENERATE_TRAP \
__debugbreak(); \
/* Avoid warning about control paths */ \
for (;;) { \
}
#else
#define GENERATE_TRAP __builtin_trap();
#endif
// ERR/WARN macros
#ifndef WARN_PRINT
#define WARN_PRINT(msg) godot::Godot::print_warning(msg, __func__, __FILE__, __LINE__)
#endif
#ifndef WARN_PRINTS
#define WARN_PRINTS(msg) WARN_PRINT((msg).utf8().get_data())
#endif
#ifndef ERR_PRINT
#define ERR_PRINT(msg) godot::Godot::print_error(msg, __func__, __FILE__, __LINE__)
#endif
#ifndef ERR_PRINTS
#define ERR_PRINTS(msg) ERR_PRINT((msg).utf8().get_data())
#endif
#ifndef FATAL_PRINT
#define FATAL_PRINT(msg) ERR_PRINT(godot::String("FATAL: ") + (msg))
#endif
#ifndef ERR_MSG_INDEX
#define ERR_MSG_INDEX(index, size) (godot::String("Index ") + #index + "=" + godot::String::num_int64(index) + " out of size (" + #size + "=" + godot::String::num_int64(size) + ")")
#endif
#ifndef ERR_MSG_NULL
#define ERR_MSG_NULL(param) (godot::String("Parameter '") + #param + "' is null.")
#endif
#ifndef ERR_MSG_COND
#define ERR_MSG_COND(cond) (godot::String("Condition '") + #cond + "' is true.")
#endif
#ifndef ERR_FAIL_INDEX
#define ERR_FAIL_INDEX(index, size) \
do { \
if (unlikely((index) < 0 || (index) >= (size))) { \
ERR_PRINT(ERR_MSG_INDEX(index, size)); \
return; \
} \
} while (0)
#endif
#ifndef ERR_FAIL_INDEX_V
#define ERR_FAIL_INDEX_V(index, size, ret) \
do { \
if (unlikely((index) < 0 || (index) >= (size))) { \
ERR_PRINT(ERR_MSG_INDEX(index, size)); \
return ret; \
} \
} while (0)
#endif
#ifndef ERR_FAIL_UNSIGNED_INDEX_V
#define ERR_FAIL_UNSIGNED_INDEX_V(index, size, ret) \
do { \
if (unlikely((index) >= (size))) { \
ERR_PRINT(ERR_MSG_INDEX(index, size)); \
return ret; \
} \
} while (0)
#endif
#ifndef CRASH_BAD_INDEX
#define CRASH_BAD_INDEX(index, size) \
do { \
if (unlikely((index) < 0 || (index) >= (size))) { \
FATAL_PRINT(ERR_MSG_INDEX(index, size)); \
GENERATE_TRAP; \
} \
} while (0)
#endif
#ifndef ERR_FAIL_NULL
#define ERR_FAIL_NULL(param) \
do { \
if (unlikely(!param)) { \
ERR_PRINT(ERR_MSG_NULL(param)); \
return; \
} \
} while (0)
#endif
#ifndef ERR_FAIL_NULL_V
#define ERR_FAIL_NULL_V(param, ret) \
do { \
if (unlikely(!param)) { \
ERR_PRINT(ERR_MSG_NULL(param)); \
return ret; \
} \
} while (0)
#endif
#ifndef ERR_FAIL_COND
#define ERR_FAIL_COND(cond) \
do { \
if (unlikely(cond)) { \
ERR_PRINT(ERR_MSG_COND(cond)); \
return; \
} \
} while (0)
#endif
#ifndef CRASH_COND
#define CRASH_COND(cond) \
do { \
if (unlikely(cond)) { \
FATAL_PRINT(ERR_MSG_COND(cond)); \
return; \
} \
} while (0)
#endif
#ifndef ERR_FAIL_COND_V
#define ERR_FAIL_COND_V(cond, ret) \
do { \
if (unlikely(cond)) { \
ERR_PRINT(ERR_MSG_COND(cond)); \
return ret; \
} \
} while (0)
#endif
#ifndef ERR_CONTINUE
#define ERR_CONTINUE(cond) \
{ \
if (unlikely(cond)) { \
ERR_PRINT(ERR_MSG_COND(cond)); \
continue; \
} \
}
#endif
#ifndef ERR_BREAK
#define ERR_BREAK(cond) \
{ \
if (unlikely(cond)) { \
ERR_PRINT(ERR_MSG_COND(cond)); \
break; \
} \
}
#endif
#ifndef ERR_FAIL
#define ERR_FAIL() \
do { \
ERR_PRINT("Method/Function Failed."); \
return; \
} while (0)
#endif
#ifndef ERR_FAIL_V
#define ERR_FAIL_V(ret) \
do { \
ERR_PRINT("Method/Function Failed."); \
return ret; \
} while (0)
#endif
#ifndef CRASH_NOW
#define CRASH_NOW() \
do { \
FATAL_PRINT("Method/Function Failed."); \
GENERATE_TRAP; \
} while (0)
#endif
#endif // DEFS_H

View File

@@ -1,59 +0,0 @@
#ifndef DICTIONARY_H
#define DICTIONARY_H
#include "Variant.hpp"
#include "Array.hpp"
#include <gdnative/dictionary.h>
namespace godot {
class Dictionary {
godot_dictionary _godot_dictionary;
friend Variant::operator Dictionary() const;
inline explicit Dictionary(const godot_dictionary &other) {
_godot_dictionary = other;
}
public:
Dictionary();
Dictionary(const Dictionary &other);
Dictionary &operator=(const Dictionary &other);
template <class... Args>
static Dictionary make(Args... args) {
return helpers::add_all(Dictionary(), args...);
}
void clear();
bool empty() const;
void erase(const Variant &key);
bool has(const Variant &key) const;
bool has_all(const Array &keys) const;
uint32_t hash() const;
Array keys() const;
Variant &operator[](const Variant &key);
const Variant &operator[](const Variant &key) const;
int size() const;
String to_json() const;
Array values() const;
~Dictionary();
};
} // namespace godot
#endif // DICTIONARY_H

View File

@@ -1,580 +0,0 @@
#ifndef GODOT_HPP
#define GODOT_HPP
#include <cstdlib>
#include <cstring>
#include <gdnative_api_struct.gen.h>
#include <nativescript/godot_nativescript.h>
#include <typeinfo>
#include "CoreTypes.hpp"
#include "Ref.hpp"
#include "TagDB.hpp"
#include "Variant.hpp"
#include "Object.hpp"
#include "GodotGlobal.hpp"
namespace godot {
namespace detail {
// Godot classes are wrapped by heap-allocated instances mimicking them through the C API.
// They all inherit `_Wrapped`.
template <class T>
T *get_wrapper(godot_object *obj) {
return (T *)godot::nativescript_1_1_api->godot_nativescript_get_instance_binding_data(godot::_RegisterState::language_index, obj);
}
// Custom class instances are not obtainable by just casting the pointer to the base class they inherit,
// partly because in Godot, scripts are not instances of the classes themselves, they are only attached to them.
// Yet we want to "fake" it as if they were the same entity.
template <class T>
T *get_custom_class_instance(const Object *obj) {
return (obj) ? (T *)godot::nativescript_api->godot_nativescript_get_userdata(obj->_owner) : nullptr;
}
template <class T>
inline T *create_custom_class_instance() {
// Usually, script instances hold a reference to their NativeScript resource.
// that resource is obtained from a `.gdns` file, which in turn exists because
// of the resource system of Godot. We can't cleanly hardcode that here,
// so the easiest for now (though not really clean) is to create new resource instances,
// individually attached to the script instances.
// We cannot use wrappers because of https://github.com/godotengine/godot/issues/39181
// godot::NativeScript *script = godot::NativeScript::_new();
// script->set_library(get_wrapper<godot::GDNativeLibrary>((godot_object *)godot::gdnlib));
// script->set_class_name(T::___get_class_name());
static_assert(T::___CLASS_IS_SCRIPT, "This function must only be used on custom classes");
// So we use the C API directly.
static godot_class_constructor script_constructor = godot::api->godot_get_class_constructor("NativeScript");
static godot_method_bind *mb_set_library = godot::api->godot_method_bind_get_method("NativeScript", "set_library");
static godot_method_bind *mb_set_class_name = godot::api->godot_method_bind_get_method("NativeScript", "set_class_name");
godot_object *script = script_constructor();
{
const void *args[] = { godot::gdnlib };
godot::api->godot_method_bind_ptrcall(mb_set_library, script, args, nullptr);
}
{
const String class_name = T::___get_class_name();
const void *args[] = { &class_name };
godot::api->godot_method_bind_ptrcall(mb_set_class_name, script, args, nullptr);
}
// Now to instanciate T, we initially did this, however in case of Reference it returns a variant with refcount
// already initialized, which woud cause inconsistent behavior compared to other classes (we still have to return a pointer).
//Variant instance_variant = script->new_();
//T *instance = godot::get_custom_class_instance<T>(instance_variant);
// So we should do this instead, however while convenient, it uses unnecessary wrapper objects.
// Object *base_obj = T::___new_godot_base();
// base_obj->set_script(script);
// return get_custom_class_instance<T>(base_obj);
// Again using the C API to do exactly what we have to do.
static godot_class_constructor base_constructor = godot::api->godot_get_class_constructor(T::___get_godot_class_name());
static godot_method_bind *mb_set_script = godot::api->godot_method_bind_get_method("Object", "set_script");
godot_object *base_obj = base_constructor();
{
const void *args[] = { script };
godot::api->godot_method_bind_ptrcall(mb_set_script, base_obj, args, nullptr);
}
return (T *)godot::nativescript_api->godot_nativescript_get_userdata(base_obj);
}
} // namespace detail
// Used in the definition of a custom class.
//
// Name: Name of your class, without namespace
// Base: Name of the direct base class, with namespace if necessary
//
// ___get_class_name: Name of the class
// ___get_godot_class_name: Name of the Godot base class this class inherits from (i.e not direct)
// _new: Creates a new instance of the class
// ___get_id: Gets the unique ID of the class. Godot and custom classes are both within that set.
// ___get_base_id: Gets the ID of the direct base class, as returned by ___get_id
// ___get_base_class_name: Name of the direct base class
// ___get_from_variant: Converts a Variant into an Object*. Will be non-null if the class matches.
#define GODOT_CLASS(Name, Base) \
\
public: \
inline static const char *___get_class_name() { return #Name; } \
enum { ___CLASS_IS_SCRIPT = 1 }; \
inline static const char *___get_godot_class_name() { \
return Base::___get_godot_class_name(); \
} \
inline static Name *_new() { \
return godot::detail::create_custom_class_instance<Name>(); \
} \
inline static size_t ___get_id() { return typeid(Name).hash_code(); } \
inline static size_t ___get_base_id() { return Base::___get_id(); } \
inline static const char *___get_base_class_name() { return Base::___get_class_name(); } \
inline static godot::Object *___get_from_variant(godot::Variant a) { \
return (godot::Object *)godot::detail::get_custom_class_instance<Name>( \
godot::Object::___get_from_variant(a)); \
} \
\
private:
// Legacy compatibility
#define GODOT_SUBCLASS(Name, Base) GODOT_CLASS(Name, Base)
template <class T>
struct _ArgCast {
static T _arg_cast(Variant a) {
return a;
}
};
template <class T>
struct _ArgCast<T *> {
static T *_arg_cast(Variant a) {
return (T *)T::___get_from_variant(a);
}
};
template <>
struct _ArgCast<Variant> {
static Variant _arg_cast(Variant a) {
return a;
}
};
// instance and destroy funcs
template <class T>
void *_godot_class_instance_func(godot_object *p, void * /*method_data*/) {
T *d = new T();
d->_owner = p;
d->_type_tag = typeid(T).hash_code();
d->_init();
return d;
}
template <class T>
void _godot_class_destroy_func(godot_object * /*p*/, void * /*method_data*/, void *data) {
T *d = (T *)data;
delete d;
}
template <class T>
void register_class() {
static_assert(T::___CLASS_IS_SCRIPT, "This function must only be used on custom classes");
godot_instance_create_func create = {};
create.create_func = _godot_class_instance_func<T>;
godot_instance_destroy_func destroy = {};
destroy.destroy_func = _godot_class_destroy_func<T>;
_TagDB::register_type(T::___get_id(), T::___get_base_id());
godot::nativescript_api->godot_nativescript_register_class(godot::_RegisterState::nativescript_handle,
T::___get_class_name(), T::___get_base_class_name(), create, destroy);
godot::nativescript_1_1_api->godot_nativescript_set_type_tag(godot::_RegisterState::nativescript_handle,
T::___get_class_name(), (const void *)T::___get_id());
T::_register_methods();
}
template <class T>
void register_tool_class() {
static_assert(T::___CLASS_IS_SCRIPT, "This function must only be used on custom classes");
godot_instance_create_func create = {};
create.create_func = _godot_class_instance_func<T>;
godot_instance_destroy_func destroy = {};
destroy.destroy_func = _godot_class_destroy_func<T>;
_TagDB::register_type(T::___get_id(), T::___get_base_id());
godot::nativescript_api->godot_nativescript_register_tool_class(godot::_RegisterState::nativescript_handle,
T::___get_class_name(), T::___get_base_class_name(), create, destroy);
godot::nativescript_1_1_api->godot_nativescript_set_type_tag(godot::_RegisterState::nativescript_handle,
T::___get_class_name(), (const void *)T::___get_id());
T::_register_methods();
}
// method registering
typedef godot_variant (*__godot_wrapper_method)(godot_object *, void *, void *, int, godot_variant **);
template <class T, class R, class... args>
const char *___get_method_class_name(R (T::*p)(args... a)) {
static_assert(T::___CLASS_IS_SCRIPT, "This function must only be used on custom classes");
(void)p; // To avoid "unused parameter" warnings. `p` is required for template matching.
return T::___get_class_name();
}
// This second version is also required to match constant functions
template <class T, class R, class... args>
const char *___get_method_class_name(R (T::*p)(args... a) const) {
static_assert(T::___CLASS_IS_SCRIPT, "This function must only be used on custom classes");
(void)p; // To avoid "unused parameter" warnings. `p` is required for template matching.
return T::___get_class_name();
}
// Okay, time for some template magic.
// Many thanks to manpat from the GDL Discord Server.
// This is stuff that's available in C++14 I think, but whatever.
template <int... I>
struct __Sequence {};
template <int N, int... I>
struct __construct_sequence {
using type = typename __construct_sequence<N - 1, N - 1, I...>::type;
};
template <int... I>
struct __construct_sequence<0, I...> {
using type = __Sequence<I...>;
};
// Now the wrapping part.
template <class T, class R, class... As>
struct _WrappedMethod {
R(T::*f)
(As...);
template <int... I>
void apply(Variant *ret, T *obj, Variant **args, __Sequence<I...>) {
*ret = (obj->*f)(_ArgCast<As>::_arg_cast(*args[I])...);
}
};
template <class T, class... As>
struct _WrappedMethod<T, void, As...> {
void (T::*f)(As...);
template <int... I>
void apply(Variant * /*ret*/, T *obj, Variant **args, __Sequence<I...>) {
(obj->*f)(_ArgCast<As>::_arg_cast(*args[I])...);
}
};
template <class T, class R, class... As>
godot_variant __wrapped_method(godot_object *, void *method_data, void *user_data, int /*num_args*/, godot_variant **args) {
godot_variant v;
godot::api->godot_variant_new_nil(&v);
T *obj = (T *)user_data;
_WrappedMethod<T, R, As...> *method = (_WrappedMethod<T, R, As...> *)method_data;
Variant *var = (Variant *)&v;
Variant **arg = (Variant **)args;
method->apply(var, obj, arg, typename __construct_sequence<sizeof...(As)>::type{});
return v;
}
template <class T, class R, class... As>
void *___make_wrapper_function(R (T::*f)(As...)) {
using MethodType = _WrappedMethod<T, R, As...>;
MethodType *p = (MethodType *)godot::api->godot_alloc(sizeof(MethodType));
p->f = f;
return (void *)p;
}
template <class T, class R, class... As>
__godot_wrapper_method ___get_wrapper_function(R (T::* /*f*/)(As...)) {
return (__godot_wrapper_method)&__wrapped_method<T, R, As...>;
}
template <class T, class R, class... A>
void *___make_wrapper_function(R (T::*f)(A...) const) {
return ___make_wrapper_function((R(T::*)(A...))f);
}
template <class T, class R, class... A>
__godot_wrapper_method ___get_wrapper_function(R (T::*f)(A...) const) {
return ___get_wrapper_function((R(T::*)(A...))f);
}
template <class M>
void register_method(const char *name, M method_ptr, godot_method_rpc_mode rpc_type = GODOT_METHOD_RPC_MODE_DISABLED) {
godot_instance_method method = {};
method.method_data = ___make_wrapper_function(method_ptr);
method.free_func = godot::api->godot_free;
method.method = (__godot_wrapper_method)___get_wrapper_function(method_ptr);
godot_method_attributes attr = {};
attr.rpc_type = rpc_type;
godot::nativescript_api->godot_nativescript_register_method(godot::_RegisterState::nativescript_handle,
___get_method_class_name(method_ptr), name, attr, method);
}
// User can specify a derived class D to register the method for, instead of it being inferred.
template <class D, class B, class R, class... As>
void register_method_explicit(const char *name, R (B::*method_ptr)(As...),
godot_method_rpc_mode rpc_type = GODOT_METHOD_RPC_MODE_DISABLED) {
static_assert(std::is_base_of<B, D>::value, "Explicit class must derive from method class");
register_method(name, static_cast<R (D::*)(As...)>(method_ptr), rpc_type);
}
template <class T, class P>
struct _PropertySetFunc {
void (T::*f)(P);
static void _wrapped_setter(godot_object * /*object*/, void *method_data, void *user_data, godot_variant *value) {
_PropertySetFunc<T, P> *set_func = (_PropertySetFunc<T, P> *)method_data;
T *obj = (T *)user_data;
Variant *v = (Variant *)value;
(obj->*(set_func->f))(_ArgCast<P>::_arg_cast(*v));
}
};
template <class T, class P>
struct _PropertyGetFunc {
P(T::*f)
();
static godot_variant _wrapped_getter(godot_object * /*object*/, void *method_data, void *user_data) {
_PropertyGetFunc<T, P> *get_func = (_PropertyGetFunc<T, P> *)method_data;
T *obj = (T *)user_data;
godot_variant var;
godot::api->godot_variant_new_nil(&var);
Variant *v = (Variant *)&var;
*v = (obj->*(get_func->f))();
return var;
}
};
template <class T, class P>
struct _PropertyDefaultSetFunc {
P(T::*f);
static void _wrapped_setter(godot_object * /*object*/, void *method_data, void *user_data, godot_variant *value) {
_PropertyDefaultSetFunc<T, P> *set_func = (_PropertyDefaultSetFunc<T, P> *)method_data;
T *obj = (T *)user_data;
Variant *v = (Variant *)value;
(obj->*(set_func->f)) = _ArgCast<P>::_arg_cast(*v);
}
};
template <class T, class P>
struct _PropertyDefaultGetFunc {
P(T::*f);
static godot_variant _wrapped_getter(godot_object * /*object*/, void *method_data, void *user_data) {
_PropertyDefaultGetFunc<T, P> *get_func = (_PropertyDefaultGetFunc<T, P> *)method_data;
T *obj = (T *)user_data;
godot_variant var;
godot::api->godot_variant_new_nil(&var);
Variant *v = (Variant *)&var;
*v = (obj->*(get_func->f));
return var;
}
};
template <class T, class P>
void register_property(const char *name, P(T::*var), P default_value,
godot_method_rpc_mode rpc_mode = GODOT_METHOD_RPC_MODE_DISABLED,
godot_property_usage_flags usage = GODOT_PROPERTY_USAGE_DEFAULT,
godot_property_hint hint = GODOT_PROPERTY_HINT_NONE, String hint_string = "") {
static_assert(T::___CLASS_IS_SCRIPT, "This function must only be used on custom classes");
Variant def_val = default_value;
usage = (godot_property_usage_flags)((int)usage | GODOT_PROPERTY_USAGE_SCRIPT_VARIABLE);
if (def_val.get_type() == Variant::OBJECT) {
Object *o = detail::get_wrapper<Object>(def_val.operator godot_object *());
if (o && o->is_class("Resource")) {
hint = (godot_property_hint)((int)hint | GODOT_PROPERTY_HINT_RESOURCE_TYPE);
hint_string = o->get_class();
}
}
godot_string *_hint_string = (godot_string *)&hint_string;
godot_property_attributes attr = {};
if (def_val.get_type() == Variant::NIL) {
attr.type = Variant::OBJECT;
} else {
attr.type = def_val.get_type();
attr.default_value = *(godot_variant *)&def_val;
}
attr.hint = hint;
attr.rset_type = rpc_mode;
attr.usage = usage;
attr.hint_string = *_hint_string;
_PropertyDefaultSetFunc<T, P> *wrapped_set =
(_PropertyDefaultSetFunc<T, P> *)godot::api->godot_alloc(sizeof(_PropertyDefaultSetFunc<T, P>));
wrapped_set->f = var;
_PropertyDefaultGetFunc<T, P> *wrapped_get =
(_PropertyDefaultGetFunc<T, P> *)godot::api->godot_alloc(sizeof(_PropertyDefaultGetFunc<T, P>));
wrapped_get->f = var;
godot_property_set_func set_func = {};
set_func.method_data = (void *)wrapped_set;
set_func.free_func = godot::api->godot_free;
set_func.set_func = &_PropertyDefaultSetFunc<T, P>::_wrapped_setter;
godot_property_get_func get_func = {};
get_func.method_data = (void *)wrapped_get;
get_func.free_func = godot::api->godot_free;
get_func.get_func = &_PropertyDefaultGetFunc<T, P>::_wrapped_getter;
godot::nativescript_api->godot_nativescript_register_property(godot::_RegisterState::nativescript_handle,
T::___get_class_name(), name, &attr, set_func, get_func);
}
template <class T, class P>
void register_property(const char *name, void (T::*setter)(P), P (T::*getter)(), P default_value,
godot_method_rpc_mode rpc_mode = GODOT_METHOD_RPC_MODE_DISABLED,
godot_property_usage_flags usage = GODOT_PROPERTY_USAGE_DEFAULT,
godot_property_hint hint = GODOT_PROPERTY_HINT_NONE, String hint_string = "") {
static_assert(T::___CLASS_IS_SCRIPT, "This function must only be used on custom classes");
Variant def_val = default_value;
godot_string *_hint_string = (godot_string *)&hint_string;
godot_property_attributes attr = {};
if (def_val.get_type() == Variant::NIL) {
attr.type = Variant::OBJECT;
} else {
attr.type = def_val.get_type();
attr.default_value = *(godot_variant *)&def_val;
}
attr.hint = hint;
attr.rset_type = rpc_mode;
attr.usage = usage;
attr.hint_string = *_hint_string;
_PropertySetFunc<T, P> *wrapped_set = (_PropertySetFunc<T, P> *)godot::api->godot_alloc(sizeof(_PropertySetFunc<T, P>));
wrapped_set->f = setter;
_PropertyGetFunc<T, P> *wrapped_get = (_PropertyGetFunc<T, P> *)godot::api->godot_alloc(sizeof(_PropertyGetFunc<T, P>));
wrapped_get->f = getter;
godot_property_set_func set_func = {};
set_func.method_data = (void *)wrapped_set;
set_func.free_func = godot::api->godot_free;
set_func.set_func = &_PropertySetFunc<T, P>::_wrapped_setter;
godot_property_get_func get_func = {};
get_func.method_data = (void *)wrapped_get;
get_func.free_func = godot::api->godot_free;
get_func.get_func = &_PropertyGetFunc<T, P>::_wrapped_getter;
godot::nativescript_api->godot_nativescript_register_property(godot::_RegisterState::nativescript_handle,
T::___get_class_name(), name, &attr, set_func, get_func);
}
template <class T, class P>
void register_property(const char *name, void (T::*setter)(P), P (T::*getter)() const, P default_value,
godot_method_rpc_mode rpc_mode = GODOT_METHOD_RPC_MODE_DISABLED,
godot_property_usage_flags usage = GODOT_PROPERTY_USAGE_DEFAULT,
godot_property_hint hint = GODOT_PROPERTY_HINT_NONE, String hint_string = "") {
register_property(name, setter, (P(T::*)())getter, default_value, rpc_mode, usage, hint, hint_string);
}
template <class T>
void register_signal(String name, Dictionary args = Dictionary()) {
static_assert(T::___CLASS_IS_SCRIPT, "This function must only be used on custom classes");
godot_signal signal = {};
signal.name = *(godot_string *)&name;
signal.num_args = args.size();
signal.num_default_args = 0;
// Need to check because malloc(0) is platform-dependent. Zero arguments will leave args to nullptr.
if (signal.num_args != 0) {
signal.args = (godot_signal_argument *)godot::api->godot_alloc(sizeof(godot_signal_argument) * signal.num_args);
memset((void *)signal.args, 0, sizeof(godot_signal_argument) * signal.num_args);
}
for (int i = 0; i < signal.num_args; i++) {
// Array entry = args[i];
// String name = entry[0];
String name = args.keys()[i];
godot_string *_key = (godot_string *)&name;
godot::api->godot_string_new_copy(&signal.args[i].name, _key);
// if (entry.size() > 1) {
// signal.args[i].type = entry[1];
// }
signal.args[i].type = args.values()[i];
}
godot::nativescript_api->godot_nativescript_register_signal(godot::_RegisterState::nativescript_handle,
T::___get_class_name(), &signal);
for (int i = 0; i < signal.num_args; i++) {
godot::api->godot_string_destroy(&signal.args[i].name);
}
if (signal.args) {
godot::api->godot_free(signal.args);
}
}
template <class T, class... Args>
void register_signal(String name, Args... varargs) {
register_signal<T>(name, Dictionary::make(varargs...));
}
#ifndef GODOT_CPP_NO_OBJECT_CAST
template <class T>
T *Object::cast_to(const Object *obj) {
if (!obj)
return nullptr;
if (T::___CLASS_IS_SCRIPT) {
size_t have_tag = (size_t)godot::nativescript_1_1_api->godot_nativescript_get_type_tag(obj->_owner);
if (have_tag) {
if (!godot::_TagDB::is_type_known((size_t)have_tag)) {
have_tag = 0;
}
}
if (!have_tag) {
have_tag = obj->_type_tag;
}
if (godot::_TagDB::is_type_compatible(T::___get_id(), have_tag)) {
return detail::get_custom_class_instance<T>(obj);
}
} else {
if (godot::core_1_2_api->godot_object_cast_to(obj->_owner, (void *)T::___get_id())) {
return (T *)obj;
}
}
return nullptr;
}
#endif
} // namespace godot
#endif // GODOT_HPP

View File

@@ -1,52 +0,0 @@
#ifndef GODOT_GLOBAL_HPP
#define GODOT_GLOBAL_HPP
#include "Array.hpp"
#include "String.hpp"
#include <gdnative_api_struct.gen.h>
namespace godot {
extern "C" const godot_gdnative_core_api_struct *api;
extern "C" const godot_gdnative_core_1_1_api_struct *core_1_1_api;
extern "C" const godot_gdnative_core_1_2_api_struct *core_1_2_api;
extern "C" const godot_gdnative_ext_nativescript_api_struct *nativescript_api;
extern "C" const godot_gdnative_ext_nativescript_1_1_api_struct *nativescript_1_1_api;
extern "C" const godot_gdnative_ext_pluginscript_api_struct *pluginscript_api;
extern "C" const godot_gdnative_ext_android_api_struct *android_api;
extern "C" const godot_gdnative_ext_arvr_api_struct *arvr_api;
extern "C" const godot_gdnative_ext_videodecoder_api_struct *videodecoder_api;
extern "C" const godot_gdnative_ext_net_api_struct *net_api;
extern "C" const godot_gdnative_ext_net_3_2_api_struct *net_3_2_api;
extern "C" const void *gdnlib;
class Godot {
public:
static void print(const String &message);
static void print_warning(const String &description, const String &function, const String &file, int line);
static void print_error(const String &description, const String &function, const String &file, int line);
static void gdnative_init(godot_gdnative_init_options *o);
static void gdnative_terminate(godot_gdnative_terminate_options *o);
static void nativescript_init(void *handle);
static void nativescript_terminate(void *handle);
static void gdnative_profiling_add_data(const char *p_signature, uint64_t p_time);
template <class... Args>
static void print(const String &fmt, Args... values) {
print(fmt.format(Array::make(values...)));
}
};
struct _RegisterState {
static void *nativescript_handle;
static int language_index;
};
} // namespace godot
#endif

View File

@@ -1,33 +0,0 @@
#ifndef GODOT_PROFILING_HPP
#define GODOT_PROFILING_HPP
#include "OS.hpp"
namespace godot {
class FunctionProfiling {
char signature[1024];
uint64_t ticks;
public:
FunctionProfiling(const char *p_function, const int p_line) {
snprintf(signature, 1024, "::%d::%s", p_line, p_function);
ticks = OS::get_singleton()->get_ticks_usec();
}
~FunctionProfiling() {
uint64_t t = OS::get_singleton()->get_ticks_usec() - ticks;
if (t > 0) {
Godot::gdnative_profiling_add_data(signature, t);
}
}
};
} // namespace godot
#ifdef DEBUG_ENABLED
#define GODOT_PROFILING_FUNCTION FunctionProfiling __function_profiling(__FUNCTION__, __LINE__);
#else
#define GODOT_PROFILING_FUNCTION
#endif
#endif

View File

@@ -1,252 +0,0 @@
#ifndef GODOT_MATH_H
#define GODOT_MATH_H
#include "Defs.hpp"
#include <cmath>
namespace godot {
namespace Math {
// Functions reproduced as in Godot's source code `math_funcs.h`.
// Some are overloads to automatically support changing real_t into either double or float in the way Godot does.
inline double fmod(double p_x, double p_y) {
return ::fmod(p_x, p_y);
}
inline float fmod(float p_x, float p_y) {
return ::fmodf(p_x, p_y);
}
inline double floor(double p_x) {
return ::floor(p_x);
}
inline float floor(float p_x) {
return ::floorf(p_x);
}
inline double exp(double p_x) {
return ::exp(p_x);
}
inline float exp(float p_x) {
return ::expf(p_x);
}
inline double sin(double p_x) {
return ::sin(p_x);
}
inline float sin(float p_x) {
return ::sinf(p_x);
}
inline double cos(double p_x) {
return ::cos(p_x);
}
inline float cos(float p_x) {
return ::cosf(p_x);
}
inline double tan(double p_x) {
return ::tan(p_x);
}
inline float tan(float p_x) {
return ::tanf(p_x);
}
inline double atan2(double p_y, double p_x) {
return ::atan2(p_y, p_x);
}
inline float atan2(float p_y, float p_x) {
return ::atan2f(p_y, p_x);
}
inline double sqrt(double p_x) {
return ::sqrt(p_x);
}
inline float sqrt(float p_x) {
return ::sqrtf(p_x);
}
inline float lerp(float minv, float maxv, float t) {
return minv + t * (maxv - minv);
}
inline double lerp(double minv, double maxv, double t) {
return minv + t * (maxv - minv);
}
inline double lerp_angle(double p_from, double p_to, double p_weight) {
double difference = fmod(p_to - p_from, Math_TAU);
double distance = fmod(2.0 * difference, Math_TAU) - difference;
return p_from + distance * p_weight;
}
inline float lerp_angle(float p_from, float p_to, float p_weight) {
float difference = fmod(p_to - p_from, (float)Math_TAU);
float distance = fmod(2.0f * difference, (float)Math_TAU) - difference;
return p_from + distance * p_weight;
}
template <typename T>
inline T clamp(T x, T minv, T maxv) {
if (x < minv) {
return minv;
}
if (x > maxv) {
return maxv;
}
return x;
}
template <typename T>
inline T min(T a, T b) {
return a < b ? a : b;
}
template <typename T>
inline T max(T a, T b) {
return a > b ? a : b;
}
template <typename T>
inline T sign(T x) {
return static_cast<T>(x < 0 ? -1 : 1);
}
inline double deg2rad(double p_y) {
return p_y * Math_PI / 180.0;
}
inline float deg2rad(float p_y) {
return p_y * static_cast<float>(Math_PI) / 180.f;
}
inline double rad2deg(double p_y) {
return p_y * 180.0 / Math_PI;
}
inline float rad2deg(float p_y) {
return p_y * 180.f / static_cast<float>(Math_PI);
}
inline double inverse_lerp(double p_from, double p_to, double p_value) {
return (p_value - p_from) / (p_to - p_from);
}
inline float inverse_lerp(float p_from, float p_to, float p_value) {
return (p_value - p_from) / (p_to - p_from);
}
inline double range_lerp(double p_value, double p_istart, double p_istop, double p_ostart, double p_ostop) {
return Math::lerp(p_ostart, p_ostop, Math::inverse_lerp(p_istart, p_istop, p_value));
}
inline float range_lerp(float p_value, float p_istart, float p_istop, float p_ostart, float p_ostop) {
return Math::lerp(p_ostart, p_ostop, Math::inverse_lerp(p_istart, p_istop, p_value));
}
inline bool is_equal_approx(real_t a, real_t b) {
// Check for exact equality first, required to handle "infinity" values.
if (a == b) {
return true;
}
// Then check for approximate equality.
real_t tolerance = CMP_EPSILON * std::abs(a);
if (tolerance < CMP_EPSILON) {
tolerance = CMP_EPSILON;
}
return std::abs(a - b) < tolerance;
}
inline bool is_equal_approx(real_t a, real_t b, real_t tolerance) {
// Check for exact equality first, required to handle "infinity" values.
if (a == b) {
return true;
}
// Then check for approximate equality.
return std::abs(a - b) < tolerance;
}
inline bool is_zero_approx(real_t s) {
return std::abs(s) < CMP_EPSILON;
}
inline double smoothstep(double p_from, double p_to, double p_weight) {
if (is_equal_approx(static_cast<real_t>(p_from), static_cast<real_t>(p_to))) {
return p_from;
}
double x = clamp((p_weight - p_from) / (p_to - p_from), 0.0, 1.0);
return x * x * (3.0 - 2.0 * x);
}
inline float smoothstep(float p_from, float p_to, float p_weight) {
if (is_equal_approx(p_from, p_to)) {
return p_from;
}
float x = clamp((p_weight - p_from) / (p_to - p_from), 0.0f, 1.0f);
return x * x * (3.0f - 2.0f * x);
}
inline double move_toward(double p_from, double p_to, double p_delta) {
return std::abs(p_to - p_from) <= p_delta ? p_to : p_from + sign(p_to - p_from) * p_delta;
}
inline float move_toward(float p_from, float p_to, float p_delta) {
return std::abs(p_to - p_from) <= p_delta ? p_to : p_from + sign(p_to - p_from) * p_delta;
}
inline double linear2db(double p_linear) {
return log(p_linear) * 8.6858896380650365530225783783321;
}
inline float linear2db(float p_linear) {
return log(p_linear) * 8.6858896380650365530225783783321f;
}
inline double db2linear(double p_db) {
return exp(p_db * 0.11512925464970228420089957273422);
}
inline float db2linear(float p_db) {
return exp(p_db * 0.11512925464970228420089957273422f);
}
inline double round(double p_val) {
return (p_val >= 0) ? floor(p_val + 0.5) : -floor(-p_val + 0.5);
}
inline float round(float p_val) {
return (p_val >= 0) ? floor(p_val + 0.5f) : -floor(-p_val + 0.5f);
}
inline int64_t wrapi(int64_t value, int64_t min, int64_t max) {
int64_t range = max - min;
return range == 0 ? min : min + ((((value - min) % range) + range) % range);
}
inline float wrapf(real_t value, real_t min, real_t max) {
const real_t range = max - min;
return is_zero_approx(range) ? min : value - (range * floor((value - min) / range));
}
inline float stepify(float p_value, float p_step) {
if (p_step != 0) {
p_value = floor(p_value / p_step + 0.5f) * p_step;
}
return p_value;
}
inline double stepify(double p_value, double p_step) {
if (p_step != 0) {
p_value = floor(p_value / p_step + 0.5) * p_step;
}
return p_value;
}
inline unsigned int next_power_of_2(unsigned int x) {
if (x == 0)
return 0;
--x;
x |= x >> 1;
x |= x >> 2;
x |= x >> 4;
x |= x >> 8;
x |= x >> 16;
return ++x;
}
} // namespace Math
} // namespace godot
#endif // GODOT_MATH_H

View File

@@ -1,54 +0,0 @@
#ifndef NODEPATH_H
#define NODEPATH_H
#include "String.hpp"
#include <gdnative/node_path.h>
namespace godot {
class NodePath {
godot_node_path _node_path;
friend class Variant;
inline explicit NodePath(godot_node_path node_path) {
_node_path = node_path;
}
public:
NodePath();
NodePath(const NodePath &other);
NodePath(const String &from);
NodePath(const char *contents);
String get_name(const int idx) const;
int get_name_count() const;
String get_subname(const int idx) const;
int get_subname_count() const;
bool is_absolute() const;
bool is_empty() const;
NodePath get_as_property_path() const;
String get_concatenated_subnames() const;
operator String() const;
void operator=(const NodePath &other);
bool operator==(const NodePath &other);
~NodePath();
};
} // namespace godot
#endif // NODEPATH_H

View File

@@ -1,68 +0,0 @@
#ifndef PLANE_H
#define PLANE_H
#include "Vector3.hpp"
#include <cmath>
namespace godot {
enum ClockDirection {
CLOCKWISE,
COUNTERCLOCKWISE
};
class Plane {
public:
Vector3 normal;
real_t d;
void set_normal(const Vector3 &p_normal);
inline Vector3 get_normal() const { return normal; } ///Point is coplanar, CMP_EPSILON for precision
void normalize();
Plane normalized() const;
/* Plane-Point operations */
inline Vector3 center() const { return normal * d; }
Vector3 get_any_point() const;
Vector3 get_any_perpendicular_normal() const;
bool is_point_over(const Vector3 &p_point) const; ///< Point is over plane
real_t distance_to(const Vector3 &p_point) const;
bool has_point(const Vector3 &p_point, real_t _epsilon = CMP_EPSILON) const;
/* intersections */
bool intersect_3(const Plane &p_plane1, const Plane &p_plane2, Vector3 *r_result = 0) const;
bool intersects_ray(Vector3 p_from, Vector3 p_dir, Vector3 *p_intersection) const;
bool intersects_segment(Vector3 p_begin, Vector3 p_end, Vector3 *p_intersection) const;
Vector3 project(const Vector3 &p_point) const;
/* misc */
inline Plane operator-() const { return Plane(-normal, -d); }
bool is_almost_like(const Plane &p_plane) const;
bool operator==(const Plane &p_plane) const;
bool operator!=(const Plane &p_plane) const;
operator String() const;
inline Plane() { d = 0; }
inline Plane(real_t p_a, real_t p_b, real_t p_c, real_t p_d) :
normal(p_a, p_b, p_c),
d(p_d) {}
Plane(const Vector3 &p_normal, real_t p_d);
Plane(const Vector3 &p_point, const Vector3 &p_normal);
Plane(const Vector3 &p_point1, const Vector3 &p_point2, const Vector3 &p_point3, ClockDirection p_dir = CLOCKWISE);
};
} // namespace godot
#endif // PLANE_H

View File

@@ -1,737 +0,0 @@
#ifndef POOLARRAYS_H
#define POOLARRAYS_H
#include "Defs.hpp"
#include "Color.hpp"
#include "GodotGlobal.hpp"
#include "String.hpp"
#include "Vector2.hpp"
#include "Vector3.hpp"
#include <gdnative/pool_arrays.h>
namespace godot {
class Array;
class PoolByteArray {
godot_pool_byte_array _godot_array;
friend class String;
friend class Variant;
inline explicit PoolByteArray(godot_pool_byte_array a) {
_godot_array = a;
}
public:
class Read {
friend class PoolByteArray;
godot_pool_byte_array_read_access *_read_access;
public:
inline Read() {
_read_access = nullptr;
}
inline Read(const Read &p_other) {
_read_access = godot::api->godot_pool_byte_array_read_access_copy(p_other._read_access);
}
inline ~Read() {
godot::api->godot_pool_byte_array_read_access_destroy(_read_access);
}
inline const uint8_t *ptr() const {
return godot::api->godot_pool_byte_array_read_access_ptr(_read_access);
}
inline const uint8_t &operator[](int p_idx) const {
return ptr()[p_idx];
}
inline void operator=(const Read &p_other) {
godot::api->godot_pool_byte_array_read_access_operator_assign(_read_access, p_other._read_access);
}
};
class Write {
friend class PoolByteArray;
godot_pool_byte_array_write_access *_write_access;
public:
inline Write() {
_write_access = nullptr;
}
inline Write(const Write &p_other) {
_write_access = godot::api->godot_pool_byte_array_write_access_copy(p_other._write_access);
}
inline ~Write() {
godot::api->godot_pool_byte_array_write_access_destroy(_write_access);
}
inline uint8_t *ptr() const {
return godot::api->godot_pool_byte_array_write_access_ptr(_write_access);
}
inline uint8_t &operator[](int p_idx) const {
return ptr()[p_idx];
}
inline void operator=(const Write &p_other) {
godot::api->godot_pool_byte_array_write_access_operator_assign(_write_access, p_other._write_access);
}
};
PoolByteArray();
PoolByteArray(const PoolByteArray &p_other);
PoolByteArray &operator=(const PoolByteArray &p_other);
PoolByteArray(const Array &array);
Read read() const;
Write write();
void append(const uint8_t data);
void append_array(const PoolByteArray &array);
int insert(const int idx, const uint8_t data);
void invert();
void push_back(const uint8_t data);
void remove(const int idx);
void resize(const int size);
void set(const int idx, const uint8_t data);
uint8_t operator[](const int idx);
int size() const;
~PoolByteArray();
};
class PoolIntArray {
godot_pool_int_array _godot_array;
friend class Variant;
explicit inline PoolIntArray(godot_pool_int_array a) {
_godot_array = a;
}
public:
class Read {
friend class PoolIntArray;
godot_pool_int_array_read_access *_read_access;
public:
inline Read() {
_read_access = nullptr;
}
inline Read(const Read &p_other) {
_read_access = godot::api->godot_pool_int_array_read_access_copy(p_other._read_access);
}
inline ~Read() {
godot::api->godot_pool_int_array_read_access_destroy(_read_access);
}
inline const int *ptr() const {
return godot::api->godot_pool_int_array_read_access_ptr(_read_access);
}
inline const int &operator[](int p_idx) const {
return ptr()[p_idx];
}
inline void operator=(const Read &p_other) {
godot::api->godot_pool_int_array_read_access_operator_assign(_read_access, p_other._read_access);
}
};
class Write {
friend class PoolIntArray;
godot_pool_int_array_write_access *_write_access;
public:
inline Write() {
_write_access = nullptr;
}
inline Write(const Write &p_other) {
_write_access = godot::api->godot_pool_int_array_write_access_copy(p_other._write_access);
}
inline ~Write() {
godot::api->godot_pool_int_array_write_access_destroy(_write_access);
}
inline int *ptr() const {
return godot::api->godot_pool_int_array_write_access_ptr(_write_access);
}
inline int &operator[](int p_idx) const {
return ptr()[p_idx];
}
inline void operator=(const Write &p_other) {
godot::api->godot_pool_int_array_write_access_operator_assign(_write_access, p_other._write_access);
}
};
PoolIntArray();
PoolIntArray(const PoolIntArray &p_other);
PoolIntArray &operator=(const PoolIntArray &p_other);
PoolIntArray(const Array &array);
Read read() const;
Write write();
void append(const int data);
void append_array(const PoolIntArray &array);
int insert(const int idx, const int data);
void invert();
void push_back(const int data);
void remove(const int idx);
void resize(const int size);
void set(const int idx, const int data);
int operator[](const int idx);
int size() const;
~PoolIntArray();
};
class PoolRealArray {
godot_pool_real_array _godot_array;
friend class Variant;
explicit inline PoolRealArray(godot_pool_real_array a) {
_godot_array = a;
}
public:
class Read {
friend class PoolRealArray;
godot_pool_real_array_read_access *_read_access;
public:
inline Read() {
_read_access = nullptr;
}
inline Read(const Read &p_other) {
_read_access = godot::api->godot_pool_real_array_read_access_copy(p_other._read_access);
}
inline ~Read() {
godot::api->godot_pool_real_array_read_access_destroy(_read_access);
}
inline const real_t *ptr() const {
return godot::api->godot_pool_real_array_read_access_ptr(_read_access);
}
inline const real_t &operator[](int p_idx) const {
return ptr()[p_idx];
}
inline void operator=(const Read &p_other) {
godot::api->godot_pool_real_array_read_access_operator_assign(_read_access, p_other._read_access);
}
};
class Write {
friend class PoolRealArray;
godot_pool_real_array_write_access *_write_access;
public:
inline Write() {
_write_access = nullptr;
}
inline Write(const Write &p_other) {
_write_access = godot::api->godot_pool_real_array_write_access_copy(p_other._write_access);
}
inline ~Write() {
godot::api->godot_pool_real_array_write_access_destroy(_write_access);
}
inline real_t *ptr() const {
return godot::api->godot_pool_real_array_write_access_ptr(_write_access);
}
inline real_t &operator[](int p_idx) const {
return ptr()[p_idx];
}
inline void operator=(const Write &p_other) {
godot::api->godot_pool_real_array_write_access_operator_assign(_write_access, p_other._write_access);
}
};
PoolRealArray();
PoolRealArray(const PoolRealArray &p_other);
PoolRealArray &operator=(const PoolRealArray &p_other);
PoolRealArray(const Array &array);
Read read() const;
Write write();
void append(const real_t data);
void append_array(const PoolRealArray &array);
int insert(const int idx, const real_t data);
void invert();
void push_back(const real_t data);
void remove(const int idx);
void resize(const int size);
void set(const int idx, const real_t data);
real_t operator[](const int idx);
int size() const;
~PoolRealArray();
};
class PoolStringArray {
godot_pool_string_array _godot_array;
friend class String;
friend class Variant;
explicit inline PoolStringArray(godot_pool_string_array a) {
_godot_array = a;
}
public:
class Read {
friend class PoolStringArray;
godot_pool_string_array_read_access *_read_access;
public:
inline Read() {
_read_access = nullptr;
}
inline Read(const Read &p_other) {
_read_access = godot::api->godot_pool_string_array_read_access_copy(p_other._read_access);
}
inline ~Read() {
godot::api->godot_pool_string_array_read_access_destroy(_read_access);
}
inline const String *ptr() const {
return (const String *)godot::api->godot_pool_string_array_read_access_ptr(_read_access);
}
inline const String &operator[](int p_idx) const {
return ptr()[p_idx];
}
inline void operator=(const Read &p_other) {
godot::api->godot_pool_string_array_read_access_operator_assign(_read_access, p_other._read_access);
}
};
class Write {
friend class PoolStringArray;
godot_pool_string_array_write_access *_write_access;
public:
inline Write() {
_write_access = nullptr;
}
inline Write(const Write &p_other) {
_write_access = godot::api->godot_pool_string_array_write_access_copy(p_other._write_access);
}
inline ~Write() {
godot::api->godot_pool_string_array_write_access_destroy(_write_access);
}
inline String *ptr() const {
return (String *)godot::api->godot_pool_string_array_write_access_ptr(_write_access);
}
inline String &operator[](int p_idx) const {
return ptr()[p_idx];
}
inline void operator=(const Write &p_other) {
godot::api->godot_pool_string_array_write_access_operator_assign(_write_access, p_other._write_access);
}
};
PoolStringArray();
PoolStringArray(const PoolStringArray &p_other);
PoolStringArray &operator=(const PoolStringArray &p_other);
PoolStringArray(const Array &array);
Read read() const;
Write write();
void append(const String &data);
void append_array(const PoolStringArray &array);
int insert(const int idx, const String &data);
void invert();
void push_back(const String &data);
void remove(const int idx);
void resize(const int size);
void set(const int idx, const String &data);
const String operator[](const int idx);
int size() const;
~PoolStringArray();
};
class PoolVector2Array {
godot_pool_vector2_array _godot_array;
friend class Variant;
explicit inline PoolVector2Array(godot_pool_vector2_array a) {
_godot_array = a;
}
public:
class Read {
friend class PoolVector2Array;
godot_pool_vector2_array_read_access *_read_access;
public:
inline Read() {
_read_access = nullptr;
}
inline Read(const Read &p_other) {
_read_access = godot::api->godot_pool_vector2_array_read_access_copy(p_other._read_access);
}
inline ~Read() {
godot::api->godot_pool_vector2_array_read_access_destroy(_read_access);
}
inline const Vector2 *ptr() const {
return (const Vector2 *)godot::api->godot_pool_vector2_array_read_access_ptr(_read_access);
}
inline const Vector2 &operator[](int p_idx) const {
return ptr()[p_idx];
}
inline void operator=(const Read &p_other) {
godot::api->godot_pool_vector2_array_read_access_operator_assign(_read_access, p_other._read_access);
}
};
class Write {
friend class PoolVector2Array;
godot_pool_vector2_array_write_access *_write_access;
public:
inline Write() {
_write_access = nullptr;
}
inline Write(const Write &p_other) {
_write_access = godot::api->godot_pool_vector2_array_write_access_copy(p_other._write_access);
}
inline ~Write() {
godot::api->godot_pool_vector2_array_write_access_destroy(_write_access);
}
inline Vector2 *ptr() const {
return (Vector2 *)godot::api->godot_pool_vector2_array_write_access_ptr(_write_access);
}
inline Vector2 &operator[](int p_idx) const {
return ptr()[p_idx];
}
inline void operator=(const Write &p_other) {
godot::api->godot_pool_vector2_array_write_access_operator_assign(_write_access, p_other._write_access);
}
};
PoolVector2Array();
PoolVector2Array(const PoolVector2Array &p_other);
PoolVector2Array &operator=(const PoolVector2Array &p_other);
PoolVector2Array(const Array &array);
Read read() const;
Write write();
void append(const Vector2 &data);
void append_array(const PoolVector2Array &array);
int insert(const int idx, const Vector2 &data);
void invert();
void push_back(const Vector2 &data);
void remove(const int idx);
void resize(const int size);
void set(const int idx, const Vector2 &data);
const Vector2 operator[](const int idx);
int size() const;
~PoolVector2Array();
};
class PoolVector3Array {
godot_pool_vector3_array _godot_array;
friend class Variant;
explicit inline PoolVector3Array(godot_pool_vector3_array a) {
_godot_array = a;
}
public:
class Read {
friend class PoolVector3Array;
godot_pool_vector3_array_read_access *_read_access;
public:
inline Read() {
_read_access = nullptr;
}
inline Read(const Read &p_other) {
_read_access = godot::api->godot_pool_vector3_array_read_access_copy(p_other._read_access);
}
inline ~Read() {
godot::api->godot_pool_vector3_array_read_access_destroy(_read_access);
}
inline const Vector3 *ptr() const {
return (const Vector3 *)godot::api->godot_pool_vector3_array_read_access_ptr(_read_access);
}
inline const Vector3 &operator[](int p_idx) const {
return ptr()[p_idx];
}
inline void operator=(const Read &p_other) {
godot::api->godot_pool_vector3_array_read_access_operator_assign(_read_access, p_other._read_access);
}
};
class Write {
friend class PoolVector3Array;
godot_pool_vector3_array_write_access *_write_access;
public:
inline Write() {
_write_access = nullptr;
}
inline Write(const Write &p_other) {
_write_access = godot::api->godot_pool_vector3_array_write_access_copy(p_other._write_access);
}
inline ~Write() {
godot::api->godot_pool_vector3_array_write_access_destroy(_write_access);
}
inline Vector3 *ptr() const {
return (Vector3 *)godot::api->godot_pool_vector3_array_write_access_ptr(_write_access);
}
inline Vector3 &operator[](int p_idx) const {
return ptr()[p_idx];
}
inline void operator=(const Write &p_other) {
godot::api->godot_pool_vector3_array_write_access_operator_assign(_write_access, p_other._write_access);
}
};
PoolVector3Array();
PoolVector3Array(const PoolVector3Array &p_other);
PoolVector3Array &operator=(const PoolVector3Array &p_other);
PoolVector3Array(const Array &array);
Read read() const;
Write write();
void append(const Vector3 &data);
void append_array(const PoolVector3Array &array);
int insert(const int idx, const Vector3 &data);
void invert();
void push_back(const Vector3 &data);
void remove(const int idx);
void resize(const int size);
void set(const int idx, const Vector3 &data);
const Vector3 operator[](const int idx);
int size() const;
~PoolVector3Array();
};
class PoolColorArray {
godot_pool_color_array _godot_array;
friend class Variant;
explicit inline PoolColorArray(godot_pool_color_array a) {
_godot_array = a;
}
public:
class Read {
friend class PoolColorArray;
godot_pool_color_array_read_access *_read_access;
public:
inline Read() {
_read_access = nullptr;
}
inline Read(const Read &p_other) {
_read_access = godot::api->godot_pool_color_array_read_access_copy(p_other._read_access);
}
inline ~Read() {
godot::api->godot_pool_color_array_read_access_destroy(_read_access);
}
inline const Color *ptr() const {
return (const Color *)godot::api->godot_pool_color_array_read_access_ptr(_read_access);
}
inline const Color &operator[](int p_idx) const {
return ptr()[p_idx];
}
inline void operator=(const Read &p_other) {
godot::api->godot_pool_color_array_read_access_operator_assign(_read_access, p_other._read_access);
}
};
class Write {
friend class PoolColorArray;
godot_pool_color_array_write_access *_write_access;
public:
inline Write() {
_write_access = nullptr;
}
inline Write(const Write &p_other) {
_write_access = godot::api->godot_pool_color_array_write_access_copy(p_other._write_access);
}
inline ~Write() {
godot::api->godot_pool_color_array_write_access_destroy(_write_access);
}
inline Color *ptr() const {
return (Color *)godot::api->godot_pool_color_array_write_access_ptr(_write_access);
}
inline Color &operator[](int p_idx) const {
return ptr()[p_idx];
}
inline void operator=(const Write &p_other) {
godot::api->godot_pool_color_array_write_access_operator_assign(_write_access, p_other._write_access);
}
};
PoolColorArray();
PoolColorArray(const PoolColorArray &p_other);
PoolColorArray &operator=(const PoolColorArray &p_other);
PoolColorArray(const Array &array);
Read read() const;
Write write();
void append(const Color &data);
void append_array(const PoolColorArray &array);
int insert(const int idx, const Color &data);
void invert();
void push_back(const Color &data);
void remove(const int idx);
void resize(const int size);
void set(const int idx, const Color &data);
const Color operator[](const int idx);
int size() const;
~PoolColorArray();
};
} // namespace godot
#endif // POOLARRAYS_H

View File

@@ -1,95 +0,0 @@
#ifndef QUAT_H
#define QUAT_H
#include <cmath>
#include "Vector3.hpp"
// #include "Basis.h"
namespace godot {
class Quat {
public:
static const Quat IDENTITY;
real_t x, y, z, w;
real_t length_squared() const;
real_t length() const;
void normalize();
Quat normalized() const;
bool is_normalized() const;
Quat inverse() const;
void set_euler_xyz(const Vector3 &p_euler);
Vector3 get_euler_xyz() const;
void set_euler_yxz(const Vector3 &p_euler);
Vector3 get_euler_yxz() const;
inline void set_euler(const Vector3 &p_euler) { set_euler_yxz(p_euler); }
inline Vector3 get_euler() const { return get_euler_yxz(); }
real_t dot(const Quat &q) const;
Quat slerp(const Quat &q, const real_t &t) const;
Quat slerpni(const Quat &q, const real_t &t) const;
Quat cubic_slerp(const Quat &q, const Quat &prep, const Quat &postq, const real_t &t) const;
void get_axis_and_angle(Vector3 &r_axis, real_t &r_angle) const;
void set_axis_angle(const Vector3 &axis, const float angle);
void operator*=(const Quat &q);
Quat operator*(const Quat &q) const;
Quat operator*(const Vector3 &v) const;
Vector3 xform(const Vector3 &v) const;
void operator+=(const Quat &q);
void operator-=(const Quat &q);
void operator*=(const real_t &s);
void operator/=(const real_t &s);
Quat operator+(const Quat &q2) const;
Quat operator-(const Quat &q2) const;
Quat operator-() const;
Quat operator*(const real_t &s) const;
Quat operator/(const real_t &s) const;
bool operator==(const Quat &p_quat) const;
bool operator!=(const Quat &p_quat) const;
operator String() const;
inline void set(real_t p_x, real_t p_y, real_t p_z, real_t p_w) {
x = p_x;
y = p_y;
z = p_z;
w = p_w;
}
inline Quat(real_t p_x, real_t p_y, real_t p_z, real_t p_w) {
x = p_x;
y = p_y;
z = p_z;
w = p_w;
}
Quat(const Vector3 &axis, const real_t &angle);
Quat(const Vector3 &v0, const Vector3 &v1);
inline Quat() {
x = y = z = 0;
w = 1;
}
};
} // namespace godot
#endif // QUAT_H

View File

@@ -1,37 +0,0 @@
#ifndef RID_H
#define RID_H
#include <gdnative/rid.h>
namespace godot {
class Object;
class RID {
godot_rid _godot_rid;
public:
RID();
RID(Object *p);
godot_rid _get_godot_rid() const;
int32_t get_id() const;
inline bool is_valid() const {
// is_valid() is not available in the C API...
return *this != RID();
}
bool operator==(const RID &p_other) const;
bool operator!=(const RID &p_other) const;
bool operator<(const RID &p_other) const;
bool operator>(const RID &p_other) const;
bool operator<=(const RID &p_other) const;
bool operator>=(const RID &p_other) const;
};
} // namespace godot
#endif // RID_H

View File

@@ -1,135 +0,0 @@
#ifndef RECT2_H
#define RECT2_H
#include "Vector2.hpp"
#include <cmath>
#include <cstdlib>
namespace godot {
class String;
typedef Vector2 Size2;
typedef Vector2 Point2;
struct Transform2D;
struct Rect2 {
Point2 position;
Size2 size;
inline const Vector2 &get_position() const { return position; }
inline void set_position(const Vector2 &p_position) { position = p_position; }
inline const Vector2 &get_size() const { return size; }
inline void set_size(const Vector2 &p_size) { size = p_size; }
inline real_t get_area() const { return size.width * size.height; }
inline bool intersects(const Rect2 &p_rect) const {
if (position.x >= (p_rect.position.x + p_rect.size.width))
return false;
if ((position.x + size.width) <= p_rect.position.x)
return false;
if (position.y >= (p_rect.position.y + p_rect.size.height))
return false;
if ((position.y + size.height) <= p_rect.position.y)
return false;
return true;
}
real_t distance_to(const Vector2 &p_point) const;
bool intersects_transformed(const Transform2D &p_xform, const Rect2 &p_rect) const;
bool intersects_segment(const Point2 &p_from, const Point2 &p_to, Point2 *r_position = nullptr, Point2 *r_normal = nullptr) const;
inline bool encloses(const Rect2 &p_rect) const {
return (p_rect.position.x >= position.x) && (p_rect.position.y >= position.y) &&
((p_rect.position.x + p_rect.size.x) < (position.x + size.x)) &&
((p_rect.position.y + p_rect.size.y) < (position.y + size.y));
}
inline bool has_no_area() const {
return (size.x <= 0 || size.y <= 0);
}
Rect2 clip(const Rect2 &p_rect) const;
Rect2 merge(const Rect2 &p_rect) const;
inline bool has_point(const Point2 &p_point) const {
if (p_point.x < position.x)
return false;
if (p_point.y < position.y)
return false;
if (p_point.x >= (position.x + size.x))
return false;
if (p_point.y >= (position.y + size.y))
return false;
return true;
}
inline bool no_area() const { return (size.width <= 0 || size.height <= 0); }
inline bool operator==(const Rect2 &p_rect) const { return position == p_rect.position && size == p_rect.size; }
inline bool operator!=(const Rect2 &p_rect) const { return position != p_rect.position || size != p_rect.size; }
inline Rect2 grow(real_t p_by) const {
Rect2 g = *this;
g.position.x -= p_by;
g.position.y -= p_by;
g.size.width += p_by * 2;
g.size.height += p_by * 2;
return g;
}
inline Rect2 expand(const Vector2 &p_vector) const {
Rect2 r = *this;
r.expand_to(p_vector);
return r;
}
inline void expand_to(const Vector2 &p_vector) { //in place function for speed
Vector2 begin = position;
Vector2 end = position + size;
if (p_vector.x < begin.x)
begin.x = p_vector.x;
if (p_vector.y < begin.y)
begin.y = p_vector.y;
if (p_vector.x > end.x)
end.x = p_vector.x;
if (p_vector.y > end.y)
end.y = p_vector.y;
position = begin;
size = end - begin;
}
operator String() const;
inline Rect2() {}
inline Rect2(real_t p_x, real_t p_y, real_t p_width, real_t p_height) {
position = Point2(p_x, p_y);
size = Size2(p_width, p_height);
}
inline Rect2(const Point2 &p_position, const Size2 &p_size) {
position = p_position;
size = p_size;
}
};
} // namespace godot
#endif // RECT2_H

View File

@@ -1,204 +0,0 @@
#ifndef REF_H
#define REF_H
#include "GodotGlobal.hpp"
#include "Reference.hpp"
#include "Variant.hpp"
namespace godot {
// Replicates Godot's Ref<T> behavior
// Rewritten from f5234e70be7dec4930c2d5a0e829ff480d044b1d.
template <class T>
class Ref {
// TODO For this nice check to work, each class must actually #include Reference classes mentionned in its methods,
// which might be annoying for coders who prefer to forward-declare to reduce compile times
// static_assert(std::is_base_of<Reference, T>::value,
// "Ref<T> can only be used with classes deriving from Reference");
T *reference = nullptr;
void ref(const Ref &p_from) {
if (p_from.reference == reference)
return;
unref();
reference = p_from.reference;
if (reference)
reference->reference();
}
void ref_pointer(T *p_ref) {
ERR_FAIL_COND(p_ref == nullptr);
if (p_ref->init_ref())
reference = p_ref;
}
public:
inline bool operator<(const Ref<T> &p_r) const {
return reference < p_r.reference;
}
inline bool operator==(const Ref<T> &p_r) const {
return reference == p_r.reference;
}
inline bool operator!=(const Ref<T> &p_r) const {
return reference != p_r.reference;
}
inline T *operator->() {
return reference;
}
inline T *operator*() {
return reference;
}
inline const T *operator->() const {
return reference;
}
inline const T *ptr() const {
return reference;
}
inline T *ptr() {
return reference;
}
inline const T *operator*() const {
return reference;
}
operator Variant() const {
// Note: the C API handles the cases where the object is a Reference,
// so the Variant will be correctly constructed with a RefPtr engine-side
return Variant((Object *)reference);
}
void operator=(const Ref &p_from) {
ref(p_from);
}
template <class T_Other>
void operator=(const Ref<T_Other> &p_from) {
Reference *refb = const_cast<Reference *>(static_cast<const Reference *>(p_from.ptr()));
if (refb == nullptr) {
unref();
return;
}
Ref r;
r.reference = Object::cast_to<T>(refb);
ref(r);
r.reference = nullptr;
}
void operator=(const Variant &p_variant) {
Object *refb = T::___get_from_variant(p_variant);
if (refb == nullptr) {
unref();
return;
}
Ref r;
r.reference = Object::cast_to<T>(refb);
ref(r);
r.reference = nullptr;
}
Ref(const Ref &p_from) {
reference = nullptr;
ref(p_from);
}
template <class T_Other>
Ref(const Ref<T_Other> &p_from) {
reference = nullptr;
Reference *refb = const_cast<Reference *>(static_cast<const Reference *>(p_from.ptr()));
if (refb == nullptr) {
unref();
return;
}
Ref r;
r.reference = Object::cast_to<T>(refb);
ref(r);
r.reference = nullptr;
}
Ref(T *p_reference) {
if (p_reference)
ref_pointer(p_reference);
else
reference = nullptr;
}
Ref(const Variant &p_variant) {
reference = nullptr;
Object *refb = T::___get_from_variant(p_variant);
if (refb == nullptr) {
unref();
return;
}
Ref r;
r.reference = Object::cast_to<T>(refb);
ref(r);
r.reference = nullptr;
}
inline bool is_valid() const { return reference != nullptr; }
inline bool is_null() const { return reference == nullptr; }
void unref() {
//TODO this should be moved to mutexes, since this engine does not really
// do a lot of referencing on references and stuff
// mutexes will avoid more crashes?
if (reference && reference->unreference()) {
//memdelete(reference);
reference->free();
}
reference = nullptr;
}
void instance() {
//ref(memnew(T));
ref(T::_new());
}
Ref() {
reference = nullptr;
}
~Ref() {
unref();
}
// Used exclusively in the bindings to recreate the Ref Godot encapsulates in return values,
// without adding to the refcount.
inline static Ref<T> __internal_constructor(Object *obj) {
Ref<T> r;
r.reference = (T *)obj;
return r;
}
};
} // namespace godot
#endif

View File

@@ -1,153 +0,0 @@
#ifndef STRING_H
#define STRING_H
#include <gdnative/string.h>
namespace godot {
class NodePath;
class Variant;
class PoolByteArray;
class PoolIntArray;
class PoolRealArray;
class PoolStringArray;
class String;
class CharString {
friend class String;
godot_char_string _char_string;
public:
~CharString();
int length() const;
const char *get_data() const;
};
class String {
godot_string _godot_string;
friend class Dictionary;
friend class NodePath;
friend class Variant;
explicit inline String(godot_string contents) :
_godot_string(contents) {}
public:
String();
String(const char *contents);
String(const wchar_t *contents);
String(const wchar_t c);
String(const String &other);
~String();
static String num(double p_num, int p_decimals = -1);
static String num_scientific(double p_num);
static String num_real(double p_num);
static String num_int64(int64_t p_num, int base = 10, bool capitalize_hex = false);
static String chr(godot_char_type p_char);
static String md5(const uint8_t *p_md5);
static String hex_encode_buffer(const uint8_t *p_buffer, int p_len);
wchar_t &operator[](const int idx);
wchar_t operator[](const int idx) const;
void operator=(const String &s);
bool operator==(const String &s) const;
bool operator!=(const String &s) const;
String operator+(const String &s) const;
void operator+=(const String &s);
void operator+=(const wchar_t c);
bool operator<(const String &s) const;
bool operator<=(const String &s) const;
bool operator>(const String &s) const;
bool operator>=(const String &s) const;
operator NodePath() const;
int length() const;
const wchar_t *unicode_str() const;
char *alloc_c_string() const;
CharString utf8() const;
CharString ascii(bool p_extended = false) const;
bool begins_with(String &s) const;
bool begins_with_char_array(const char *p_char_array) const;
PoolStringArray bigrams() const;
String c_escape() const;
String c_unescape() const;
String capitalize() const;
bool empty() const;
bool ends_with(String &text) const;
void erase(int position, int chars);
int find(String what, int from = 0) const;
int find_last(String what) const;
int findn(String what, int from = 0) const;
String format(Variant values) const;
String format(Variant values, String placeholder) const;
String get_base_dir() const;
String get_basename() const;
String get_extension() const;
String get_file() const;
int hash() const;
int hex_to_int() const;
String insert(int position, String what) const;
bool is_abs_path() const;
bool is_rel_path() const;
bool is_subsequence_of(String text) const;
bool is_subsequence_ofi(String text) const;
bool is_valid_float() const;
bool is_valid_html_color() const;
bool is_valid_identifier() const;
bool is_valid_integer() const;
bool is_valid_ip_address() const;
String json_escape() const;
String left(int position) const;
bool match(String expr) const;
bool matchn(String expr) const;
PoolByteArray md5_buffer() const;
String md5_text() const;
int ord_at(int at) const;
String pad_decimals(int digits) const;
String pad_zeros(int digits) const;
String percent_decode() const;
String percent_encode() const;
String plus_file(String file) const;
String replace(String what, String forwhat) const;
String replacen(String what, String forwhat) const;
int rfind(String what, int from = -1) const;
int rfindn(String what, int from = -1) const;
String right(int position) const;
PoolByteArray sha256_buffer() const;
String sha256_text() const;
float similarity(String text) const;
PoolStringArray split(String divisor, bool allow_empty = true) const;
PoolIntArray split_ints(String divisor, bool allow_empty = true) const;
PoolRealArray split_floats(String divisor, bool allow_empty = true) const;
String strip_edges(bool left = true, bool right = true) const;
String substr(int from, int len) const;
float to_float() const;
int64_t to_int() const;
String to_lower() const;
String to_upper() const;
String xml_escape() const;
String xml_unescape() const;
signed char casecmp_to(String p_str) const;
signed char nocasecmp_to(String p_str) const;
signed char naturalnocasecmp_to(String p_str) const;
String dedent() const;
PoolStringArray rsplit(const String &divisor, const bool allow_empty = true, const int maxsplit = 0) const;
String rstrip(const String &chars) const;
String trim_prefix(const String &prefix) const;
String trim_suffix(const String &suffix) const;
};
String operator+(const char *a, const String &b);
String operator+(const wchar_t *a, const String &b);
} // namespace godot
#endif // STRING_H

View File

@@ -1,19 +0,0 @@
#ifndef TAGDB_HPP
#define TAGDB_HPP
#include <stddef.h>
namespace godot {
namespace _TagDB {
void register_type(size_t type_tag, size_t base_type_tag);
bool is_type_known(size_t type_tag);
void register_global_type(const char *name, size_t type_tag, size_t base_type_tag);
bool is_type_compatible(size_t type_tag, size_t base_type_tag);
} // namespace _TagDB
} // namespace godot
#endif // TAGDB_HPP

View File

@@ -1,91 +0,0 @@
#ifndef TRANSFORM_H
#define TRANSFORM_H
#include "Basis.hpp"
#include "AABB.hpp"
#include "Plane.hpp"
namespace godot {
class Transform {
public:
static const Transform IDENTITY;
static const Transform FLIP_X;
static const Transform FLIP_Y;
static const Transform FLIP_Z;
Basis basis;
Vector3 origin;
void invert();
Transform inverse() const;
void affine_invert();
Transform affine_inverse() const;
Transform rotated(const Vector3 &p_axis, real_t p_phi) const;
void rotate(const Vector3 &p_axis, real_t p_phi);
void rotate_basis(const Vector3 &p_axis, real_t p_phi);
void set_look_at(const Vector3 &p_eye, const Vector3 &p_target, const Vector3 &p_up);
Transform looking_at(const Vector3 &p_target, const Vector3 &p_up) const;
void scale(const Vector3 &p_scale);
Transform scaled(const Vector3 &p_scale) const;
void scale_basis(const Vector3 &p_scale);
void translate(real_t p_tx, real_t p_ty, real_t p_tz);
void translate(const Vector3 &p_translation);
Transform translated(const Vector3 &p_translation) const;
inline const Basis &get_basis() const { return basis; }
inline void set_basis(const Basis &p_basis) { basis = p_basis; }
inline const Vector3 &get_origin() const { return origin; }
inline void set_origin(const Vector3 &p_origin) { origin = p_origin; }
void orthonormalize();
Transform orthonormalized() const;
bool operator==(const Transform &p_transform) const;
bool operator!=(const Transform &p_transform) const;
Vector3 xform(const Vector3 &p_vector) const;
Vector3 xform_inv(const Vector3 &p_vector) const;
Plane xform(const Plane &p_plane) const;
Plane xform_inv(const Plane &p_plane) const;
AABB xform(const AABB &p_aabb) const;
AABB xform_inv(const AABB &p_aabb) const;
void operator*=(const Transform &p_transform);
Transform operator*(const Transform &p_transform) const;
inline Vector3 operator*(const Vector3 &p_vector) const {
return Vector3(
basis.elements[0].dot(p_vector) + origin.x,
basis.elements[1].dot(p_vector) + origin.y,
basis.elements[2].dot(p_vector) + origin.z);
}
Transform interpolate_with(const Transform &p_transform, real_t p_c) const;
Transform inverse_xform(const Transform &t) const;
void set(real_t xx, real_t xy, real_t xz, real_t yx, real_t yy, real_t yz, real_t zx, real_t zy, real_t zz, real_t tx, real_t ty, real_t tz);
operator String() const;
inline Transform(real_t xx, real_t xy, real_t xz, real_t yx, real_t yy, real_t yz, real_t zx, real_t zy, real_t zz, real_t tx, real_t ty, real_t tz) {
set(xx, xy, xz, yx, yy, yz, zx, zy, zz, tx, ty, tz);
}
Transform(const Basis &p_basis, const Vector3 &p_origin = Vector3());
inline Transform() {}
};
} // namespace godot
#endif // TRANSFORM_H

View File

@@ -1,106 +0,0 @@
#ifndef TRANSFORM2D_H
#define TRANSFORM2D_H
#include "Vector2.hpp"
namespace godot {
typedef Vector2 Size2;
struct Rect2;
struct Transform2D {
static const Transform2D IDENTITY;
static const Transform2D FLIP_X;
static const Transform2D FLIP_Y;
// Warning #1: basis of Transform2D is stored differently from Basis. In terms of elements array, the basis matrix looks like "on paper":
// M = (elements[0][0] elements[1][0])
// (elements[0][1] elements[1][1])
// This is such that the columns, which can be interpreted as basis vectors of the coordinate system "painted" on the object, can be accessed as elements[i].
// Note that this is the opposite of the indices in mathematical texts, meaning: $M_{12}$ in a math book corresponds to elements[1][0] here.
// This requires additional care when working with explicit indices.
// See https://en.wikipedia.org/wiki/Row-_and_column-major_order for further reading.
// Warning #2: 2D be aware that unlike 3D code, 2D code uses a left-handed coordinate system: Y-axis points down,
// and angle is measure from +X to +Y in a clockwise-fashion.
Vector2 elements[3];
inline real_t tdotx(const Vector2 &v) const { return elements[0][0] * v.x + elements[1][0] * v.y; }
inline real_t tdoty(const Vector2 &v) const { return elements[0][1] * v.x + elements[1][1] * v.y; }
inline const Vector2 &operator[](int p_idx) const { return elements[p_idx]; }
inline Vector2 &operator[](int p_idx) { return elements[p_idx]; }
inline Vector2 get_axis(int p_axis) const {
ERR_FAIL_INDEX_V(p_axis, 3, Vector2());
return elements[p_axis];
}
inline void set_axis(int p_axis, const Vector2 &p_vec) {
ERR_FAIL_INDEX(p_axis, 3);
elements[p_axis] = p_vec;
}
void invert();
Transform2D inverse() const;
void affine_invert();
Transform2D affine_inverse() const;
void set_rotation(real_t p_phi);
real_t get_rotation() const;
void set_rotation_and_scale(real_t p_phi, const Size2 &p_scale);
void rotate(real_t p_phi);
void scale(const Size2 &p_scale);
void scale_basis(const Size2 &p_scale);
void translate(real_t p_tx, real_t p_ty);
void translate(const Vector2 &p_translation);
real_t basis_determinant() const;
Size2 get_scale() const;
inline const Vector2 &get_origin() const { return elements[2]; }
inline void set_origin(const Vector2 &p_origin) { elements[2] = p_origin; }
Transform2D scaled(const Size2 &p_scale) const;
Transform2D basis_scaled(const Size2 &p_scale) const;
Transform2D translated(const Vector2 &p_offset) const;
Transform2D rotated(real_t p_phi) const;
Transform2D untranslated() const;
void orthonormalize();
Transform2D orthonormalized() const;
bool operator==(const Transform2D &p_transform) const;
bool operator!=(const Transform2D &p_transform) const;
void operator*=(const Transform2D &p_transform);
Transform2D operator*(const Transform2D &p_transform) const;
Transform2D interpolate_with(const Transform2D &p_transform, real_t p_c) const;
Vector2 basis_xform(const Vector2 &p_vec) const;
Vector2 basis_xform_inv(const Vector2 &p_vec) const;
Vector2 xform(const Vector2 &p_vec) const;
Vector2 xform_inv(const Vector2 &p_vec) const;
Rect2 xform(const Rect2 &p_vec) const;
Rect2 xform_inv(const Rect2 &p_vec) const;
operator String() const;
Transform2D(real_t xx, real_t xy, real_t yx, real_t yy, real_t ox, real_t oy);
Transform2D(real_t p_rot, const Vector2 &p_pos);
inline Transform2D() {
elements[0][0] = 1.0;
elements[1][1] = 1.0;
}
};
} // namespace godot
#endif // TRANSFORM2D_H

View File

@@ -1,276 +0,0 @@
#ifndef VARIANT_H
#define VARIANT_H
#include <gdnative/variant.h>
#include "Defs.hpp"
#include "AABB.hpp"
#include "Basis.hpp"
#include "Color.hpp"
#include "NodePath.hpp"
#include "Plane.hpp"
#include "PoolArrays.hpp"
#include "Quat.hpp"
#include "RID.hpp"
#include "Rect2.hpp"
#include "String.hpp"
#include "Transform.hpp"
#include "Transform2D.hpp"
#include "Vector2.hpp"
#include "Vector3.hpp"
#include <iostream>
namespace godot {
class Dictionary;
class Array;
class Variant {
godot_variant _godot_variant;
friend class Array;
inline explicit Variant(godot_variant v) {
_godot_variant = v;
}
public:
enum Type {
NIL,
// atomic types
BOOL,
INT,
REAL,
STRING,
// math types
VECTOR2, // 5
RECT2,
VECTOR3,
TRANSFORM2D,
PLANE,
QUAT, // 10
RECT3, //sorry naming convention fail :( not like it's used often
BASIS,
TRANSFORM,
// misc types
COLOR,
NODE_PATH, // 15
_RID,
OBJECT,
DICTIONARY,
ARRAY,
// arrays
POOL_BYTE_ARRAY, // 20
POOL_INT_ARRAY,
POOL_REAL_ARRAY,
POOL_STRING_ARRAY,
POOL_VECTOR2_ARRAY,
POOL_VECTOR3_ARRAY, // 25
POOL_COLOR_ARRAY,
VARIANT_MAX
};
enum Operator {
//comparation
OP_EQUAL,
OP_NOT_EQUAL,
OP_LESS,
OP_LESS_EQUAL,
OP_GREATER,
OP_GREATER_EQUAL,
//mathematic
OP_ADD,
OP_SUBSTRACT,
OP_MULTIPLY,
OP_DIVIDE,
OP_NEGATE,
OP_POSITIVE,
OP_MODULE,
OP_STRING_CONCAT,
//bitwise
OP_SHIFT_LEFT,
OP_SHIFT_RIGHT,
OP_BIT_AND,
OP_BIT_OR,
OP_BIT_XOR,
OP_BIT_NEGATE,
//logic
OP_AND,
OP_OR,
OP_XOR,
OP_NOT,
//containment
OP_IN,
OP_MAX
};
Variant();
Variant(const Variant &v);
Variant(bool p_bool);
Variant(signed int p_int);
Variant(unsigned int p_int);
Variant(signed short p_short);
inline Variant(unsigned short p_short) :
Variant((unsigned int)p_short) {}
inline Variant(signed char p_char) :
Variant((signed int)p_char) {}
inline Variant(unsigned char p_char) :
Variant((unsigned int)p_char) {}
Variant(int64_t p_char);
Variant(uint64_t p_char);
Variant(float p_float);
Variant(double p_double);
Variant(const String &p_string);
Variant(const char *const p_cstring);
Variant(const wchar_t *p_wstring);
Variant(const Vector2 &p_vector2);
Variant(const Rect2 &p_rect2);
Variant(const Vector3 &p_vector3);
Variant(const Plane &p_plane);
Variant(const AABB &p_aabb);
Variant(const Quat &p_quat);
Variant(const Basis &p_transform);
Variant(const Transform2D &p_transform);
Variant(const Transform &p_transform);
Variant(const Color &p_color);
Variant(const NodePath &p_path);
Variant(const RID &p_rid);
Variant(const Object *p_object);
Variant(const Dictionary &p_dictionary);
Variant(const Array &p_array);
Variant(const PoolByteArray &p_raw_array);
Variant(const PoolIntArray &p_int_array);
Variant(const PoolRealArray &p_real_array);
Variant(const PoolStringArray &p_string_array);
Variant(const PoolVector2Array &p_vector2_array);
Variant(const PoolVector3Array &p_vector3_array);
Variant(const PoolColorArray &p_color_array);
Variant &operator=(const Variant &v);
operator bool() const;
operator signed int() const;
operator unsigned int() const;
operator signed short() const;
operator unsigned short() const;
operator signed char() const;
operator unsigned char() const;
operator int64_t() const;
operator uint64_t() const;
operator wchar_t() const;
operator float() const;
operator double() const;
operator String() const;
operator Vector2() const;
operator Rect2() const;
operator Vector3() const;
operator Plane() const;
operator AABB() const;
operator Quat() const;
operator Basis() const;
operator Transform() const;
operator Transform2D() const;
operator Color() const;
operator NodePath() const;
operator RID() const;
operator godot_object *() const;
template <typename T>
operator T *() const { return static_cast<T *>(T::___get_from_variant(*this)); }
operator Dictionary() const;
operator Array() const;
operator PoolByteArray() const;
operator PoolIntArray() const;
operator PoolRealArray() const;
operator PoolStringArray() const;
operator PoolVector2Array() const;
operator PoolVector3Array() const;
operator PoolColorArray() const;
Type get_type() const;
Variant call(const String &method, const Variant **args, const int arg_count);
bool has_method(const String &method);
bool operator==(const Variant &b) const;
bool operator!=(const Variant &b) const;
bool operator<(const Variant &b) const;
bool operator<=(const Variant &b) const;
bool operator>(const Variant &b) const;
bool operator>=(const Variant &b) const;
bool hash_compare(const Variant &b) const;
bool booleanize() const;
~Variant();
};
} // namespace godot
#endif // VARIANT_H

View File

@@ -1,276 +0,0 @@
#ifndef VECTOR2_H
#define VECTOR2_H
#include <gdnative/vector2.h>
#include "Defs.hpp"
#include <Math.hpp>
namespace godot {
class String;
struct Vector2 {
enum Axis {
AXIS_X = 0,
AXIS_Y,
AXIS_COUNT
};
static const Vector2 ZERO;
static const Vector2 ONE;
static const Vector2 INF;
// Coordinate system of the 2D engine
static const Vector2 LEFT;
static const Vector2 RIGHT;
static const Vector2 UP;
static const Vector2 DOWN;
union {
real_t x;
real_t width;
};
union {
real_t y;
real_t height;
};
inline Vector2(real_t p_x, real_t p_y) {
x = p_x;
y = p_y;
}
inline Vector2() {
x = 0;
y = 0;
}
inline real_t &operator[](int p_idx) {
return p_idx ? y : x;
}
inline const real_t &operator[](int p_idx) const {
return p_idx ? y : x;
}
inline Vector2 operator+(const Vector2 &p_v) const {
return Vector2(x + p_v.x, y + p_v.y);
}
inline void operator+=(const Vector2 &p_v) {
x += p_v.x;
y += p_v.y;
}
inline Vector2 operator-(const Vector2 &p_v) const {
return Vector2(x - p_v.x, y - p_v.y);
}
inline void operator-=(const Vector2 &p_v) {
x -= p_v.x;
y -= p_v.y;
}
inline Vector2 operator*(const Vector2 &p_v1) const {
return Vector2(x * p_v1.x, y * p_v1.y);
}
inline Vector2 operator*(const real_t &rvalue) const {
return Vector2(x * rvalue, y * rvalue);
}
inline void operator*=(const real_t &rvalue) {
x *= rvalue;
y *= rvalue;
}
inline void operator*=(const Vector2 &rvalue) {
*this = *this * rvalue;
}
inline Vector2 operator/(const Vector2 &p_v1) const {
return Vector2(x / p_v1.x, y / p_v1.y);
}
inline Vector2 operator/(const real_t &rvalue) const {
return Vector2(x / rvalue, y / rvalue);
}
inline void operator/=(const real_t &rvalue) {
x /= rvalue;
y /= rvalue;
}
inline Vector2 operator-() const {
return Vector2(-x, -y);
}
bool operator==(const Vector2 &p_vec2) const;
bool operator!=(const Vector2 &p_vec2) const;
inline bool operator<(const Vector2 &p_vec2) const { return (x == p_vec2.x) ? (y < p_vec2.y) : (x < p_vec2.x); }
inline bool operator<=(const Vector2 &p_vec2) const { return (x == p_vec2.x) ? (y <= p_vec2.y) : (x <= p_vec2.x); }
inline void normalize() {
real_t l = x * x + y * y;
if (l != 0) {
l = sqrt(l);
x /= l;
y /= l;
}
}
inline Vector2 normalized() const {
Vector2 v = *this;
v.normalize();
return v;
}
inline real_t length() const {
return sqrt(x * x + y * y);
}
inline real_t length_squared() const {
return x * x + y * y;
}
inline real_t distance_to(const Vector2 &p_vector2) const {
return sqrt((x - p_vector2.x) * (x - p_vector2.x) + (y - p_vector2.y) * (y - p_vector2.y));
}
inline real_t distance_squared_to(const Vector2 &p_vector2) const {
return (x - p_vector2.x) * (x - p_vector2.x) + (y - p_vector2.y) * (y - p_vector2.y);
}
inline real_t angle_to(const Vector2 &p_vector2) const {
return atan2(cross(p_vector2), dot(p_vector2));
}
inline real_t angle_to_point(const Vector2 &p_vector2) const {
return atan2(y - p_vector2.y, x - p_vector2.x);
}
inline Vector2 direction_to(const Vector2 &p_b) const {
Vector2 ret(p_b.x - x, p_b.y - y);
ret.normalize();
return ret;
}
inline real_t dot(const Vector2 &p_other) const {
return x * p_other.x + y * p_other.y;
}
inline real_t cross(const Vector2 &p_other) const {
return x * p_other.y - y * p_other.x;
}
inline Vector2 cross(real_t p_other) const {
return Vector2(p_other * y, -p_other * x);
}
Vector2 project(const Vector2 &p_vec) const;
Vector2 plane_project(real_t p_d, const Vector2 &p_vec) const;
Vector2 clamped(real_t p_len) const;
static inline Vector2 linear_interpolate(const Vector2 &p_a, const Vector2 &p_b, real_t p_t) {
Vector2 res = p_a;
res.x += (p_t * (p_b.x - p_a.x));
res.y += (p_t * (p_b.y - p_a.y));
return res;
}
inline Vector2 linear_interpolate(const Vector2 &p_b, real_t p_t) const {
Vector2 res = *this;
res.x += (p_t * (p_b.x - x));
res.y += (p_t * (p_b.y - y));
return res;
}
Vector2 cubic_interpolate(const Vector2 &p_b, const Vector2 &p_pre_a, const Vector2 &p_post_b, real_t p_t) const;
Vector2 move_toward(const Vector2 &p_to, const real_t p_delta) const {
Vector2 v = *this;
Vector2 vd = p_to - v;
real_t len = vd.length();
return len <= p_delta || len < CMP_EPSILON ? p_to : v + vd / len * p_delta;
}
inline Vector2 slide(const Vector2 &p_vec) const {
return p_vec - *this * this->dot(p_vec);
}
inline Vector2 bounce(const Vector2 &p_normal) const {
return -reflect(p_normal);
}
inline Vector2 reflect(const Vector2 &p_normal) const {
return -(*this - p_normal * this->dot(p_normal) * 2.0);
}
inline real_t angle() const {
return atan2(y, x);
}
inline void set_rotation(real_t p_radians) {
x = cosf(p_radians);
y = sinf(p_radians);
}
inline Vector2 abs() const {
return Vector2(fabs(x), fabs(y));
}
inline Vector2 rotated(real_t p_by) const {
Vector2 v;
v.set_rotation(angle() + p_by);
v *= length();
return v;
}
inline Vector2 tangent() const {
return Vector2(y, -x);
}
inline Vector2 floor() const {
return Vector2(Math::floor(x), Math::floor(y));
}
inline Vector2 snapped(const Vector2 &p_by) const {
return Vector2(
Math::stepify(x, p_by.x),
Math::stepify(y, p_by.y));
}
inline real_t aspect() const { return width / height; }
operator String() const;
};
inline Vector2 operator*(real_t p_scalar, const Vector2 &p_vec) {
return p_vec * p_scalar;
}
namespace Math {
// Convenience, since they exist in GDScript
inline Vector2 cartesian2polar(Vector2 v) {
return Vector2(Math::sqrt(v.x * v.x + v.y * v.y), Math::atan2(v.y, v.x));
}
inline Vector2 polar2cartesian(Vector2 v) {
// x == radius
// y == angle
return Vector2(v.x * Math::cos(v.y), v.x * Math::sin(v.y));
}
} // namespace Math
} // namespace godot
#endif // VECTOR2_H

View File

@@ -1,314 +0,0 @@
#ifndef VECTOR3_H
#define VECTOR3_H
#include <gdnative/vector3.h>
#include "Defs.hpp"
#include "String.hpp"
#include <Math.hpp>
namespace godot {
class Basis;
struct Vector3 {
enum Axis {
AXIS_X,
AXIS_Y,
AXIS_Z,
AXIS_COUNT
};
static const Vector3 ZERO;
static const Vector3 ONE;
static const Vector3 INF;
// Coordinate system of the 3D engine
static const Vector3 LEFT;
static const Vector3 RIGHT;
static const Vector3 UP;
static const Vector3 DOWN;
static const Vector3 FORWARD;
static const Vector3 BACK;
union {
struct {
real_t x;
real_t y;
real_t z;
};
real_t coord[3]; // Not for direct access, use [] operator instead
};
inline Vector3(real_t x, real_t y, real_t z) {
this->x = x;
this->y = y;
this->z = z;
}
inline Vector3() {
this->x = 0;
this->y = 0;
this->z = 0;
}
inline const real_t &operator[](int p_axis) const {
return coord[p_axis];
}
inline real_t &operator[](int p_axis) {
return coord[p_axis];
}
inline Vector3 &operator+=(const Vector3 &p_v) {
x += p_v.x;
y += p_v.y;
z += p_v.z;
return *this;
}
inline Vector3 operator+(const Vector3 &p_v) const {
Vector3 v = *this;
v += p_v;
return v;
}
inline Vector3 &operator-=(const Vector3 &p_v) {
x -= p_v.x;
y -= p_v.y;
z -= p_v.z;
return *this;
}
inline Vector3 operator-(const Vector3 &p_v) const {
Vector3 v = *this;
v -= p_v;
return v;
}
inline Vector3 &operator*=(const Vector3 &p_v) {
x *= p_v.x;
y *= p_v.y;
z *= p_v.z;
return *this;
}
inline Vector3 operator*(const Vector3 &p_v) const {
Vector3 v = *this;
v *= p_v;
return v;
}
inline Vector3 &operator/=(const Vector3 &p_v) {
x /= p_v.x;
y /= p_v.y;
z /= p_v.z;
return *this;
}
inline Vector3 operator/(const Vector3 &p_v) const {
Vector3 v = *this;
v /= p_v;
return v;
}
inline Vector3 &operator*=(real_t p_scalar) {
*this *= Vector3(p_scalar, p_scalar, p_scalar);
return *this;
}
inline Vector3 operator*(real_t p_scalar) const {
Vector3 v = *this;
v *= p_scalar;
return v;
}
inline Vector3 &operator/=(real_t p_scalar) {
*this /= Vector3(p_scalar, p_scalar, p_scalar);
return *this;
}
inline Vector3 operator/(real_t p_scalar) const {
Vector3 v = *this;
v /= p_scalar;
return v;
}
inline Vector3 operator-() const {
return Vector3(-x, -y, -z);
}
inline bool operator==(const Vector3 &p_v) const {
return (x == p_v.x && y == p_v.y && z == p_v.z);
}
inline bool operator!=(const Vector3 &p_v) const {
return (x != p_v.x || y != p_v.y || z != p_v.z);
}
bool operator<(const Vector3 &p_v) const;
bool operator<=(const Vector3 &p_v) const;
inline Vector3 abs() const {
return Vector3(::fabs(x), ::fabs(y), ::fabs(z));
}
inline Vector3 ceil() const {
return Vector3(::ceil(x), ::ceil(y), ::ceil(z));
}
inline Vector3 cross(const Vector3 &b) const {
Vector3 ret(
(y * b.z) - (z * b.y),
(z * b.x) - (x * b.z),
(x * b.y) - (y * b.x));
return ret;
}
inline Vector3 linear_interpolate(const Vector3 &p_b, real_t p_t) const {
return Vector3(
x + (p_t * (p_b.x - x)),
y + (p_t * (p_b.y - y)),
z + (p_t * (p_b.z - z)));
}
inline Vector3 slerp(const Vector3 &p_b, real_t p_t) const {
real_t theta = angle_to(p_b);
return rotated(cross(p_b).normalized(), theta * p_t);
}
Vector3 cubic_interpolate(const Vector3 &b, const Vector3 &pre_a, const Vector3 &post_b, const real_t t) const;
Vector3 move_toward(const Vector3 &p_to, const real_t p_delta) const {
Vector3 v = *this;
Vector3 vd = p_to - v;
real_t len = vd.length();
return len <= p_delta || len < CMP_EPSILON ? p_to : v + vd / len * p_delta;
}
Vector3 bounce(const Vector3 &p_normal) const {
return -reflect(p_normal);
}
inline real_t length() const {
real_t x2 = x * x;
real_t y2 = y * y;
real_t z2 = z * z;
return ::sqrt(x2 + y2 + z2);
}
inline real_t length_squared() const {
real_t x2 = x * x;
real_t y2 = y * y;
real_t z2 = z * z;
return x2 + y2 + z2;
}
inline real_t distance_squared_to(const Vector3 &b) const {
return (b - *this).length_squared();
}
inline real_t distance_to(const Vector3 &b) const {
return (b - *this).length();
}
inline real_t dot(const Vector3 &b) const {
return x * b.x + y * b.y + z * b.z;
}
inline Vector3 project(const Vector3 &p_b) const {
return p_b * (dot(p_b) / p_b.length_squared());
}
inline real_t angle_to(const Vector3 &b) const {
return std::atan2(cross(b).length(), dot(b));
}
inline Vector3 direction_to(const Vector3 &p_b) const {
Vector3 ret(p_b.x - x, p_b.y - y, p_b.z - z);
ret.normalize();
return ret;
}
inline Vector3 floor() const {
return Vector3(::floor(x), ::floor(y), ::floor(z));
}
inline Vector3 inverse() const {
return Vector3(1.f / x, 1.f / y, 1.f / z);
}
inline bool is_normalized() const {
return std::abs(length_squared() - 1.f) < 0.00001f;
}
Basis outer(const Vector3 &b) const;
int max_axis() const;
int min_axis() const;
inline void normalize() {
real_t l = length();
if (l == 0) {
x = y = z = 0;
} else {
x /= l;
y /= l;
z /= l;
}
}
inline Vector3 normalized() const {
Vector3 v = *this;
v.normalize();
return v;
}
inline Vector3 reflect(const Vector3 &p_normal) const {
return -(*this - p_normal * this->dot(p_normal) * 2.0);
}
inline Vector3 rotated(const Vector3 &axis, const real_t phi) const {
Vector3 v = *this;
v.rotate(axis, phi);
return v;
}
void rotate(const Vector3 &p_axis, real_t p_phi);
inline Vector3 slide(const Vector3 &by) const {
return *this - by * this->dot(by);
}
void snap(real_t p_val);
inline Vector3 snapped(const float by) {
Vector3 v = *this;
v.snap(by);
return v;
}
operator String() const;
};
inline Vector3 operator*(real_t p_scalar, const Vector3 &p_vec) {
return p_vec * p_scalar;
}
inline Vector3 vec3_cross(const Vector3 &p_a, const Vector3 &p_b) {
return p_a.cross(p_b);
}
} // namespace godot
#endif // VECTOR3_H

View File

@@ -1,17 +0,0 @@
#ifndef WRAPPED_HPP
#define WRAPPED_HPP
#include <gdnative/gdnative.h>
namespace godot {
// This is an internal base class used by the bindings. You should not need to access its members.
class _Wrapped {
public:
godot_object *_owner;
size_t _type_tag;
};
} // namespace godot
#endif // WRAPPED_HPP

View File

@@ -1,2 +0,0 @@
*
!.gitignore

View 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 <class T>
static void add_by_type() {
add_plugin_class(T::get_class_static());
}
template <class T>
static void remove_by_type() {
remove_plugin_class(T::get_class_static());
}
};
} // namespace godot
#endif // GODOT_EDITOR_PLUGIN_REGISTRATION_HPP

View File

@@ -0,0 +1,284 @@
/**************************************************************************/
/* ref.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_REF_HPP
#define GODOT_REF_HPP
#include <godot_cpp/core/defs.hpp>
#include <godot_cpp/classes/object.hpp>
#include <godot_cpp/classes/ref_counted.hpp>
#include <godot_cpp/core/binder_common.hpp>
#include <godot_cpp/core/memory.hpp>
#include <godot_cpp/variant/variant.hpp>
namespace godot {
// Helper class for RefCounted objects, same as Godot one.
class RefCounted;
template <class T>
class Ref {
T *reference = nullptr;
void ref(const Ref &p_from) {
if (p_from.reference == reference) {
return;
}
unref();
reference = p_from.reference;
if (reference) {
reference->reference();
}
}
void ref_pointer(T *p_ref) {
ERR_FAIL_NULL(p_ref);
if (p_ref->init_ref()) {
reference = p_ref;
}
}
public:
_FORCE_INLINE_ bool operator==(const T *p_ptr) const {
return reference == p_ptr;
}
_FORCE_INLINE_ bool operator!=(const T *p_ptr) const {
return reference != p_ptr;
}
_FORCE_INLINE_ bool operator<(const Ref<T> &p_r) const {
return reference < p_r.reference;
}
_FORCE_INLINE_ bool operator==(const Ref<T> &p_r) const {
return reference == p_r.reference;
}
_FORCE_INLINE_ bool operator!=(const Ref<T> &p_r) const {
return reference != p_r.reference;
}
_FORCE_INLINE_ T *operator*() const {
return reference;
}
_FORCE_INLINE_ T *operator->() const {
return reference;
}
_FORCE_INLINE_ T *ptr() const {
return reference;
}
operator Variant() const {
return Variant(reference);
}
void operator=(const Ref &p_from) {
ref(p_from);
}
template <class T_Other>
void operator=(const Ref<T_Other> &p_from) {
RefCounted *refb = const_cast<RefCounted *>(static_cast<const RefCounted *>(p_from.ptr()));
if (!refb) {
unref();
return;
}
Ref r;
r.reference = Object::cast_to<T>(refb);
ref(r);
r.reference = nullptr;
}
void operator=(const Variant &p_variant) {
// Needs testing, Variant has a cast to Object * here.
// Object *object = p_variant.get_validated_object();
Object *object = p_variant;
if (object == reference) {
return;
}
unref();
if (!object) {
return;
}
T *r = Object::cast_to<T>(object);
if (r && r->reference()) {
reference = r;
}
}
template <class T_Other>
void reference_ptr(T_Other *p_ptr) {
if (reference == p_ptr) {
return;
}
unref();
T *r = Object::cast_to<T>(p_ptr);
if (r) {
ref_pointer(r);
}
}
Ref(const Ref &p_from) {
ref(p_from);
}
template <class T_Other>
Ref(const Ref<T_Other> &p_from) {
RefCounted *refb = const_cast<RefCounted *>(static_cast<const RefCounted *>(p_from.ptr()));
if (!refb) {
unref();
return;
}
Ref r;
r.reference = Object::cast_to<T>(refb);
ref(r);
r.reference = nullptr;
}
Ref(T *p_reference) {
if (p_reference) {
ref_pointer(p_reference);
}
}
Ref(const Variant &p_variant) {
// Needs testing, Variant has a cast to Object * here.
// Object *object = p_variant.get_validated_object();
Object *object = p_variant;
if (!object) {
return;
}
T *r = Object::cast_to<T>(object);
if (r && r->reference()) {
reference = r;
}
}
inline bool is_valid() const { return reference != nullptr; }
inline bool is_null() const { return reference == nullptr; }
void unref() {
if (reference && reference->unreference()) {
memdelete(reference);
}
reference = nullptr;
}
void instantiate() {
ref(memnew(T()));
}
Ref() {}
~Ref() {
unref();
}
// Used exclusively in the bindings to recreate the Ref Godot encapsulates in return values,
// without adding to the refcount.
inline static Ref<T> _gde_internal_constructor(Object *obj) {
Ref<T> r;
r.reference = (T *)obj;
return r;
}
};
template <class T>
struct PtrToArg<Ref<T>> {
_FORCE_INLINE_ static Ref<T> convert(const void *p_ptr) {
GDExtensionRefPtr ref = (GDExtensionRefPtr)p_ptr;
ERR_FAIL_NULL_V(p_ptr, Ref<T>());
return Ref<T>(reinterpret_cast<T *>(godot::internal::get_object_instance_binding(godot::internal::gdextension_interface_ref_get_object(ref))));
}
typedef Ref<T> EncodeT;
_FORCE_INLINE_ static void encode(Ref<T> p_val, void *p_ptr) {
GDExtensionRefPtr ref = (GDExtensionRefPtr)p_ptr;
ERR_FAIL_NULL(ref);
// This code assumes that p_ptr points to an unset Ref<T> variable on the Godot side
// so we only set it if we have an object to set.
if (p_val.is_valid()) {
godot::internal::gdextension_interface_ref_set_object(ref, p_val->_owner);
}
}
};
template <class T>
struct PtrToArg<const Ref<T> &> {
typedef Ref<T> EncodeT;
_FORCE_INLINE_ static Ref<T> convert(const void *p_ptr) {
GDExtensionRefPtr ref = const_cast<GDExtensionRefPtr>(p_ptr);
ERR_FAIL_NULL_V(p_ptr, Ref<T>());
return Ref<T>(reinterpret_cast<T *>(godot::internal::get_object_instance_binding(godot::internal::gdextension_interface_ref_get_object(ref))));
}
};
template <class 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;
static inline PropertyInfo get_class_info() {
return make_property_info(Variant::Type::OBJECT, "", PROPERTY_HINT_RESOURCE_TYPE, T::get_class_static());
}
};
template <class 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;
static inline PropertyInfo get_class_info() {
return make_property_info(Variant::Type::OBJECT, "", PROPERTY_HINT_RESOURCE_TYPE, T::get_class_static());
}
};
} // namespace godot
#endif // GODOT_REF_HPP

View File

@@ -0,0 +1,475 @@
/**************************************************************************/
/* wrapped.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_WRAPPED_HPP
#define GODOT_WRAPPED_HPP
#include <godot_cpp/core/memory.hpp>
#include <godot_cpp/core/property_info.hpp>
#include <godot_cpp/templates/list.hpp>
#include <godot_cpp/godot.hpp>
namespace godot {
class ClassDB;
typedef void GodotObject;
// Base for all engine classes, to contain the pointer to the engine instance.
class Wrapped {
friend class GDExtensionBinding;
friend void postinitialize_handler(Wrapped *);
protected:
#ifdef HOT_RELOAD_ENABLED
struct RecreateInstance {
GDExtensionClassInstancePtr wrapper;
GDExtensionObjectPtr owner;
RecreateInstance *next;
};
inline static RecreateInstance *recreate_instance = nullptr;
#endif
virtual const StringName *_get_extension_class_name() const; // This is needed to retrieve the class name before the godot object has its _extension and _extension_instance members assigned.
virtual const GDExtensionInstanceBindingCallbacks *_get_bindings_callbacks() const = 0;
void _notification(int p_what) {}
bool _set(const StringName &p_name, const Variant &p_property) { return false; }
bool _get(const StringName &p_name, Variant &r_property) const { return false; }
void _get_property_list(List<PropertyInfo> *p_list) const {}
bool _property_can_revert(const StringName &p_name) const { return false; }
bool _property_get_revert(const StringName &p_name, Variant &r_property) const { return false; }
void _validate_property(PropertyInfo &p_property) const {}
String _to_string() const { return "[" + String(get_class_static()) + ":" + itos(get_instance_id()) + "]"; }
static void notification_bind(GDExtensionClassInstancePtr p_instance, int32_t p_what, GDExtensionBool p_reversed) {}
static GDExtensionBool set_bind(GDExtensionClassInstancePtr p_instance, GDExtensionConstStringNamePtr p_name, GDExtensionConstVariantPtr p_value) { return false; }
static GDExtensionBool get_bind(GDExtensionClassInstancePtr p_instance, GDExtensionConstStringNamePtr p_name, GDExtensionVariantPtr r_ret) { return false; }
static const GDExtensionPropertyInfo *get_property_list_bind(GDExtensionClassInstancePtr p_instance, uint32_t *r_count) { return nullptr; }
static void free_property_list_bind(GDExtensionClassInstancePtr p_instance, const GDExtensionPropertyInfo *p_list) {}
static GDExtensionBool property_can_revert_bind(GDExtensionClassInstancePtr p_instance, GDExtensionConstStringNamePtr p_name) { return false; }
static GDExtensionBool property_get_revert_bind(GDExtensionClassInstancePtr p_instance, GDExtensionConstStringNamePtr p_name, GDExtensionVariantPtr r_ret) { return false; }
static GDExtensionBool validate_property_bind(GDExtensionClassInstancePtr p_instance, GDExtensionPropertyInfo *p_property) { return false; }
static void to_string_bind(GDExtensionClassInstancePtr p_instance, GDExtensionBool *r_is_valid, GDExtensionStringPtr r_out) {}
// The only reason this has to be held here, is when we return results of `_get_property_list` to Godot, we pass
// pointers to strings in this list. They have to remain valid to pass the bridge, until the list is freed by Godot...
::godot::List<::godot::PropertyInfo> plist_owned;
void _postinitialize();
Wrapped(const StringName p_godot_class);
Wrapped(GodotObject *p_godot_object);
virtual ~Wrapped() {}
public:
static StringName &get_class_static() {
static StringName string_name = StringName("Wrapped");
return string_name;
}
uint64_t get_instance_id() const {
return 0;
}
// Must be public but you should not touch this.
GodotObject *_owner = nullptr;
};
namespace internal {
GDExtensionPropertyInfo *create_c_property_list(const ::godot::List<::godot::PropertyInfo> &plist_cpp, uint32_t *r_size);
void free_c_property_list(GDExtensionPropertyInfo *plist);
typedef void (*EngineClassRegistrationCallback)();
void add_engine_class_registration_callback(EngineClassRegistrationCallback p_callback);
void register_engine_class(const StringName &p_name, const GDExtensionInstanceBindingCallbacks *p_callbacks);
void register_engine_classes();
template <class 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
#ifdef HOT_RELOAD_ENABLED
#define _GDCLASS_RECREATE(m_class, m_inherits) \
m_class *new_instance = (m_class *)memalloc(sizeof(m_class)); \
Wrapped::RecreateInstance recreate_data = { new_instance, obj, Wrapped::recreate_instance }; \
Wrapped::recreate_instance = &recreate_data; \
memnew_placement(new_instance, m_class); \
return new_instance;
#else
#define _GDCLASS_RECREATE(m_class, m_inherits) return nullptr;
#endif
// Use this on top of your own classes.
// Note: the trail of `***` is to keep sane diffs in PRs, because clang-format otherwise moves every `\` which makes
// every line of the macro different
#define GDCLASS(m_class, m_inherits) /***********************************************************************************************************************************************/ \
private: \
void operator=(const m_class &p_rval) {} \
friend class ::godot::ClassDB; \
\
protected: \
virtual const ::godot::StringName *_get_extension_class_name() const override { \
static ::godot::StringName string_name = get_class_static(); \
return &string_name; \
} \
\
virtual const GDExtensionInstanceBindingCallbacks *_get_bindings_callbacks() const override { \
return &_gde_binding_callbacks; \
} \
\
static void (*_get_bind_methods())() { \
return &m_class::_bind_methods; \
} \
\
static void (::godot::Wrapped::*_get_notification())(int) { \
return (void(::godot::Wrapped::*)(int)) & m_class::_notification; \
} \
\
static bool (::godot::Wrapped::*_get_set())(const ::godot::StringName &p_name, const ::godot::Variant &p_property) { \
return (bool(::godot::Wrapped::*)(const ::godot::StringName &p_name, const ::godot::Variant &p_property)) & m_class::_set; \
} \
\
static bool (::godot::Wrapped::*_get_get())(const ::godot::StringName &p_name, ::godot::Variant &r_ret) const { \
return (bool(::godot::Wrapped::*)(const ::godot::StringName &p_name, ::godot::Variant &r_ret) const) & m_class::_get; \
} \
\
static void (::godot::Wrapped::*_get_get_property_list())(::godot::List<::godot::PropertyInfo> * p_list) const { \
return (void(::godot::Wrapped::*)(::godot::List<::godot::PropertyInfo> * p_list) const) & m_class::_get_property_list; \
} \
\
static bool (::godot::Wrapped::*_get_property_can_revert())(const ::godot::StringName &p_name) const { \
return (bool(::godot::Wrapped::*)(const ::godot::StringName &p_name) const) & m_class::_property_can_revert; \
} \
\
static bool (::godot::Wrapped::*_get_property_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 void (::godot::Wrapped::*_get_validate_property())(::godot::PropertyInfo & p_property) const { \
return (void(::godot::Wrapped::*)(::godot::PropertyInfo & p_property) const) & m_class::_validate_property; \
} \
\
static ::godot::String (::godot::Wrapped::*_get_to_string())() const { \
return (::godot::String(::godot::Wrapped::*)() const) & m_class::_to_string; \
} \
\
template <class T, class 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) { \
return; \
} \
m_inherits::initialize_class(); \
if (m_class::_get_bind_methods() != m_inherits::_get_bind_methods()) { \
_bind_methods(); \
m_inherits::register_virtuals<m_class, m_inherits>(); \
} \
initialized = true; \
} \
\
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 GDExtensionObjectPtr create(void *data) { \
m_class *new_object = memnew(m_class); \
return new_object->_owner; \
} \
\
static GDExtensionClassInstancePtr recreate(void *data, GDExtensionObjectPtr obj) { \
_GDCLASS_RECREATE(m_class, m_inherits); \
} \
\
static void notification_bind(GDExtensionClassInstancePtr p_instance, int32_t p_what, GDExtensionBool p_reversed) { \
if (p_instance && m_class::_get_notification()) { \
if (m_class::_get_notification() != m_inherits::_get_notification()) { \
m_class *cls = reinterpret_cast<m_class *>(p_instance); \
return cls->_notification(p_what); \
} \
m_inherits::notification_bind(p_instance, p_what, p_reversed); \
} \
} \
\
static GDExtensionBool set_bind(GDExtensionClassInstancePtr p_instance, GDExtensionConstStringNamePtr p_name, GDExtensionConstVariantPtr p_value) { \
if (p_instance && m_class::_get_set()) { \
if (m_class::_get_set() != m_inherits::_get_set()) { \
m_class *cls = reinterpret_cast<m_class *>(p_instance); \
return cls->_set(*reinterpret_cast<const ::godot::StringName *>(p_name), *reinterpret_cast<const ::godot::Variant *>(p_value)); \
} \
return m_inherits::set_bind(p_instance, p_name, p_value); \
} \
return false; \
} \
\
static GDExtensionBool get_bind(GDExtensionClassInstancePtr p_instance, GDExtensionConstStringNamePtr p_name, GDExtensionVariantPtr r_ret) { \
if (p_instance && m_class::_get_get()) { \
if (m_class::_get_get() != m_inherits::_get_get()) { \
m_class *cls = reinterpret_cast<m_class *>(p_instance); \
return cls->_get(*reinterpret_cast<const ::godot::StringName *>(p_name), *reinterpret_cast<::godot::Variant *>(r_ret)); \
} \
return m_inherits::get_bind(p_instance, p_name, r_ret); \
} \
return false; \
} \
\
static inline bool has_get_property_list() { \
return m_class::_get_get_property_list() && m_class::_get_get_property_list() != m_inherits::_get_get_property_list(); \
} \
\
static const GDExtensionPropertyInfo *get_property_list_bind(GDExtensionClassInstancePtr p_instance, uint32_t *r_count) { \
if (!p_instance) { \
if (r_count) \
*r_count = 0; \
return nullptr; \
} \
m_class *cls = reinterpret_cast<m_class *>(p_instance); \
::godot::List<::godot::PropertyInfo> &plist_cpp = cls->plist_owned; \
ERR_FAIL_COND_V_MSG(!plist_cpp.is_empty(), nullptr, "Internal error, property list was not freed by engine!"); \
cls->_get_property_list(&plist_cpp); \
return ::godot::internal::create_c_property_list(plist_cpp, r_count); \
} \
\
static void free_property_list_bind(GDExtensionClassInstancePtr p_instance, const GDExtensionPropertyInfo *p_list) { \
if (p_instance) { \
m_class *cls = reinterpret_cast<m_class *>(p_instance); \
cls->plist_owned.clear(); \
/* TODO `GDExtensionClassFreePropertyList` is ill-defined, we need a non-const pointer to free this. */ \
::godot::internal::free_c_property_list(const_cast<GDExtensionPropertyInfo *>(p_list)); \
} \
} \
\
static GDExtensionBool property_can_revert_bind(GDExtensionClassInstancePtr p_instance, GDExtensionConstStringNamePtr p_name) { \
if (p_instance && m_class::_get_property_can_revert()) { \
if (m_class::_get_property_can_revert() != m_inherits::_get_property_can_revert()) { \
m_class *cls = reinterpret_cast<m_class *>(p_instance); \
return cls->_property_can_revert(*reinterpret_cast<const ::godot::StringName *>(p_name)); \
} \
return m_inherits::property_can_revert_bind(p_instance, p_name); \
} \
return false; \
} \
\
static GDExtensionBool property_get_revert_bind(GDExtensionClassInstancePtr p_instance, GDExtensionConstStringNamePtr p_name, GDExtensionVariantPtr r_ret) { \
if (p_instance && m_class::_get_property_get_revert()) { \
if (m_class::_get_property_get_revert() != m_inherits::_get_property_get_revert()) { \
m_class *cls = reinterpret_cast<m_class *>(p_instance); \
return cls->_property_get_revert(*reinterpret_cast<const ::godot::StringName *>(p_name), *reinterpret_cast<::godot::Variant *>(r_ret)); \
} \
return m_inherits::property_get_revert_bind(p_instance, p_name, r_ret); \
} \
return false; \
} \
\
static GDExtensionBool validate_property_bind(GDExtensionClassInstancePtr p_instance, GDExtensionPropertyInfo *p_property) { \
bool ret = false; \
if (p_instance && m_class::_get_validate_property()) { \
ret = m_inherits::validate_property_bind(p_instance, p_property); \
if (m_class::_get_validate_property() != m_inherits::_get_validate_property()) { \
m_class *cls = reinterpret_cast<m_class *>(p_instance); \
::godot::PropertyInfo info(p_property); \
cls->_validate_property(info); \
info._update(p_property); \
return true; \
} \
} \
return ret; \
} \
\
static void to_string_bind(GDExtensionClassInstancePtr p_instance, GDExtensionBool *r_is_valid, GDExtensionStringPtr r_out) { \
if (p_instance && m_class::_get_to_string()) { \
if (m_class::_get_to_string() != m_inherits::_get_to_string()) { \
m_class *cls = reinterpret_cast<m_class *>(p_instance); \
*reinterpret_cast<::godot::String *>(r_out) = cls->_to_string(); \
*r_is_valid = true; \
return; \
} \
m_inherits::to_string_bind(p_instance, r_is_valid, r_out); \
} \
} \
\
static void free(void *data, GDExtensionClassInstancePtr ptr) { \
if (ptr) { \
m_class *cls = reinterpret_cast<m_class *>(ptr); \
cls->~m_class(); \
::godot::Memory::free_static(cls); \
} \
} \
\
static void *_gde_binding_create_callback(void *p_token, void *p_instance) { \
return nullptr; \
} \
\
static void _gde_binding_free_callback(void *p_token, void *p_instance, void *p_binding) { \
} \
\
static 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, \
}; \
\
private:
// Don't use this for your classes, use GDCLASS() instead.
#define GDEXTENSION_CLASS_ALIAS(m_class, m_alias_for, m_inherits) /******************************************************************************************************************/ \
private: \
inline static ::godot::internal::EngineClassRegistration<m_class> _gde_engine_class_registration_helper; \
void operator=(const m_class &p_rval) {} \
\
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 GDExtensionClassInstancePtr recreate(void *data, GDExtensionObjectPtr obj) { \
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

View File

@@ -0,0 +1,696 @@
/**************************************************************************/
/* binder_common.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_BINDER_COMMON_HPP
#define GODOT_BINDER_COMMON_HPP
#include <gdextension_interface.h>
#include <godot_cpp/core/method_ptrcall.hpp>
#include <godot_cpp/core/type_info.hpp>
#include <array>
#include <vector>
namespace godot {
#define VARIANT_ENUM_CAST(m_enum) \
namespace godot { \
MAKE_ENUM_TYPE_INFO(m_enum) \
template <> \
struct VariantCaster<m_enum> { \
static _FORCE_INLINE_ m_enum cast(const Variant &p_variant) { \
return (m_enum)p_variant.operator int64_t(); \
} \
}; \
template <> \
struct PtrToArg<m_enum> { \
_FORCE_INLINE_ static m_enum convert(const void *p_ptr) { \
return m_enum(*reinterpret_cast<const int64_t *>(p_ptr)); \
} \
typedef int64_t EncodeT; \
_FORCE_INLINE_ static void encode(m_enum p_val, void *p_ptr) { \
*reinterpret_cast<int64_t *>(p_ptr) = p_val; \
} \
}; \
}
#define VARIANT_BITFIELD_CAST(m_enum) \
namespace godot { \
MAKE_BITFIELD_TYPE_INFO(m_enum) \
template <> \
struct VariantCaster<BitField<m_enum>> { \
static _FORCE_INLINE_ BitField<m_enum> cast(const Variant &p_variant) { \
return BitField<m_enum>(p_variant.operator int64_t()); \
} \
}; \
template <> \
struct PtrToArg<BitField<m_enum>> { \
_FORCE_INLINE_ static BitField<m_enum> convert(const void *p_ptr) { \
return BitField<m_enum>(*reinterpret_cast<const int64_t *>(p_ptr)); \
} \
typedef int64_t EncodeT; \
_FORCE_INLINE_ static void encode(BitField<m_enum> p_val, void *p_ptr) { \
*reinterpret_cast<int64_t *>(p_ptr) = p_val; \
} \
}; \
}
template <class T>
struct VariantCaster {
static _FORCE_INLINE_ T cast(const Variant &p_variant) {
using TStripped = std::remove_pointer_t<T>;
if constexpr (std::is_base_of<Object, TStripped>::value) {
return Object::cast_to<TStripped>(p_variant);
} else {
return p_variant;
}
}
};
template <class T>
struct VariantCaster<T &> {
static _FORCE_INLINE_ T cast(const Variant &p_variant) {
using TStripped = std::remove_pointer_t<T>;
if constexpr (std::is_base_of<Object, TStripped>::value) {
return Object::cast_to<TStripped>(p_variant);
} else {
return p_variant;
}
}
};
template <class T>
struct VariantCaster<const T &> {
static _FORCE_INLINE_ T cast(const Variant &p_variant) {
using TStripped = std::remove_pointer_t<T>;
if constexpr (std::is_base_of<Object, TStripped>::value) {
return Object::cast_to<TStripped>(p_variant);
} else {
return p_variant;
}
}
};
template <typename T>
struct VariantObjectClassChecker {
static _FORCE_INLINE_ bool check(const Variant &p_variant) {
using TStripped = std::remove_pointer_t<T>;
if constexpr (std::is_base_of<Object, TStripped>::value) {
Object *obj = p_variant;
return Object::cast_to<TStripped>(p_variant) || !obj;
} else {
return true;
}
}
};
template <typename T>
class Ref;
template <typename T>
struct VariantObjectClassChecker<const Ref<T> &> {
static _FORCE_INLINE_ bool check(const Variant &p_variant) {
Object *obj = p_variant;
const Ref<T> node = p_variant;
return node.ptr() || !obj;
}
};
template <class T>
struct VariantCasterAndValidate {
static _FORCE_INLINE_ T cast(const Variant **p_args, uint32_t p_arg_idx, GDExtensionCallError &r_error) {
GDExtensionVariantType argtype = GDExtensionVariantType(GetTypeInfo<T>::VARIANT_TYPE);
if (!internal::gdextension_interface_variant_can_convert_strict(static_cast<GDExtensionVariantType>(p_args[p_arg_idx]->get_type()), argtype) ||
!VariantObjectClassChecker<T>::check(p_args[p_arg_idx])) {
r_error.error = GDEXTENSION_CALL_ERROR_INVALID_ARGUMENT;
r_error.argument = p_arg_idx;
r_error.expected = argtype;
}
return VariantCaster<T>::cast(*p_args[p_arg_idx]);
}
};
template <class T>
struct VariantCasterAndValidate<T &> {
static _FORCE_INLINE_ T cast(const Variant **p_args, uint32_t p_arg_idx, GDExtensionCallError &r_error) {
GDExtensionVariantType argtype = GDExtensionVariantType(GetTypeInfo<T>::VARIANT_TYPE);
if (!internal::gdextension_interface_variant_can_convert_strict(static_cast<GDExtensionVariantType>(p_args[p_arg_idx]->get_type()), argtype) ||
!VariantObjectClassChecker<T>::check(p_args[p_arg_idx])) {
r_error.error = GDEXTENSION_CALL_ERROR_INVALID_ARGUMENT;
r_error.argument = p_arg_idx;
r_error.expected = argtype;
}
return VariantCaster<T>::cast(*p_args[p_arg_idx]);
}
};
template <class T>
struct VariantCasterAndValidate<const T &> {
static _FORCE_INLINE_ T cast(const Variant **p_args, uint32_t p_arg_idx, GDExtensionCallError &r_error) {
GDExtensionVariantType argtype = GDExtensionVariantType(GetTypeInfo<T>::VARIANT_TYPE);
if (!internal::gdextension_interface_variant_can_convert_strict(static_cast<GDExtensionVariantType>(p_args[p_arg_idx]->get_type()), argtype) ||
!VariantObjectClassChecker<T>::check(p_args[p_arg_idx])) {
r_error.error = GDEXTENSION_CALL_ERROR_INVALID_ARGUMENT;
r_error.argument = p_arg_idx;
r_error.expected = argtype;
}
return VariantCaster<T>::cast(*p_args[p_arg_idx]);
}
};
template <class T, class... P, size_t... Is>
void call_with_ptr_args_helper(T *p_instance, void (T::*p_method)(P...), const GDExtensionConstTypePtr *p_args, IndexSequence<Is...>) {
(p_instance->*p_method)(PtrToArg<P>::convert(p_args[Is])...);
}
template <class T, class... P, size_t... Is>
void call_with_ptr_argsc_helper(T *p_instance, void (T::*p_method)(P...) const, const GDExtensionConstTypePtr *p_args, IndexSequence<Is...>) {
(p_instance->*p_method)(PtrToArg<P>::convert(p_args[Is])...);
}
template <class T, class R, class... P, size_t... Is>
void call_with_ptr_args_ret_helper(T *p_instance, R (T::*p_method)(P...), const GDExtensionConstTypePtr *p_args, void *r_ret, IndexSequence<Is...>) {
PtrToArg<R>::encode((p_instance->*p_method)(PtrToArg<P>::convert(p_args[Is])...), r_ret);
}
template <class T, class R, class... P, size_t... Is>
void call_with_ptr_args_retc_helper(T *p_instance, R (T::*p_method)(P...) const, const GDExtensionConstTypePtr *p_args, void *r_ret, IndexSequence<Is...>) {
PtrToArg<R>::encode((p_instance->*p_method)(PtrToArg<P>::convert(p_args[Is])...), r_ret);
}
template <class T, class... P>
void call_with_ptr_args(T *p_instance, void (T::*p_method)(P...), const GDExtensionConstTypePtr *p_args, void * /*ret*/) {
call_with_ptr_args_helper<T, P...>(p_instance, p_method, p_args, BuildIndexSequence<sizeof...(P)>{});
}
template <class T, class... P>
void call_with_ptr_args(T *p_instance, void (T::*p_method)(P...) const, const GDExtensionConstTypePtr *p_args, void * /*ret*/) {
call_with_ptr_argsc_helper<T, P...>(p_instance, p_method, p_args, BuildIndexSequence<sizeof...(P)>{});
}
template <class T, class R, class... P>
void call_with_ptr_args(T *p_instance, R (T::*p_method)(P...), const GDExtensionConstTypePtr *p_args, void *r_ret) {
call_with_ptr_args_ret_helper<T, R, P...>(p_instance, p_method, p_args, r_ret, BuildIndexSequence<sizeof...(P)>{});
}
template <class T, class R, class... P>
void call_with_ptr_args(T *p_instance, R (T::*p_method)(P...) const, const GDExtensionConstTypePtr *p_args, void *r_ret) {
call_with_ptr_args_retc_helper<T, R, P...>(p_instance, p_method, p_args, r_ret, BuildIndexSequence<sizeof...(P)>{});
}
template <class T, class... P, size_t... Is>
void call_with_variant_args_helper(T *p_instance, void (T::*p_method)(P...), const Variant **p_args, GDExtensionCallError &r_error, IndexSequence<Is...>) {
r_error.error = GDEXTENSION_CALL_OK;
#ifdef DEBUG_METHODS_ENABLED
(p_instance->*p_method)(VariantCasterAndValidate<P>::cast(p_args, Is, r_error)...);
#else
(p_instance->*p_method)(VariantCaster<P>::cast(*p_args[Is])...);
#endif
(void)(p_args); // Avoid warning.
}
template <class T, class... P, size_t... Is>
void call_with_variant_argsc_helper(T *p_instance, void (T::*p_method)(P...) const, const Variant **p_args, GDExtensionCallError &r_error, IndexSequence<Is...>) {
r_error.error = GDEXTENSION_CALL_OK;
#ifdef DEBUG_METHODS_ENABLED
(p_instance->*p_method)(VariantCasterAndValidate<P>::cast(p_args, Is, r_error)...);
#else
(p_instance->*p_method)(VariantCaster<P>::cast(*p_args[Is])...);
#endif
(void)(p_args); // Avoid warning.
}
template <class T, class R, class... P, size_t... Is>
void call_with_variant_args_ret_helper(T *p_instance, R (T::*p_method)(P...), const Variant **p_args, Variant &r_ret, GDExtensionCallError &r_error, IndexSequence<Is...>) {
r_error.error = GDEXTENSION_CALL_OK;
#ifdef DEBUG_METHODS_ENABLED
r_ret = (p_instance->*p_method)(VariantCasterAndValidate<P>::cast(p_args, Is, r_error)...);
#else
r_ret = (p_instance->*p_method)(VariantCaster<P>::cast(*p_args[Is])...);
#endif
}
template <class T, class R, class... P, size_t... Is>
void call_with_variant_args_retc_helper(T *p_instance, R (T::*p_method)(P...) const, const Variant **p_args, Variant &r_ret, GDExtensionCallError &r_error, IndexSequence<Is...>) {
r_error.error = GDEXTENSION_CALL_OK;
#ifdef DEBUG_METHODS_ENABLED
r_ret = (p_instance->*p_method)(VariantCasterAndValidate<P>::cast(p_args, Is, r_error)...);
#else
r_ret = (p_instance->*p_method)(VariantCaster<P>::cast(*p_args[Is])...);
#endif
(void)p_args;
}
template <class T, class... P>
void call_with_variant_args(T *p_instance, void (T::*p_method)(P...), const Variant **p_args, int p_argcount, GDExtensionCallError &r_error) {
#ifdef DEBUG_ENABLED
if ((size_t)p_argcount > sizeof...(P)) {
r_error.error = GDEXTENSION_CALL_ERROR_TOO_MANY_ARGUMENTS;
r_error.argument = (int32_t)sizeof...(P);
return;
}
if ((size_t)p_argcount < sizeof...(P)) {
r_error.error = GDEXTENSION_CALL_ERROR_TOO_FEW_ARGUMENTS;
r_error.argument = (int32_t)sizeof...(P);
return;
}
#endif
call_with_variant_args_helper<T, P...>(p_instance, p_method, p_args, r_error, BuildIndexSequence<sizeof...(P)>{});
}
template <class T, class R, class... P>
void call_with_variant_args_ret(T *p_instance, R (T::*p_method)(P...), const Variant **p_args, int p_argcount, Variant &r_ret, GDExtensionCallError &r_error) {
#ifdef DEBUG_ENABLED
if ((size_t)p_argcount > sizeof...(P)) {
r_error.error = GDEXTENSION_CALL_ERROR_TOO_MANY_ARGUMENTS;
r_error.argument = (int32_t)sizeof...(P);
return;
}
if ((size_t)p_argcount < sizeof...(P)) {
r_error.error = GDEXTENSION_CALL_ERROR_TOO_FEW_ARGUMENTS;
r_error.argument = (int32_t)sizeof...(P);
return;
}
#endif
call_with_variant_args_ret_helper<T, R, P...>(p_instance, p_method, p_args, r_ret, r_error, BuildIndexSequence<sizeof...(P)>{});
}
template <class T, class R, class... P>
void call_with_variant_args_retc(T *p_instance, R (T::*p_method)(P...) const, const Variant **p_args, int p_argcount, Variant &r_ret, GDExtensionCallError &r_error) {
#ifdef DEBUG_ENABLED
if ((size_t)p_argcount > sizeof...(P)) {
r_error.error = GDEXTENSION_CALL_ERROR_TOO_MANY_ARGUMENTS;
r_error.argument = (int32_t)sizeof...(P);
return;
}
if ((size_t)p_argcount < sizeof...(P)) {
r_error.error = GDEXTENSION_CALL_ERROR_TOO_FEW_ARGUMENTS;
r_error.argument = (int32_t)sizeof...(P);
return;
}
#endif
call_with_variant_args_retc_helper<T, R, P...>(p_instance, p_method, p_args, r_ret, r_error, BuildIndexSequence<sizeof...(P)>{});
}
template <class T, class... P>
void call_with_variant_args_dv(T *p_instance, void (T::*p_method)(P...), const GDExtensionConstVariantPtr *p_args, int p_argcount, GDExtensionCallError &r_error, const std::vector<Variant> &default_values) {
#ifdef DEBUG_ENABLED
if ((size_t)p_argcount > sizeof...(P)) {
r_error.error = GDEXTENSION_CALL_ERROR_TOO_MANY_ARGUMENTS;
r_error.argument = (int32_t)sizeof...(P);
return;
}
#endif
int32_t missing = (int32_t)sizeof...(P) - (int32_t)p_argcount;
int32_t dvs = (int32_t)default_values.size();
#ifdef DEBUG_ENABLED
if (missing > dvs) {
r_error.error = GDEXTENSION_CALL_ERROR_TOO_FEW_ARGUMENTS;
r_error.argument = (int32_t)sizeof...(P);
return;
}
#endif
Variant args[sizeof...(P) == 0 ? 1 : sizeof...(P)]; // Avoid zero sized array.
std::array<const Variant *, sizeof...(P)> argsp;
for (int32_t i = 0; i < (int32_t)sizeof...(P); i++) {
if (i < p_argcount) {
args[i] = Variant(p_args[i]);
} else {
args[i] = default_values[i - p_argcount + (dvs - missing)];
}
argsp[i] = &args[i];
}
call_with_variant_args_helper(p_instance, p_method, argsp.data(), r_error, BuildIndexSequence<sizeof...(P)>{});
}
template <class T, class... P>
void call_with_variant_argsc_dv(T *p_instance, void (T::*p_method)(P...) const, const GDExtensionConstVariantPtr *p_args, int p_argcount, GDExtensionCallError &r_error, const std::vector<Variant> &default_values) {
#ifdef DEBUG_ENABLED
if ((size_t)p_argcount > sizeof...(P)) {
r_error.error = GDEXTENSION_CALL_ERROR_TOO_MANY_ARGUMENTS;
r_error.argument = (int32_t)sizeof...(P);
return;
}
#endif
int32_t missing = (int32_t)sizeof...(P) - (int32_t)p_argcount;
int32_t dvs = (int32_t)default_values.size();
#ifdef DEBUG_ENABLED
if (missing > dvs) {
r_error.error = GDEXTENSION_CALL_ERROR_TOO_FEW_ARGUMENTS;
r_error.argument = (int32_t)sizeof...(P);
return;
}
#endif
Variant args[sizeof...(P) == 0 ? 1 : sizeof...(P)]; // Avoid zero sized array.
std::array<const Variant *, sizeof...(P)> argsp;
for (int32_t i = 0; i < (int32_t)sizeof...(P); i++) {
if (i < p_argcount) {
args[i] = Variant(p_args[i]);
} else {
args[i] = default_values[i - p_argcount + (dvs - missing)];
}
argsp[i] = &args[i];
}
call_with_variant_argsc_helper(p_instance, p_method, argsp.data(), r_error, BuildIndexSequence<sizeof...(P)>{});
}
template <class T, class R, class... P>
void call_with_variant_args_ret_dv(T *p_instance, R (T::*p_method)(P...), const GDExtensionConstVariantPtr *p_args, int p_argcount, Variant &r_ret, GDExtensionCallError &r_error, const std::vector<Variant> &default_values) {
#ifdef DEBUG_ENABLED
if ((size_t)p_argcount > sizeof...(P)) {
r_error.error = GDEXTENSION_CALL_ERROR_TOO_MANY_ARGUMENTS;
r_error.argument = (int32_t)sizeof...(P);
return;
}
#endif
int32_t missing = (int32_t)sizeof...(P) - (int32_t)p_argcount;
int32_t dvs = (int32_t)default_values.size();
#ifdef DEBUG_ENABLED
if (missing > dvs) {
r_error.error = GDEXTENSION_CALL_ERROR_TOO_FEW_ARGUMENTS;
r_error.argument = (int32_t)sizeof...(P);
return;
}
#endif
Variant args[sizeof...(P) == 0 ? 1 : sizeof...(P)]; // Avoid zero sized array.
std::array<const Variant *, sizeof...(P)> argsp;
for (int32_t i = 0; i < (int32_t)sizeof...(P); i++) {
if (i < p_argcount) {
args[i] = Variant(p_args[i]);
} else {
args[i] = default_values[i - p_argcount + (dvs - missing)];
}
argsp[i] = &args[i];
}
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>
void call_with_variant_args_retc_dv(T *p_instance, R (T::*p_method)(P...) const, const GDExtensionConstVariantPtr *p_args, int p_argcount, Variant &r_ret, GDExtensionCallError &r_error, const std::vector<Variant> &default_values) {
#ifdef DEBUG_ENABLED
if ((size_t)p_argcount > sizeof...(P)) {
r_error.error = GDEXTENSION_CALL_ERROR_TOO_MANY_ARGUMENTS;
r_error.argument = (int32_t)sizeof...(P);
return;
}
#endif
int32_t missing = (int32_t)sizeof...(P) - (int32_t)p_argcount;
int32_t dvs = (int32_t)default_values.size();
#ifdef DEBUG_ENABLED
if (missing > dvs) {
r_error.error = GDEXTENSION_CALL_ERROR_TOO_FEW_ARGUMENTS;
r_error.argument = (int32_t)sizeof...(P);
return;
}
#endif
Variant args[sizeof...(P) == 0 ? 1 : sizeof...(P)]; // Avoid zero sized array.
std::array<const Variant *, sizeof...(P)> argsp;
for (int32_t i = 0; i < (int32_t)sizeof...(P); i++) {
if (i < p_argcount) {
args[i] = Variant(p_args[i]);
} else {
args[i] = default_values[i - p_argcount + (dvs - missing)];
}
argsp[i] = &args[i];
}
call_with_variant_args_retc_helper(p_instance, p_method, argsp.data(), r_ret, r_error, BuildIndexSequence<sizeof...(P)>{});
}
// GCC raises "parameter 'p_args' set but not used" when P = {},
// it's not clever enough to treat other P values as making this branch valid.
#if defined(DEBUG_METHODS_ENABLED) && defined(__GNUC__) && !defined(__clang__)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-but-set-parameter"
#endif
template <class Q>
void call_get_argument_type_helper(int p_arg, int &index, GDExtensionVariantType &type) {
if (p_arg == index) {
type = GDExtensionVariantType(GetTypeInfo<Q>::VARIANT_TYPE);
}
index++;
}
template <class... P>
GDExtensionVariantType call_get_argument_type(int p_arg) {
GDExtensionVariantType type = GDEXTENSION_VARIANT_TYPE_NIL;
int index = 0;
// I think rocket science is simpler than modern C++.
using expand_type = int[];
expand_type a{ 0, (call_get_argument_type_helper<P>(p_arg, index, type), 0)... };
(void)a; // Suppress (valid, but unavoidable) -Wunused-variable warning.
(void)index; // Suppress GCC warning.
return type;
}
template <class Q>
void call_get_argument_type_info_helper(int p_arg, int &index, PropertyInfo &info) {
if (p_arg == index) {
info = GetTypeInfo<Q>::get_class_info();
}
index++;
}
template <class... P>
void call_get_argument_type_info(int p_arg, PropertyInfo &info) {
int index = 0;
// I think rocket science is simpler than modern C++.
using expand_type = int[];
expand_type a{ 0, (call_get_argument_type_info_helper<P>(p_arg, index, info), 0)... };
(void)a; // Suppress (valid, but unavoidable) -Wunused-variable warning.
(void)index; // Suppress GCC warning.
}
template <class Q>
void call_get_argument_metadata_helper(int p_arg, int &index, GDExtensionClassMethodArgumentMetadata &md) {
if (p_arg == index) {
md = GetTypeInfo<Q>::METADATA;
}
index++;
}
template <class... P>
GDExtensionClassMethodArgumentMetadata call_get_argument_metadata(int p_arg) {
GDExtensionClassMethodArgumentMetadata md = GDEXTENSION_METHOD_ARGUMENT_METADATA_NONE;
int index = 0;
// I think rocket science is simpler than modern C++.
using expand_type = int[];
expand_type a{ 0, (call_get_argument_metadata_helper<P>(p_arg, index, md), 0)... };
(void)a; // Suppress (valid, but unavoidable) -Wunused-variable warning.
(void)index;
return md;
}
template <class... P, size_t... Is>
void call_with_variant_args_static(void (*p_method)(P...), const Variant **p_args, GDExtensionCallError &r_error, IndexSequence<Is...>) {
r_error.error = GDEXTENSION_CALL_OK;
#ifdef DEBUG_METHODS_ENABLED
(p_method)(VariantCasterAndValidate<P>::cast(p_args, Is, r_error)...);
#else
(p_method)(VariantCaster<P>::cast(*p_args[Is])...);
#endif
}
template <class... P>
void call_with_variant_args_static_dv(void (*p_method)(P...), const GDExtensionConstVariantPtr *p_args, int p_argcount, GDExtensionCallError &r_error, const std::vector<Variant> &default_values) {
#ifdef DEBUG_ENABLED
if ((size_t)p_argcount > sizeof...(P)) {
r_error.error = GDEXTENSION_CALL_ERROR_TOO_MANY_ARGUMENTS;
r_error.argument = sizeof...(P);
return;
}
#endif
int32_t missing = (int32_t)sizeof...(P) - (int32_t)p_argcount;
int32_t dvs = default_values.size();
#ifdef DEBUG_ENABLED
if (missing > dvs) {
r_error.error = GDEXTENSION_CALL_ERROR_TOO_FEW_ARGUMENTS;
r_error.argument = sizeof...(P);
return;
}
#endif
Variant args[sizeof...(P) == 0 ? 1 : sizeof...(P)]; // Avoid zero sized array.
std::array<const Variant *, sizeof...(P)> argsp;
for (int32_t i = 0; i < (int32_t)sizeof...(P); i++) {
if (i < p_argcount) {
args[i] = Variant(p_args[i]);
} else {
args[i] = default_values[i - p_argcount + (dvs - missing)];
}
argsp[i] = &args[i];
}
call_with_variant_args_static(p_method, argsp.data(), r_error, BuildIndexSequence<sizeof...(P)>{});
}
template <class... P, size_t... Is>
void call_with_ptr_args_static_method_helper(void (*p_method)(P...), const GDExtensionConstTypePtr *p_args, IndexSequence<Is...>) {
p_method(PtrToArg<P>::convert(p_args[Is])...);
}
template <class... P>
void call_with_ptr_args_static_method(void (*p_method)(P...), const GDExtensionConstTypePtr *p_args) {
call_with_ptr_args_static_method_helper<P...>(p_method, p_args, BuildIndexSequence<sizeof...(P)>{});
}
template <class R, class... P>
void call_with_variant_args_static_ret(R (*p_method)(P...), const Variant **p_args, int p_argcount, Variant &r_ret, GDExtensionCallError &r_error) {
#ifdef DEBUG_ENABLED
if ((size_t)p_argcount > sizeof...(P)) {
r_error.error = GDEXTENSION_CALL_ERROR_TOO_MANY_ARGUMENTS;
r_error.argument = (int32_t)sizeof...(P);
return;
}
if ((size_t)p_argcount < sizeof...(P)) {
r_error.error = GDEXTENSION_CALL_ERROR_TOO_FEW_ARGUMENTS;
r_error.argument = (int32_t)sizeof...(P);
return;
}
#endif
call_with_variant_args_static_ret<R, P...>(p_method, p_args, r_ret, r_error, BuildIndexSequence<sizeof...(P)>{});
}
template <class... P>
void call_with_variant_args_static_ret(void (*p_method)(P...), const Variant **p_args, int p_argcount, Variant &r_ret, GDExtensionCallError &r_error) {
#ifdef DEBUG_ENABLED
if ((size_t)p_argcount > sizeof...(P)) {
r_error.error = GDEXTENSION_CALL_ERROR_TOO_MANY_ARGUMENTS;
r_error.argument = (int32_t)sizeof...(P);
return;
}
if ((size_t)p_argcount < sizeof...(P)) {
r_error.error = GDEXTENSION_CALL_ERROR_TOO_FEW_ARGUMENTS;
r_error.argument = (int32_t)sizeof...(P);
return;
}
#endif
call_with_variant_args_static<P...>(p_method, p_args, r_error, BuildIndexSequence<sizeof...(P)>{});
}
template <class R, class... P, size_t... Is>
void call_with_variant_args_static_ret(R (*p_method)(P...), const Variant **p_args, Variant &r_ret, GDExtensionCallError &r_error, IndexSequence<Is...>) {
r_error.error = GDEXTENSION_CALL_OK;
#ifdef DEBUG_METHODS_ENABLED
r_ret = (p_method)(VariantCasterAndValidate<P>::cast(p_args, Is, r_error)...);
#else
r_ret = (p_method)(VariantCaster<P>::cast(*p_args[Is])...);
#endif
}
template <class R, class... P>
void call_with_variant_args_static_ret_dv(R (*p_method)(P...), const GDExtensionConstVariantPtr *p_args, int p_argcount, Variant &r_ret, GDExtensionCallError &r_error, const std::vector<Variant> &default_values) {
#ifdef DEBUG_ENABLED
if ((size_t)p_argcount > sizeof...(P)) {
r_error.error = GDEXTENSION_CALL_ERROR_TOO_MANY_ARGUMENTS;
r_error.argument = sizeof...(P);
return;
}
#endif
int32_t missing = (int32_t)sizeof...(P) - (int32_t)p_argcount;
int32_t dvs = default_values.size();
#ifdef DEBUG_ENABLED
if (missing > dvs) {
r_error.error = GDEXTENSION_CALL_ERROR_TOO_FEW_ARGUMENTS;
r_error.argument = sizeof...(P);
return;
}
#endif
Variant args[sizeof...(P) == 0 ? 1 : sizeof...(P)]; // Avoid zero sized array.
std::array<const Variant *, sizeof...(P)> argsp;
for (int32_t i = 0; i < (int32_t)sizeof...(P); i++) {
if (i < p_argcount) {
args[i] = Variant(p_args[i]);
} else {
args[i] = default_values[i - p_argcount + (dvs - missing)];
}
argsp[i] = &args[i];
}
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>
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>
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)>{});
}
#if defined(__GNUC__) && !defined(__clang__)
#pragma GCC diagnostic pop
#endif
} // namespace godot
#include <godot_cpp/classes/global_constants_binds.hpp>
#include <godot_cpp/variant/builtin_binds.hpp>
#endif // GODOT_BINDER_COMMON_HPP

View File

@@ -0,0 +1,80 @@
/**************************************************************************/
/* builtin_ptrcall.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_BUILTIN_PTRCALL_HPP
#define GODOT_BUILTIN_PTRCALL_HPP
#include <gdextension_interface.h>
#include <array>
namespace godot {
namespace internal {
template <class... Args>
void _call_builtin_constructor(const GDExtensionPtrConstructor constructor, GDExtensionTypePtr base, Args... args) {
std::array<GDExtensionConstTypePtr, sizeof...(Args)> call_args = { { (GDExtensionConstTypePtr)args... } };
constructor(base, call_args.data());
}
template <class T, class... Args>
T _call_builtin_method_ptr_ret(const GDExtensionPtrBuiltInMethod method, GDExtensionTypePtr base, Args... args) {
T ret;
std::array<GDExtensionConstTypePtr, sizeof...(Args)> call_args = { { (GDExtensionConstTypePtr)args... } };
method(base, call_args.data(), &ret, sizeof...(Args));
return ret;
}
template <class... Args>
void _call_builtin_method_ptr_no_ret(const GDExtensionPtrBuiltInMethod method, GDExtensionTypePtr base, Args... args) {
std::array<GDExtensionConstTypePtr, sizeof...(Args)> call_args = { { (GDExtensionConstTypePtr)args... } };
method(base, call_args.data(), nullptr, sizeof...(Args));
}
template <class T>
T _call_builtin_operator_ptr(const GDExtensionPtrOperatorEvaluator op, GDExtensionConstTypePtr left, GDExtensionConstTypePtr right) {
T ret;
op(left, right, &ret);
return ret;
}
template <class T>
T _call_builtin_ptr_getter(const GDExtensionPtrGetter getter, GDExtensionConstTypePtr base) {
T ret;
getter(base, &ret);
return ret;
}
} // namespace internal
} // namespace godot
#endif // GODOT_BUILTIN_PTRCALL_HPP

View File

@@ -0,0 +1,301 @@
/**************************************************************************/
/* class_db.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_CLASS_DB_HPP
#define GODOT_CLASS_DB_HPP
#include <gdextension_interface.h>
#include <godot_cpp/core/defs.hpp>
#include <godot_cpp/core/error_macros.hpp>
#include <godot_cpp/core/method_bind.hpp>
#include <godot_cpp/core/object.hpp>
#include <godot_cpp/classes/class_db_singleton.hpp>
// Makes callable_mp readily available in all classes connecting signals.
// Needs to come after method_bind and object have been included.
#include <godot_cpp/variant/callable_method_pointer.hpp>
#include <list>
#include <set>
#include <string>
#include <unordered_map>
#include <vector>
// Needed to use StringName as key in `std::unordered_map`
template <>
struct std::hash<godot::StringName> {
std::size_t operator()(godot::StringName const &s) const noexcept {
return s.hash();
}
};
namespace godot {
#define DEFVAL(m_defval) (m_defval)
struct MethodDefinition {
StringName name;
std::list<StringName> args;
MethodDefinition() {}
MethodDefinition(StringName p_name) :
name(p_name) {}
};
MethodDefinition D_METHOD(StringName p_name);
MethodDefinition D_METHOD(StringName p_name, StringName p_arg1);
template <typename... Args>
MethodDefinition D_METHOD(StringName p_name, StringName p_arg1, Args... args) {
MethodDefinition md = D_METHOD(p_name, args...);
md.args.push_front(p_arg1);
return md;
}
class ClassDB {
static GDExtensionInitializationLevel current_level;
friend class godot::GDExtensionBinding;
public:
struct ClassInfo {
StringName name;
StringName parent_name;
GDExtensionInitializationLevel level = GDEXTENSION_INITIALIZATION_SCENE;
std::unordered_map<StringName, MethodBind *> method_map;
std::set<StringName> signal_names;
std::unordered_map<StringName, GDExtensionClassCallVirtual> virtual_methods;
std::set<StringName> property_names;
std::set<StringName> constant_names;
// Pointer to the parent custom class, if any. Will be null if the parent class is a Godot class.
ClassInfo *parent_ptr = nullptr;
};
private:
// This may only contain custom classes, not Godot classes
static std::unordered_map<StringName, ClassInfo> classes;
static std::unordered_map<StringName, const GDExtensionInstanceBindingCallbacks *> instance_binding_callbacks;
// Used to remember the custom class registration order.
static std::vector<StringName> class_register_order;
static MethodBind *bind_methodfi(uint32_t p_flags, MethodBind *p_bind, const MethodDefinition &method_name, const void **p_defs, int p_defcount);
static void initialize_class(const ClassInfo &cl);
static void bind_method_godot(const StringName &p_class_name, MethodBind *p_method);
template <class T, bool is_abstract>
static void _register_class(bool p_virtual = false, bool p_exposed = true);
public:
template <class T>
static void register_class(bool p_virtual = false);
template <class T>
static void register_abstract_class();
template <class T>
static void register_internal_class();
_FORCE_INLINE_ static void _register_engine_class(const StringName &p_name, const GDExtensionInstanceBindingCallbacks *p_callbacks) {
instance_binding_callbacks[p_name] = p_callbacks;
}
template <class N, class M, typename... VarArgs>
static MethodBind *bind_method(N p_method_name, M p_method, VarArgs... p_args);
template <class N, class M, typename... VarArgs>
static MethodBind *bind_static_method(StringName p_class, N p_method_name, M p_method, VarArgs... p_args);
template <class M>
static MethodBind *bind_vararg_method(uint32_t p_flags, StringName p_name, M p_method, const MethodInfo &p_info = MethodInfo(), const std::vector<Variant> &p_default_args = std::vector<Variant>{}, bool p_return_nil_is_variant = true);
static void add_property_group(const StringName &p_class, const String &p_name, const String &p_prefix);
static void add_property_subgroup(const StringName &p_class, const String &p_name, const String &p_prefix);
static void add_property(const StringName &p_class, const PropertyInfo &p_pinfo, const StringName &p_setter, const StringName &p_getter, int p_index = -1);
static void add_signal(const StringName &p_class, const MethodInfo &p_signal);
static void bind_integer_constant(const StringName &p_class_name, const StringName &p_enum_name, const StringName &p_constant_name, GDExtensionInt p_constant_value, bool p_is_bitfield = false);
static void bind_virtual_method(const StringName &p_class, const StringName &p_method, GDExtensionClassCallVirtual p_call);
static MethodBind *get_method(const StringName &p_class, const StringName &p_method);
static GDExtensionClassCallVirtual get_virtual_func(void *p_userdata, GDExtensionConstStringNamePtr p_name);
static const GDExtensionInstanceBindingCallbacks *get_instance_binding_callbacks(const StringName &p_class);
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);
#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);
#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);
#define BIND_VIRTUAL_METHOD(m_class, m_method) \
{ \
auto _call##m_method = [](GDExtensionObjectPtr p_instance, const GDExtensionConstTypePtr *p_args, GDExtensionTypePtr p_ret) -> void { \
call_with_ptr_args(reinterpret_cast<m_class *>(p_instance), &m_class::m_method, p_args, p_ret); \
}; \
godot::ClassDB::bind_virtual_method(m_class::get_class_static(), #m_method, _call##m_method); \
}
template <class T, bool is_abstract>
void ClassDB::_register_class(bool p_virtual, bool p_exposed) {
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
ClassInfo cl;
cl.name = T::get_class_static();
cl.parent_name = T::get_parent_class_static();
cl.level = current_level;
std::unordered_map<StringName, ClassInfo>::iterator parent_it = classes.find(cl.parent_name);
if (parent_it != classes.end()) {
// Assign parent if it is also a custom class
cl.parent_ptr = &parent_it->second;
}
classes[cl.name] = cl;
class_register_order.push_back(cl.name);
// Register this class with Godot
GDExtensionClassCreationInfo2 class_info = {
p_virtual, // GDExtensionBool is_virtual;
is_abstract, // GDExtensionBool is_abstract;
p_exposed, // GDExtensionBool is_exposed;
T::set_bind, // GDExtensionClassSet set_func;
T::get_bind, // GDExtensionClassGet get_func;
T::has_get_property_list() ? T::get_property_list_bind : nullptr, // GDExtensionClassGetPropertyList get_property_list_func;
T::free_property_list_bind, // GDExtensionClassFreePropertyList free_property_list_func;
T::property_can_revert_bind, // GDExtensionClassPropertyCanRevert property_can_revert_func;
T::property_get_revert_bind, // GDExtensionClassPropertyGetRevert property_get_revert_func;
T::validate_property_bind, // GDExtensionClassValidateProperty validate_property_func;
T::notification_bind, // GDExtensionClassNotification2 notification_func;
T::to_string_bind, // GDExtensionClassToString to_string_func;
nullptr, // GDExtensionClassReference reference_func;
nullptr, // GDExtensionClassUnreference unreference_func;
T::create, // GDExtensionClassCreateInstance create_instance_func; /* this one is mandatory */
T::free, // GDExtensionClassFreeInstance free_instance_func; /* this one is mandatory */
T::recreate, // GDExtensionClassRecreateInstance recreate_instance_func;
&ClassDB::get_virtual_func, // GDExtensionClassGetVirtual get_virtual_func;
nullptr, // GDExtensionClassGetVirtualCallData get_virtual_call_data_func;
nullptr, // GDExtensionClassCallVirtualWithData call_virtual_func;
nullptr, // GDExtensionClassGetRID get_rid;
(void *)&T::get_class_static(), // void *class_userdata;
};
internal::gdextension_interface_classdb_register_extension_class2(internal::library, cl.name._native_ptr(), cl.parent_name._native_ptr(), &class_info);
// call bind_methods etc. to register all members of the class
T::initialize_class();
// now register our class within ClassDB within Godot
initialize_class(classes[cl.name]);
}
template <class T>
void ClassDB::register_class(bool p_virtual) {
ClassDB::_register_class<T, false>(p_virtual);
}
template <class T>
void ClassDB::register_abstract_class() {
ClassDB::_register_class<T, true>();
}
template <class T>
void ClassDB::register_internal_class() {
ClassDB::_register_class<T, false>(false, false);
}
template <class N, class M, typename... VarArgs>
MethodBind *ClassDB::bind_method(N p_method_name, M p_method, VarArgs... p_args) {
Variant args[sizeof...(p_args) + 1] = { p_args..., Variant() }; // +1 makes sure zero sized arrays are also supported.
const Variant *argptrs[sizeof...(p_args) + 1];
for (uint32_t i = 0; i < sizeof...(p_args); i++) {
argptrs[i] = &args[i];
}
MethodBind *bind = create_method_bind(p_method);
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>
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];
for (uint32_t i = 0; i < sizeof...(p_args); i++) {
argptrs[i] = &args[i];
}
MethodBind *bind = create_static_method_bind(p_method);
bind->set_instance_class(p_class);
return bind_methodfi(0, bind, p_method_name, sizeof...(p_args) == 0 ? nullptr : (const void **)argptrs, sizeof...(p_args));
}
template <class M>
MethodBind *ClassDB::bind_vararg_method(uint32_t p_flags, StringName p_name, M p_method, const MethodInfo &p_info, const std::vector<Variant> &p_default_args, bool p_return_nil_is_variant) {
MethodBind *bind = create_vararg_method_bind(p_method, p_info, p_return_nil_is_variant);
ERR_FAIL_NULL_V(bind, nullptr);
bind->set_name(p_name);
bind->set_default_arguments(p_default_args);
StringName instance_type = bind->get_instance_class();
std::unordered_map<StringName, ClassInfo>::iterator type_it = classes.find(instance_type);
if (type_it == classes.end()) {
memdelete(bind);
ERR_FAIL_V_MSG(nullptr, String("Class '{0}' doesn't exist.").format(Array::make(instance_type)));
}
ClassInfo &type = type_it->second;
if (type.method_map.find(p_name) != type.method_map.end()) {
memdelete(bind);
ERR_FAIL_V_MSG(nullptr, String("Binding duplicate method: {0}::{1}.").format(Array::make(instance_type, p_method)));
}
// register our method bind within our plugin
type.method_map[p_name] = bind;
// and register with godot
bind_method_godot(type.name, bind);
return bind;
}
#define GDREGISTER_CLASS(m_class) ClassDB::register_class<m_class>();
#define GDREGISTER_VIRTUAL_CLASS(m_class) ClassDB::register_class<m_class>(true);
#define GDREGISTER_ABSTRACT_CLASS(m_class) ClassDB::register_abstract_class<m_class>();
#define GDREGISTER_INTERNAL_CLASS(m_class) ClassDB::register_internal_class<m_class>();
} // namespace godot
#endif // GODOT_CLASS_DB_HPP

View File

@@ -0,0 +1,130 @@
/**************************************************************************/
/* defs.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_DEFS_HPP
#define GODOT_DEFS_HPP
#include <cstddef>
#include <cstdint>
#include <cstring>
#if !defined(GDE_EXPORT)
#if defined(_WIN32)
#define GDE_EXPORT __declspec(dllexport)
#elif defined(__GNUC__)
#define GDE_EXPORT __attribute__((visibility("default")))
#else
#define GDE_EXPORT
#endif
#endif
// Turn argument to string constant:
// https://gcc.gnu.org/onlinedocs/cpp/Stringizing.html#Stringizing
#ifndef _STR
#define _STR(m_x) #m_x
#define _MKSTR(m_x) _STR(m_x)
#endif
// Should always inline no matter what.
#ifndef _ALWAYS_INLINE_
#if defined(__GNUC__)
#define _ALWAYS_INLINE_ __attribute__((always_inline)) inline
#elif defined(_MSC_VER)
#define _ALWAYS_INLINE_ __forceinline
#else
#define _ALWAYS_INLINE_ inline
#endif
#endif
// Should always inline, except in debug builds because it makes debugging harder.
#ifndef _FORCE_INLINE_
#ifdef DISABLE_FORCED_INLINE
#define _FORCE_INLINE_ inline
#else
#define _FORCE_INLINE_ _ALWAYS_INLINE_
#endif
#endif
#ifndef _NO_DISCARD_
#define _NO_DISCARD_ [[nodiscard]]
#endif
// Windows badly defines a lot of stuff we'll never use. Undefine it.
#ifdef _WIN32
#undef min // override standard definition
#undef max // override standard definition
#undef ERROR // override (really stupid) wingdi.h standard definition
#undef DELETE // override (another really stupid) winnt.h standard definition
#undef MessageBox // override winuser.h standard definition
#undef MIN // override standard definition
#undef MAX // override standard definition
#undef CLAMP // override standard definition
#undef Error
#undef OK
#undef CONNECT_DEFERRED // override from Windows SDK, clashes with Object enum
#endif
#if defined(__GNUC__)
#define likely(x) __builtin_expect(!!(x), 1)
#define unlikely(x) __builtin_expect(!!(x), 0)
#else
#define likely(x) x
#define unlikely(x) x
#endif
#ifdef REAL_T_IS_DOUBLE
typedef double real_t;
#else
typedef float real_t;
#endif
// Generic swap template.
#ifndef SWAP
#define SWAP(m_x, m_y) __swap_tmpl((m_x), (m_y))
template <class T>
inline void __swap_tmpl(T &x, T &y) {
T aux = x;
x = y;
y = aux;
}
#endif // SWAP
// Home-made index sequence trick, so it can be used everywhere without the costly include of std::tuple.
// https://stackoverflow.com/questions/15014096/c-index-of-type-during-variadic-template-expansion
template <size_t... Is>
struct IndexSequence {};
template <size_t N, size_t... Is>
struct BuildIndexSequence : BuildIndexSequence<N - 1, N - 1, Is...> {};
template <size_t... Is>
struct BuildIndexSequence<0, Is...> : IndexSequence<Is...> {};
#endif // GODOT_DEFS_HPP

View File

@@ -0,0 +1,97 @@
/**************************************************************************/
/* engine_ptrcall.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_ENGINE_PTRCALL_HPP
#define GODOT_ENGINE_PTRCALL_HPP
#include <gdextension_interface.h>
#include <godot_cpp/core/binder_common.hpp>
#include <godot_cpp/core/object.hpp>
#include <godot_cpp/godot.hpp>
#include <array>
namespace godot {
namespace internal {
template <class O, class... Args>
O *_call_native_mb_ret_obj(const GDExtensionMethodBindPtr mb, void *instance, const Args &...args) {
GodotObject *ret = nullptr;
std::array<GDExtensionConstTypePtr, sizeof...(Args)> mb_args = { { (GDExtensionConstTypePtr)args... } };
internal::gdextension_interface_object_method_bind_ptrcall(mb, instance, mb_args.data(), &ret);
if (ret == nullptr) {
return nullptr;
}
return reinterpret_cast<O *>(internal::get_object_instance_binding(ret));
}
template <class R, class... Args>
R _call_native_mb_ret(const GDExtensionMethodBindPtr mb, void *instance, const Args &...args) {
R ret;
std::array<GDExtensionConstTypePtr, sizeof...(Args)> mb_args = { { (GDExtensionConstTypePtr)args... } };
internal::gdextension_interface_object_method_bind_ptrcall(mb, instance, mb_args.data(), &ret);
return ret;
}
template <class... Args>
void _call_native_mb_no_ret(const GDExtensionMethodBindPtr mb, void *instance, const Args &...args) {
std::array<GDExtensionConstTypePtr, sizeof...(Args)> mb_args = { { (GDExtensionConstTypePtr)args... } };
internal::gdextension_interface_object_method_bind_ptrcall(mb, instance, mb_args.data(), nullptr);
}
template <class R, class... Args>
R _call_utility_ret(GDExtensionPtrUtilityFunction func, const Args &...args) {
R ret;
std::array<GDExtensionConstTypePtr, sizeof...(Args)> mb_args = { { (GDExtensionConstTypePtr)args... } };
func(&ret, mb_args.data(), mb_args.size());
return ret;
}
template <class... Args>
Object *_call_utility_ret_obj(const GDExtensionPtrUtilityFunction func, void *instance, const Args &...args) {
GodotObject *ret = nullptr;
std::array<GDExtensionConstTypePtr, sizeof...(Args)> mb_args = { { (GDExtensionConstTypePtr)args... } };
func(&ret, mb_args.data(), mb_args.size());
return (Object *)internal::get_object_instance_binding(ret);
}
template <class... Args>
void _call_utility_no_ret(const GDExtensionPtrUtilityFunction func, const Args &...args) {
std::array<GDExtensionConstTypePtr, sizeof...(Args)> mb_args = { { (GDExtensionConstTypePtr)args... } };
func(nullptr, mb_args.data(), mb_args.size());
}
} // namespace internal
} // namespace godot
#endif // GODOT_ENGINE_PTRCALL_HPP

View File

@@ -0,0 +1,806 @@
/**************************************************************************/
/* error_macros.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_ERROR_MACROS_HPP
#define GODOT_ERROR_MACROS_HPP
#include <godot_cpp/core/defs.hpp>
#include <atomic>
namespace godot {
class String;
void _err_print_error(const char *p_function, const char *p_file, int p_line, const char *p_error, bool p_editor_notify = false, bool p_is_warning = false);
void _err_print_error(const char *p_function, const char *p_file, int p_line, const String &p_error, bool p_editor_notify = false, bool p_is_warning = false);
void _err_print_error(const char *p_function, const char *p_file, int p_line, const char *p_error, const char *p_message, bool p_editor_notify = false, bool p_is_warning = false);
void _err_print_error(const char *p_function, const char *p_file, int p_line, const String &p_error, const char *p_message, bool p_editor_notify = false, bool p_is_warning = false);
void _err_print_error(const char *p_function, const char *p_file, int p_line, const char *p_error, const String &p_message, bool p_editor_notify = false, bool p_is_warning = false);
void _err_print_error(const char *p_function, const char *p_file, int p_line, const String &p_error, const String &p_message, bool p_editor_notify = false, bool p_is_warning = false);
void _err_print_index_error(const char *p_function, const char *p_file, int p_line, int64_t p_index, int64_t p_size, const char *p_index_str, const char *p_size_str, const char *p_message = "", bool p_editor_notify = false, bool p_fatal = false);
void _err_print_index_error(const char *p_function, const char *p_file, int p_line, int64_t p_index, int64_t p_size, const char *p_index_str, const char *p_size_str, const String &p_message, bool p_editor_notify = false, bool p_fatal = false);
void _err_flush_stdout();
} // namespace godot
#ifdef __GNUC__
#define FUNCTION_STR __FUNCTION__
#else
#define FUNCTION_STR __FUNCTION__
#endif
#ifdef _MSC_VER
/**
* Don't use GENERATE_TRAP() directly, should only be used be the macros below.
*/
#define GENERATE_TRAP() __debugbreak()
#else
/**
* Don't use GENERATE_TRAP() directly, should only be used be the macros below.
*/
#define GENERATE_TRAP() __builtin_trap()
#endif
/**
* Error macros.
* WARNING: These macros work in the opposite way to assert().
*
* Unlike exceptions and asserts, these macros try to maintain consistency and stability.
* In most cases, bugs and/or invalid data are not fatal. They should never allow a perfectly
* running application to fail or crash.
* Always try to return processable data, so the engine can keep running well.
* Use the _MSG versions to print a meaningful message to help with debugging.
*
* The `((void)0)` no-op statement is used as a trick to force us to put a semicolon after
* those macros, making them look like proper statements.
* The if wrappers are used to ensure that the macro replacement does not trigger unexpected
* issues when expanded e.g. after an `if (cond) ERR_FAIL();` without braces.
*/
// Index out of bounds error macros.
// These macros should be used instead of `ERR_FAIL_COND` for bounds checking.
// Integer index out of bounds error macros.
/**
* Try using `ERR_FAIL_INDEX_MSG`.
* Only use this macro if there is no sensible error message.
*
* Ensures an integer index `m_index` is less than `m_size` and greater than or equal to 0.
* If not, the current function returns.
*/
#define ERR_FAIL_INDEX(m_index, m_size) \
if (unlikely((m_index) < 0 || (m_index) >= (m_size))) { \
::godot::_err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size)); \
return; \
} else \
((void)0)
/**
* Ensures an integer index `m_index` is less than `m_size` and greater than or equal to 0.
* If not, prints `m_msg` and the current function returns.
*/
#define ERR_FAIL_INDEX_MSG(m_index, m_size, m_msg) \
if (unlikely((m_index) < 0 || (m_index) >= (m_size))) { \
::godot::_err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size), m_msg); \
return; \
} else \
((void)0)
/**
* Same as `ERR_FAIL_INDEX_MSG` but also notifies the editor.
*/
#define ERR_FAIL_INDEX_EDMSG(m_index, m_size, m_msg) \
if (unlikely((m_index) < 0 || (m_index) >= (m_size))) { \
::godot::_err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size), m_msg, true); \
return; \
} else \
((void)0)
/**
* Try using `ERR_FAIL_INDEX_V_MSG`.
* Only use this macro if there is no sensible error message.
*
* Ensures an integer index `m_index` is less than `m_size` and greater than or equal to 0.
* If not, the current function returns `m_retval`.
*/
#define ERR_FAIL_INDEX_V(m_index, m_size, m_retval) \
if (unlikely((m_index) < 0 || (m_index) >= (m_size))) { \
::godot::_err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size)); \
return m_retval; \
} else \
((void)0)
/**
* Ensures an integer index `m_index` is less than `m_size` and greater than or equal to 0.
* If not, prints `m_msg` and the current function returns `m_retval`.
*/
#define ERR_FAIL_INDEX_V_MSG(m_index, m_size, m_retval, m_msg) \
if (unlikely((m_index) < 0 || (m_index) >= (m_size))) { \
::godot::_err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size), m_msg); \
return m_retval; \
} else \
((void)0)
/**
* Same as `ERR_FAIL_INDEX_V_MSG` but also notifies the editor.
*/
#define ERR_FAIL_INDEX_V_EDMSG(m_index, m_size, m_retval, m_msg) \
if (unlikely((m_index) < 0 || (m_index) >= (m_size))) { \
::godot::_err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size), m_msg, true); \
return m_retval; \
} else \
((void)0)
/**
* Try using `ERR_FAIL_INDEX_MSG` or `ERR_FAIL_INDEX_V_MSG`.
* Only use this macro if there is no sensible fallback i.e. the error is unrecoverable, and
* there is no sensible error message.
*
* Ensures an integer index `m_index` is less than `m_size` and greater than or equal to 0.
* If not, the application crashes.
*/
#define CRASH_BAD_INDEX(m_index, m_size) \
if (unlikely((m_index) < 0 || (m_index) >= (m_size))) { \
::godot::_err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size), "", false, true); \
::godot::_err_flush_stdout(); \
GENERATE_TRAP(); \
} else \
((void)0)
/**
* Try using `ERR_FAIL_INDEX_MSG` or `ERR_FAIL_INDEX_V_MSG`.
* Only use this macro if there is no sensible fallback i.e. the error is unrecoverable.
*
* Ensures an integer index `m_index` is less than `m_size` and greater than or equal to 0.
* If not, prints `m_msg` and the application crashes.
*/
#define CRASH_BAD_INDEX_MSG(m_index, m_size, m_msg) \
if (unlikely((m_index) < 0 || (m_index) >= (m_size))) { \
::godot::_err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size), m_msg, false, true); \
::godot::_err_flush_stdout(); \
GENERATE_TRAP(); \
} else \
((void)0)
// Unsigned integer index out of bounds error macros.
/**
* Try using `ERR_FAIL_UNSIGNED_INDEX_MSG`.
* Only use this macro if there is no sensible error message.
*
* Ensures an unsigned integer index `m_index` is less than `m_size`.
* If not, the current function returns.
*/
#define ERR_FAIL_UNSIGNED_INDEX(m_index, m_size) \
if (unlikely((m_index) >= (m_size))) { \
::godot::_err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size)); \
return; \
} else \
((void)0)
/**
* Ensures an unsigned integer index `m_index` is less than `m_size`.
* If not, prints `m_msg` and the current function returns.
*/
#define ERR_FAIL_UNSIGNED_INDEX_MSG(m_index, m_size, m_msg) \
if (unlikely((m_index) >= (m_size))) { \
::godot::_err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size), m_msg); \
return; \
} else \
((void)0)
/**
* Same as `ERR_FAIL_UNSIGNED_INDEX_MSG` but also notifies the editor.
*/
#define ERR_FAIL_UNSIGNED_INDEX_EDMSG(m_index, m_size, m_msg) \
if (unlikely((m_index) >= (m_size))) { \
::godot::_err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size), m_msg, true); \
return; \
} else \
((void)0)
/**
* Try using `ERR_FAIL_UNSIGNED_INDEX_V_MSG`.
* Only use this macro if there is no sensible error message.
*
* Ensures an unsigned integer index `m_index` is less than `m_size`.
* If not, the current function returns `m_retval`.
*/
#define ERR_FAIL_UNSIGNED_INDEX_V(m_index, m_size, m_retval) \
if (unlikely((m_index) >= (m_size))) { \
::godot::_err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size)); \
return m_retval; \
} else \
((void)0)
/**
* Ensures an unsigned integer index `m_index` is less than `m_size`.
* If not, prints `m_msg` and the current function returns `m_retval`.
*/
#define ERR_FAIL_UNSIGNED_INDEX_V_MSG(m_index, m_size, m_retval, m_msg) \
if (unlikely((m_index) >= (m_size))) { \
::godot::_err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size), m_msg); \
return m_retval; \
} else \
((void)0)
/**
* Same as `ERR_FAIL_UNSIGNED_INDEX_V_EDMSG` but also notifies the editor.
*/
#define ERR_FAIL_UNSIGNED_INDEX_V_EDMSG(m_index, m_size, m_retval, m_msg) \
if (unlikely((m_index) >= (m_size))) { \
::godot::_err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size), m_msg, true); \
return m_retval; \
} else \
((void)0)
/**
* Try using `ERR_FAIL_UNSIGNED_INDEX_MSG` or `ERR_FAIL_UNSIGNED_INDEX_V_MSG`.
* Only use this macro if there is no sensible fallback i.e. the error is unrecoverable, and
* there is no sensible error message.
*
* Ensures an unsigned integer index `m_index` is less than `m_size`.
* If not, the application crashes.
*/
#define CRASH_BAD_UNSIGNED_INDEX(m_index, m_size) \
if (unlikely((m_index) >= (m_size))) { \
::godot::_err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size), "", false, true); \
::godot::_err_flush_stdout(); \
GENERATE_TRAP(); \
} else \
((void)0)
/**
* Try using `ERR_FAIL_UNSIGNED_INDEX_MSG` or `ERR_FAIL_UNSIGNED_INDEX_V_MSG`.
* Only use this macro if there is no sensible fallback i.e. the error is unrecoverable.
*
* Ensures an unsigned integer index `m_index` is less than `m_size`.
* If not, prints `m_msg` and the application crashes.
*/
#define CRASH_BAD_UNSIGNED_INDEX_MSG(m_index, m_size, m_msg) \
if (unlikely((m_index) >= (m_size))) { \
::godot::_err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size), m_msg, false, true); \
::godot::_err_flush_stdout(); \
GENERATE_TRAP(); \
} else \
((void)0)
// Null reference error macros.
/**
* Try using `ERR_FAIL_NULL_MSG`.
* Only use this macro if there is no sensible error message.
*
* Ensures a pointer `m_param` is not null.
* If it is null, the current function returns.
*/
#define ERR_FAIL_NULL(m_param) \
if (unlikely(m_param == nullptr)) { \
::godot::_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Parameter \"" _STR(m_param) "\" is null."); \
return; \
} else \
((void)0)
/**
* Ensures a pointer `m_param` is not null.
* If it is null, prints `m_msg` and the current function returns.
*/
#define ERR_FAIL_NULL_MSG(m_param, m_msg) \
if (unlikely(m_param == nullptr)) { \
::godot::_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Parameter \"" _STR(m_param) "\" is null.", m_msg); \
return; \
} else \
((void)0)
/**
* Same as `ERR_FAIL_NULL_MSG` but also notifies the editor.
*/
#define ERR_FAIL_NULL_EDMSG(m_param, m_msg) \
if (unlikely(m_param == nullptr)) { \
::godot::_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Parameter \"" _STR(m_param) "\" is null.", m_msg, true); \
return; \
} else \
((void)0)
/**
* Try using `ERR_FAIL_NULL_V_MSG`.
* Only use this macro if there is no sensible error message.
*
* Ensures a pointer `m_param` is not null.
* If it is null, the current function returns `m_retval`.
*/
#define ERR_FAIL_NULL_V(m_param, m_retval) \
if (unlikely(m_param == nullptr)) { \
::godot::_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Parameter \"" _STR(m_param) "\" is null."); \
return m_retval; \
} else \
((void)0)
/**
* Ensures a pointer `m_param` is not null.
* If it is null, prints `m_msg` and the current function returns `m_retval`.
*/
#define ERR_FAIL_NULL_V_MSG(m_param, m_retval, m_msg) \
if (unlikely(m_param == nullptr)) { \
::godot::_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Parameter \"" _STR(m_param) "\" is null.", m_msg); \
return m_retval; \
} else \
((void)0)
/**
* Same as `ERR_FAIL_NULL_V_MSG` but also notifies the editor.
*/
#define ERR_FAIL_NULL_V_EDMSG(m_param, m_retval, m_msg) \
if (unlikely(m_param == nullptr)) { \
::godot::_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Parameter \"" _STR(m_param) "\" is null.", m_msg, true); \
return m_retval; \
} else \
((void)0)
/**
* Try using `ERR_FAIL_COND_MSG`.
* Only use this macro if there is no sensible error message.
* If checking for null use ERR_FAIL_NULL_MSG instead.
* If checking index bounds use ERR_FAIL_INDEX_MSG instead.
*
* Ensures `m_cond` is false.
* If `m_cond` is true, the current function returns.
*/
#define ERR_FAIL_COND(m_cond) \
if (unlikely(m_cond)) { \
::godot::_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Condition \"" _STR(m_cond) "\" is true."); \
return; \
} else \
((void)0)
/**
* Ensures `m_cond` is false.
* If `m_cond` is true, prints `m_msg` and the current function returns.
*
* If checking for null use ERR_FAIL_NULL_MSG instead.
* If checking index bounds use ERR_FAIL_INDEX_MSG instead.
*/
#define ERR_FAIL_COND_MSG(m_cond, m_msg) \
if (unlikely(m_cond)) { \
::godot::_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Condition \"" _STR(m_cond) "\" is true.", m_msg); \
return; \
} else \
((void)0)
/**
* Same as `ERR_FAIL_COND_MSG` but also notifies the editor.
*/
#define ERR_FAIL_COND_EDMSG(m_cond, m_msg) \
if (unlikely(m_cond)) { \
::godot::_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Condition \"" _STR(m_cond) "\" is true.", m_msg, true); \
return; \
} else \
((void)0)
/**
* Try using `ERR_FAIL_COND_V_MSG`.
* Only use this macro if there is no sensible error message.
* If checking for null use ERR_FAIL_NULL_V_MSG instead.
* If checking index bounds use ERR_FAIL_INDEX_V_MSG instead.
*
* Ensures `m_cond` is false.
* If `m_cond` is true, the current function returns `m_retval`.
*/
#define ERR_FAIL_COND_V(m_cond, m_retval) \
if (unlikely(m_cond)) { \
::godot::_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Condition \"" _STR(m_cond) "\" is true. Returning: " _STR(m_retval)); \
return m_retval; \
} else \
((void)0)
/**
* Ensures `m_cond` is false.
* If `m_cond` is true, prints `m_msg` and the current function returns `m_retval`.
*
* If checking for null use ERR_FAIL_NULL_V_MSG instead.
* If checking index bounds use ERR_FAIL_INDEX_V_MSG instead.
*/
#define ERR_FAIL_COND_V_MSG(m_cond, m_retval, m_msg) \
if (unlikely(m_cond)) { \
::godot::_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Condition \"" _STR(m_cond) "\" is true. Returning: " _STR(m_retval), m_msg); \
return m_retval; \
} else \
((void)0)
/**
* Same as `ERR_FAIL_COND_V_MSG` but also notifies the editor.
*/
#define ERR_FAIL_COND_V_EDMSG(m_cond, m_retval, m_msg) \
if (unlikely(m_cond)) { \
::godot::_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Condition \"" _STR(m_cond) "\" is true. Returning: " _STR(m_retval), m_msg, true); \
return m_retval; \
} else \
((void)0)
/**
* Try using `ERR_CONTINUE_MSG`.
* Only use this macro if there is no sensible error message.
*
* Ensures `m_cond` is false.
* If `m_cond` is true, the current loop continues.
*/
#define ERR_CONTINUE(m_cond) \
if (unlikely(m_cond)) { \
::godot::_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Condition \"" _STR(m_cond) "\" is true. Continuing."); \
continue; \
} else \
((void)0)
/**
* Ensures `m_cond` is false.
* If `m_cond` is true, prints `m_msg` and the current loop continues.
*/
#define ERR_CONTINUE_MSG(m_cond, m_msg) \
if (unlikely(m_cond)) { \
::godot::_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Condition \"" _STR(m_cond) "\" is true. Continuing.", m_msg); \
continue; \
} else \
((void)0)
/**
* Same as `ERR_CONTINUE_MSG` but also notifies the editor.
*/
#define ERR_CONTINUE_EDMSG(m_cond, m_msg) \
if (unlikely(m_cond)) { \
::godot::_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Condition \"" _STR(m_cond) "\" is true. Continuing.", m_msg, true); \
continue; \
} else \
((void)0)
/**
* Try using `ERR_BREAK_MSG`.
* Only use this macro if there is no sensible error message.
*
* Ensures `m_cond` is false.
* If `m_cond` is true, the current loop breaks.
*/
#define ERR_BREAK(m_cond) \
if (unlikely(m_cond)) { \
::godot::_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Condition \"" _STR(m_cond) "\" is true. Breaking."); \
break; \
} else \
((void)0)
/**
* Ensures `m_cond` is false.
* If `m_cond` is true, prints `m_msg` and the current loop breaks.
*/
#define ERR_BREAK_MSG(m_cond, m_msg) \
if (unlikely(m_cond)) { \
::godot::_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Condition \"" _STR(m_cond) "\" is true. Breaking.", m_msg); \
break; \
} else \
((void)0)
/**
* Same as `ERR_BREAK_MSG` but also notifies the editor.
*/
#define ERR_BREAK_EDMSG(m_cond, m_msg) \
if (unlikely(m_cond)) { \
::godot::_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Condition \"" _STR(m_cond) "\" is true. Breaking.", m_msg, true); \
break; \
} else \
((void)0)
/**
* Try using `ERR_FAIL_COND_MSG` or `ERR_FAIL_COND_V_MSG`.
* Only use this macro if there is no sensible fallback i.e. the error is unrecoverable, and
* there is no sensible error message.
*
* Ensures `m_cond` is false.
* If `m_cond` is true, the application crashes.
*/
#define CRASH_COND(m_cond) \
if (unlikely(m_cond)) { \
::godot::_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "FATAL: Condition \"" _STR(m_cond) "\" is true."); \
::godot::_err_flush_stdout(); \
GENERATE_TRAP(); \
} else \
((void)0)
/**
* Try using `ERR_FAIL_COND_MSG` or `ERR_FAIL_COND_V_MSG`.
* Only use this macro if there is no sensible fallback i.e. the error is unrecoverable.
*
* Ensures `m_cond` is false.
* If `m_cond` is true, prints `m_msg` and the application crashes.
*/
#define CRASH_COND_MSG(m_cond, m_msg) \
if (unlikely(m_cond)) { \
::godot::_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "FATAL: Condition \"" _STR(m_cond) "\" is true.", m_msg); \
::godot::_err_flush_stdout(); \
GENERATE_TRAP(); \
} else \
((void)0)
// Generic error macros.
/**
* Try using `ERR_FAIL_COND_MSG` or `ERR_FAIL_MSG`.
* Only use this macro if more complex error detection or recovery is required, and
* there is no sensible error message.
*
* The current function returns.
*/
#define ERR_FAIL() \
if (true) { \
::godot::_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Method/function failed."); \
return; \
} else \
((void)0)
/**
* Try using `ERR_FAIL_COND_MSG`.
* Only use this macro if more complex error detection or recovery is required.
*
* Prints `m_msg`, and the current function returns.
*/
#define ERR_FAIL_MSG(m_msg) \
if (true) { \
::godot::_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Method/function failed.", m_msg); \
return; \
} else \
((void)0)
/**
* Same as `ERR_FAIL_MSG` but also notifies the editor.
*/
#define ERR_FAIL_EDMSG(m_msg) \
if (true) { \
::godot::_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Method/function failed.", m_msg, true); \
return; \
} else \
((void)0)
/**
* Try using `ERR_FAIL_COND_V_MSG` or `ERR_FAIL_V_MSG`.
* Only use this macro if more complex error detection or recovery is required, and
* there is no sensible error message.
*
* The current function returns `m_retval`.
*/
#define ERR_FAIL_V(m_retval) \
if (true) { \
::godot::_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Method/function failed. Returning: " _STR(m_retval)); \
return m_retval; \
} else \
((void)0)
/**
* Try using `ERR_FAIL_COND_V_MSG`.
* Only use this macro if more complex error detection or recovery is required.
*
* Prints `m_msg`, and the current function returns `m_retval`.
*/
#define ERR_FAIL_V_MSG(m_retval, m_msg) \
if (true) { \
::godot::_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Method/function failed. Returning: " _STR(m_retval), m_msg); \
return m_retval; \
} else \
((void)0)
/**
* Same as `ERR_FAIL_V_MSG` but also notifies the editor.
*/
#define ERR_FAIL_V_EDMSG(m_retval, m_msg) \
if (true) { \
::godot::_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Method/function failed. Returning: " _STR(m_retval), m_msg, true); \
return m_retval; \
} else \
((void)0)
/**
* Try using `ERR_FAIL_COND_MSG`, `ERR_FAIL_COND_V_MSG`, `ERR_CONTINUE_MSG` or `ERR_BREAK_MSG`.
* Only use this macro at the start of a function that has not been implemented yet, or
* if more complex error detection or recovery is required.
*
* Prints `m_msg`.
*/
#define ERR_PRINT(m_msg) \
::godot::_err_print_error(FUNCTION_STR, __FILE__, __LINE__, m_msg)
/**
* Same as `ERR_PRINT` but also notifies the editor.
*/
#define ERR_PRINT_ED(m_msg) \
::godot::_err_print_error(FUNCTION_STR, __FILE__, __LINE__, m_msg, true)
/**
* Prints `m_msg` once during the application lifetime.
*/
#define ERR_PRINT_ONCE(m_msg) \
if (true) { \
static bool first_print = true; \
if (first_print) { \
::godot::_err_print_error(FUNCTION_STR, __FILE__, __LINE__, m_msg); \
first_print = false; \
} \
} else \
((void)0)
/**
* Same as `ERR_PRINT_ONCE` but also notifies the editor.
*/
#define ERR_PRINT_ONCE_ED(m_msg) \
if (true) { \
static bool first_print = true; \
if (first_print) { \
::godot::_err_print_error(FUNCTION_STR, __FILE__, __LINE__, m_msg, true); \
first_print = false; \
} \
} else \
((void)0)
// Print warning message macros.
/**
* Prints `m_msg`.
*
* If warning about deprecated usage, use `WARN_DEPRECATED` or `WARN_DEPRECATED_MSG` instead.
*/
#define WARN_PRINT(m_msg) \
::godot::_err_print_error(FUNCTION_STR, __FILE__, __LINE__, m_msg, false, true)
/**
* Same as `WARN_PRINT` but also notifies the editor.
*/
#define WARN_PRINT_ED(m_msg) \
::godot::_err_print_error(FUNCTION_STR, __FILE__, __LINE__, m_msg, true, true)
/**
* Prints `m_msg` once during the application lifetime.
*
* If warning about deprecated usage, use `WARN_DEPRECATED` or `WARN_DEPRECATED_MSG` instead.
*/
#define WARN_PRINT_ONCE(m_msg) \
if (true) { \
static bool first_print = true; \
if (first_print) { \
::godot::_err_print_error(FUNCTION_STR, __FILE__, __LINE__, m_msg, false, true); \
first_print = false; \
} \
} else \
((void)0)
/**
* Same as `WARN_PRINT_ONCE` but also notifies the editor.
*/
#define WARN_PRINT_ONCE_ED(m_msg) \
if (true) { \
static bool first_print = true; \
if (first_print) { \
::godot::_err_print_error(FUNCTION_STR, __FILE__, __LINE__, m_msg, true, true); \
first_print = false; \
} \
} else \
((void)0)
// Print deprecated warning message macros.
/**
* Warns that the current function is deprecated.
*/
#define WARN_DEPRECATED \
if (true) { \
static std::atomic<bool> warning_shown; \
if (!warning_shown.load()) { \
::godot::_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "This method has been deprecated and will be removed in the future.", false, true); \
warning_shown.store(true); \
} \
} else \
((void)0)
/**
* Warns that the current function is deprecated and prints `m_msg`.
*/
#define WARN_DEPRECATED_MSG(m_msg) \
if (true) { \
static std::atomic<bool> warning_shown; \
if (!warning_shown.load()) { \
::godot::_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "This method has been deprecated and will be removed in the future.", m_msg, false, true); \
warning_shown.store(true); \
} \
} else \
((void)0)
/**
* Do not use.
* If the application should never reach this point use CRASH_NOW_MSG(m_msg) to explain why.
*
* The application crashes.
*/
#define CRASH_NOW() \
if (true) { \
::godot::_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "FATAL: Method/function failed."); \
::godot::_err_flush_stdout(); \
GENERATE_TRAP(); \
} else \
((void)0)
/**
* Only use if the application should never reach this point.
*
* Prints `m_msg`, and then the application crashes.
*/
#define CRASH_NOW_MSG(m_msg) \
if (true) { \
::godot::_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "FATAL: Method/function failed.", m_msg); \
::godot::_err_flush_stdout(); \
GENERATE_TRAP(); \
} else \
((void)0)
/**
* This should be a 'free' assert for program flow and should not be needed in any releases,
* only used in dev builds.
*/
#ifdef DEBUG_ENABLED
#define DEV_ASSERT(m_cond) \
if (unlikely(!(m_cond))) { \
::godot::_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "FATAL: DEV_ASSERT failed \"" _STR(m_cond) "\" is false."); \
::godot::_err_flush_stdout(); \
GENERATE_TRAP(); \
} else \
((void)0)
#else
#define DEV_ASSERT(m_cond)
#endif
/**
* Gives an error message when a method bind is invalid (likely the hash changed).
* Avoids crashing the application in this case. It's not free, so it's debug only.
*/
#ifdef DEBUG_ENABLED
#define CHECK_METHOD_BIND_RET(m_mb, m_ret) \
if (unlikely(!m_mb)) { \
ERR_PRINT_ONCE("Method bind was not found. Likely the engine method changed to an incompatible version."); \
return m_ret; \
} else \
((void)0)
#define CHECK_METHOD_BIND(m_mb) \
if (unlikely(!m_mb)) { \
ERR_PRINT_ONCE("Method bind was not found. Likely the engine method changed to an incompatible version."); \
return; \
} else \
((void)0)
#else
#define CHECK_METHOD_BIND_RET(m_mb, m_ret)
#define CHECK_METHOD_BIND(m_mb)
#endif
#endif // GODOT_ERROR_MACROS_HPP

View File

@@ -0,0 +1,811 @@
/**************************************************************************/
/* math.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_MATH_HPP
#define GODOT_MATH_HPP
#include <godot_cpp/core/defs.hpp>
#include <gdextension_interface.h>
#include <cmath>
namespace godot {
#define Math_SQRT12 0.7071067811865475244008443621048490
#define Math_SQRT2 1.4142135623730950488016887242
#define Math_LN2 0.6931471805599453094172321215
#define Math_PI 3.1415926535897932384626433833
#define Math_TAU 6.2831853071795864769252867666
#define Math_E 2.7182818284590452353602874714
#define Math_INF INFINITY
#define Math_NAN NAN
// Make room for our constexpr's below by overriding potential system-specific macros.
#undef ABS
#undef SIGN
#undef MIN
#undef MAX
#undef CLAMP
// Generic ABS function, for math uses please use Math::abs.
template <typename T>
constexpr T ABS(T m_v) {
return m_v < 0 ? -m_v : m_v;
}
template <typename T>
constexpr const T SIGN(const T m_v) {
return m_v == 0 ? 0.0f : (m_v < 0 ? -1.0f : +1.0f);
}
template <typename T, typename T2>
constexpr auto MIN(const T m_a, const T2 m_b) {
return m_a < m_b ? m_a : m_b;
}
template <typename T, typename T2>
constexpr auto MAX(const T m_a, const T2 m_b) {
return m_a > m_b ? m_a : m_b;
}
template <typename T, typename T2, typename T3>
constexpr auto CLAMP(const T m_a, const T2 m_min, const T3 m_max) {
return m_a < m_min ? m_min : (m_a > m_max ? m_max : m_a);
}
// Generic swap template.
#ifndef SWAP
#define SWAP(m_x, m_y) __swap_tmpl((m_x), (m_y))
template <class T>
inline void __swap_tmpl(T &x, T &y) {
T aux = x;
x = y;
y = aux;
}
#endif // SWAP
/* Functions to handle powers of 2 and shifting. */
// Function to find the next power of 2 to an integer.
static _FORCE_INLINE_ unsigned int next_power_of_2(unsigned int x) {
if (x == 0) {
return 0;
}
--x;
x |= x >> 1;
x |= x >> 2;
x |= x >> 4;
x |= x >> 8;
x |= x >> 16;
return ++x;
}
// Function to find the previous power of 2 to an integer.
static _FORCE_INLINE_ unsigned int previous_power_of_2(unsigned int x) {
x |= x >> 1;
x |= x >> 2;
x |= x >> 4;
x |= x >> 8;
x |= x >> 16;
return x - (x >> 1);
}
// Function to find the closest power of 2 to an integer.
static _FORCE_INLINE_ unsigned int closest_power_of_2(unsigned int x) {
unsigned int nx = next_power_of_2(x);
unsigned int px = previous_power_of_2(x);
return (nx - x) > (x - px) ? px : nx;
}
// Get a shift value from a power of 2.
static inline int get_shift_from_power_of_2(unsigned int p_bits) {
for (unsigned int i = 0; i < 32; i++) {
if (p_bits == (unsigned int)(1 << i)) {
return i;
}
}
return -1;
}
template <class T>
static _FORCE_INLINE_ T nearest_power_of_2_templated(T x) {
--x;
// The number of operations on x is the base two logarithm
// of the number of bits in the type. Add three to account
// for sizeof(T) being in bytes.
size_t num = get_shift_from_power_of_2(sizeof(T)) + 3;
// If the compiler is smart, it unrolls this loop.
// If it's dumb, this is a bit slow.
for (size_t i = 0; i < num; i++) {
x |= x >> (1 << i);
}
return ++x;
}
// Function to find the nearest (bigger) power of 2 to an integer.
static inline unsigned int nearest_shift(unsigned int p_number) {
for (int i = 30; i >= 0; i--) {
if (p_number & (1 << i)) {
return i + 1;
}
}
return 0;
}
// constexpr function to find the floored log2 of a number
template <typename T>
constexpr T floor_log2(T x) {
return x < 2 ? x : 1 + floor_log2(x >> 1);
}
// Get the number of bits needed to represent the number.
// IE, if you pass in 8, you will get 4.
// If you want to know how many bits are needed to store 8 values however, pass in (8 - 1).
template <typename T>
constexpr T get_num_bits(T x) {
return floor_log2(x);
}
// Swap 16, 32 and 64 bits value for endianness.
#if defined(__GNUC__)
#define BSWAP16(x) __builtin_bswap16(x)
#define BSWAP32(x) __builtin_bswap32(x)
#define BSWAP64(x) __builtin_bswap64(x)
#else
static inline uint16_t BSWAP16(uint16_t x) {
return (x >> 8) | (x << 8);
}
static inline uint32_t BSWAP32(uint32_t x) {
return ((x << 24) | ((x << 8) & 0x00FF0000) | ((x >> 8) & 0x0000FF00) | (x >> 24));
}
static inline uint64_t BSWAP64(uint64_t x) {
x = (x & 0x00000000FFFFFFFF) << 32 | (x & 0xFFFFFFFF00000000) >> 32;
x = (x & 0x0000FFFF0000FFFF) << 16 | (x & 0xFFFF0000FFFF0000) >> 16;
x = (x & 0x00FF00FF00FF00FF) << 8 | (x & 0xFF00FF00FF00FF00) >> 8;
return x;
}
#endif
namespace Math {
// This epsilon should match the one used by Godot for consistency.
// Using `f` when `real_t` is float.
#define CMP_EPSILON 0.00001f
#define CMP_EPSILON2 (CMP_EPSILON * CMP_EPSILON)
// This epsilon is for values related to a unit size (scalar or vector len).
#ifdef PRECISE_MATH_CHECKS
#define UNIT_EPSILON 0.00001
#else
// Tolerate some more floating point error normally.
#define UNIT_EPSILON 0.001
#endif
// Functions reproduced as in Godot's source code `math_funcs.h`.
// Some are overloads to automatically support changing real_t into either double or float in the way Godot does.
inline double fmod(double p_x, double p_y) {
return ::fmod(p_x, p_y);
}
inline float fmod(float p_x, float p_y) {
return ::fmodf(p_x, p_y);
}
inline double fposmod(double p_x, double p_y) {
double value = Math::fmod(p_x, p_y);
if ((value < 0 && p_y > 0) || (value > 0 && p_y < 0)) {
value += p_y;
}
value += 0.0;
return value;
}
inline float fposmod(float p_x, float p_y) {
float value = Math::fmod(p_x, p_y);
if ((value < 0 && p_y > 0) || (value > 0 && p_y < 0)) {
value += p_y;
}
value += 0.0f;
return value;
}
inline float fposmodp(float p_x, float p_y) {
float value = Math::fmod(p_x, p_y);
if (value < 0) {
value += p_y;
}
value += 0.0f;
return value;
}
inline double fposmodp(double p_x, double p_y) {
double value = Math::fmod(p_x, p_y);
if (value < 0) {
value += p_y;
}
value += 0.0;
return value;
}
inline int64_t posmod(int64_t p_x, int64_t p_y) {
int64_t value = p_x % p_y;
if ((value < 0 && p_y > 0) || (value > 0 && p_y < 0)) {
value += p_y;
}
return value;
}
inline double floor(double p_x) {
return ::floor(p_x);
}
inline float floor(float p_x) {
return ::floorf(p_x);
}
inline double ceil(double p_x) {
return ::ceil(p_x);
}
inline float ceil(float p_x) {
return ::ceilf(p_x);
}
inline double exp(double p_x) {
return ::exp(p_x);
}
inline float exp(float p_x) {
return ::expf(p_x);
}
inline double sin(double p_x) {
return ::sin(p_x);
}
inline float sin(float p_x) {
return ::sinf(p_x);
}
inline double cos(double p_x) {
return ::cos(p_x);
}
inline float cos(float p_x) {
return ::cosf(p_x);
}
inline double tan(double p_x) {
return ::tan(p_x);
}
inline float tan(float p_x) {
return ::tanf(p_x);
}
inline double sinh(double p_x) {
return ::sinh(p_x);
}
inline float sinh(float p_x) {
return ::sinhf(p_x);
}
inline float sinc(float p_x) {
return p_x == 0 ? 1 : ::sin(p_x) / p_x;
}
inline double sinc(double p_x) {
return p_x == 0 ? 1 : ::sin(p_x) / p_x;
}
inline float sincn(float p_x) {
return (float)sinc(Math_PI * p_x);
}
inline double sincn(double p_x) {
return sinc(Math_PI * p_x);
}
inline double cosh(double p_x) {
return ::cosh(p_x);
}
inline float cosh(float p_x) {
return ::coshf(p_x);
}
inline double tanh(double p_x) {
return ::tanh(p_x);
}
inline float tanh(float p_x) {
return ::tanhf(p_x);
}
inline double asin(double p_x) {
return ::asin(p_x);
}
inline float asin(float p_x) {
return ::asinf(p_x);
}
inline double acos(double p_x) {
return ::acos(p_x);
}
inline float acos(float p_x) {
return ::acosf(p_x);
}
inline double atan(double p_x) {
return ::atan(p_x);
}
inline float atan(float p_x) {
return ::atanf(p_x);
}
inline double atan2(double p_y, double p_x) {
return ::atan2(p_y, p_x);
}
inline float atan2(float p_y, float p_x) {
return ::atan2f(p_y, p_x);
}
inline double sqrt(double p_x) {
return ::sqrt(p_x);
}
inline float sqrt(float p_x) {
return ::sqrtf(p_x);
}
inline double pow(double p_x, double p_y) {
return ::pow(p_x, p_y);
}
inline float pow(float p_x, float p_y) {
return ::powf(p_x, p_y);
}
inline double log(double p_x) {
return ::log(p_x);
}
inline float log(float p_x) {
return ::logf(p_x);
}
inline float lerp(float minv, float maxv, float t) {
return minv + t * (maxv - minv);
}
inline double lerp(double minv, double maxv, double t) {
return minv + t * (maxv - minv);
}
inline double lerp_angle(double p_from, double p_to, double p_weight) {
double difference = fmod(p_to - p_from, Math_TAU);
double distance = fmod(2.0 * difference, Math_TAU) - difference;
return p_from + distance * p_weight;
}
inline float lerp_angle(float p_from, float p_to, float p_weight) {
float difference = fmod(p_to - p_from, (float)Math_TAU);
float distance = fmod(2.0f * difference, (float)Math_TAU) - difference;
return p_from + distance * p_weight;
}
inline double cubic_interpolate(double p_from, double p_to, double p_pre, double p_post, double p_weight) {
return 0.5 *
((p_from * 2.0) +
(-p_pre + p_to) * p_weight +
(2.0 * p_pre - 5.0 * p_from + 4.0 * p_to - p_post) * (p_weight * p_weight) +
(-p_pre + 3.0 * p_from - 3.0 * p_to + p_post) * (p_weight * p_weight * p_weight));
}
inline float cubic_interpolate(float p_from, float p_to, float p_pre, float p_post, float p_weight) {
return 0.5f *
((p_from * 2.0f) +
(-p_pre + p_to) * p_weight +
(2.0f * p_pre - 5.0f * p_from + 4.0f * p_to - p_post) * (p_weight * p_weight) +
(-p_pre + 3.0f * p_from - 3.0f * p_to + p_post) * (p_weight * p_weight * p_weight));
}
inline double cubic_interpolate_angle(double p_from, double p_to, double p_pre, double p_post, double p_weight) {
double from_rot = fmod(p_from, Math_TAU);
double pre_diff = fmod(p_pre - from_rot, Math_TAU);
double pre_rot = from_rot + fmod(2.0 * pre_diff, Math_TAU) - pre_diff;
double to_diff = fmod(p_to - from_rot, Math_TAU);
double to_rot = from_rot + fmod(2.0 * to_diff, Math_TAU) - to_diff;
double post_diff = fmod(p_post - to_rot, Math_TAU);
double post_rot = to_rot + fmod(2.0 * post_diff, Math_TAU) - post_diff;
return cubic_interpolate(from_rot, to_rot, pre_rot, post_rot, p_weight);
}
inline float cubic_interpolate_angle(float p_from, float p_to, float p_pre, float p_post, float p_weight) {
float from_rot = fmod(p_from, (float)Math_TAU);
float pre_diff = fmod(p_pre - from_rot, (float)Math_TAU);
float pre_rot = from_rot + fmod(2.0f * pre_diff, (float)Math_TAU) - pre_diff;
float to_diff = fmod(p_to - from_rot, (float)Math_TAU);
float to_rot = from_rot + fmod(2.0f * to_diff, (float)Math_TAU) - to_diff;
float post_diff = fmod(p_post - to_rot, (float)Math_TAU);
float post_rot = to_rot + fmod(2.0f * post_diff, (float)Math_TAU) - post_diff;
return cubic_interpolate(from_rot, to_rot, pre_rot, post_rot, p_weight);
}
inline double cubic_interpolate_in_time(double p_from, double p_to, double p_pre, double p_post, double p_weight,
double p_to_t, double p_pre_t, double p_post_t) {
/* Barry-Goldman method */
double t = Math::lerp(0.0, p_to_t, p_weight);
double a1 = Math::lerp(p_pre, p_from, p_pre_t == 0 ? 0.0 : (t - p_pre_t) / -p_pre_t);
double a2 = Math::lerp(p_from, p_to, p_to_t == 0 ? 0.5 : t / p_to_t);
double a3 = Math::lerp(p_to, p_post, p_post_t - p_to_t == 0 ? 1.0 : (t - p_to_t) / (p_post_t - p_to_t));
double b1 = Math::lerp(a1, a2, p_to_t - p_pre_t == 0 ? 0.0 : (t - p_pre_t) / (p_to_t - p_pre_t));
double b2 = Math::lerp(a2, a3, p_post_t == 0 ? 1.0 : t / p_post_t);
return Math::lerp(b1, b2, p_to_t == 0 ? 0.5 : t / p_to_t);
}
inline float cubic_interpolate_in_time(float p_from, float p_to, float p_pre, float p_post, float p_weight,
float p_to_t, float p_pre_t, float p_post_t) {
/* Barry-Goldman method */
float t = Math::lerp(0.0f, p_to_t, p_weight);
float a1 = Math::lerp(p_pre, p_from, p_pre_t == 0 ? 0.0f : (t - p_pre_t) / -p_pre_t);
float a2 = Math::lerp(p_from, p_to, p_to_t == 0 ? 0.5f : t / p_to_t);
float a3 = Math::lerp(p_to, p_post, p_post_t - p_to_t == 0 ? 1.0f : (t - p_to_t) / (p_post_t - p_to_t));
float b1 = Math::lerp(a1, a2, p_to_t - p_pre_t == 0 ? 0.0f : (t - p_pre_t) / (p_to_t - p_pre_t));
float b2 = Math::lerp(a2, a3, p_post_t == 0 ? 1.0f : t / p_post_t);
return Math::lerp(b1, b2, p_to_t == 0 ? 0.5f : t / p_to_t);
}
inline double cubic_interpolate_angle_in_time(double p_from, double p_to, double p_pre, double p_post, double p_weight,
double p_to_t, double p_pre_t, double p_post_t) {
double from_rot = fmod(p_from, Math_TAU);
double pre_diff = fmod(p_pre - from_rot, Math_TAU);
double pre_rot = from_rot + fmod(2.0 * pre_diff, Math_TAU) - pre_diff;
double to_diff = fmod(p_to - from_rot, Math_TAU);
double to_rot = from_rot + fmod(2.0 * to_diff, Math_TAU) - to_diff;
double post_diff = fmod(p_post - to_rot, Math_TAU);
double post_rot = to_rot + fmod(2.0 * post_diff, Math_TAU) - post_diff;
return cubic_interpolate_in_time(from_rot, to_rot, pre_rot, post_rot, p_weight, p_to_t, p_pre_t, p_post_t);
}
inline float cubic_interpolate_angle_in_time(float p_from, float p_to, float p_pre, float p_post, float p_weight,
float p_to_t, float p_pre_t, float p_post_t) {
float from_rot = fmod(p_from, (float)Math_TAU);
float pre_diff = fmod(p_pre - from_rot, (float)Math_TAU);
float pre_rot = from_rot + fmod(2.0f * pre_diff, (float)Math_TAU) - pre_diff;
float to_diff = fmod(p_to - from_rot, (float)Math_TAU);
float to_rot = from_rot + fmod(2.0f * to_diff, (float)Math_TAU) - to_diff;
float post_diff = fmod(p_post - to_rot, (float)Math_TAU);
float post_rot = to_rot + fmod(2.0f * post_diff, (float)Math_TAU) - post_diff;
return cubic_interpolate_in_time(from_rot, to_rot, pre_rot, post_rot, p_weight, p_to_t, p_pre_t, p_post_t);
}
inline double bezier_interpolate(double p_start, double p_control_1, double p_control_2, double p_end, double p_t) {
/* Formula from Wikipedia article on Bezier curves. */
double omt = (1.0 - p_t);
double omt2 = omt * omt;
double omt3 = omt2 * omt;
double t2 = p_t * p_t;
double t3 = t2 * p_t;
return p_start * omt3 + p_control_1 * omt2 * p_t * 3.0 + p_control_2 * omt * t2 * 3.0 + p_end * t3;
}
inline float bezier_interpolate(float p_start, float p_control_1, float p_control_2, float p_end, float p_t) {
/* Formula from Wikipedia article on Bezier curves. */
float omt = (1.0f - p_t);
float omt2 = omt * omt;
float omt3 = omt2 * omt;
float t2 = p_t * p_t;
float t3 = t2 * p_t;
return p_start * omt3 + p_control_1 * omt2 * p_t * 3.0f + p_control_2 * omt * t2 * 3.0f + p_end * t3;
}
template <typename T>
inline T clamp(T x, T minv, T maxv) {
if (x < minv) {
return minv;
}
if (x > maxv) {
return maxv;
}
return x;
}
template <typename T>
inline T min(T a, T b) {
return a < b ? a : b;
}
template <typename T>
inline T max(T a, T b) {
return a > b ? a : b;
}
template <typename T>
inline T sign(T x) {
return static_cast<T>(SIGN(x));
}
template <typename T>
inline T abs(T x) {
return std::abs(x);
}
inline double deg_to_rad(double p_y) {
return p_y * Math_PI / 180.0;
}
inline float deg_to_rad(float p_y) {
return p_y * static_cast<float>(Math_PI) / 180.f;
}
inline double rad_to_deg(double p_y) {
return p_y * 180.0 / Math_PI;
}
inline float rad_to_deg(float p_y) {
return p_y * 180.f / static_cast<float>(Math_PI);
}
inline double inverse_lerp(double p_from, double p_to, double p_value) {
return (p_value - p_from) / (p_to - p_from);
}
inline float inverse_lerp(float p_from, float p_to, float p_value) {
return (p_value - p_from) / (p_to - p_from);
}
inline double remap(double p_value, double p_istart, double p_istop, double p_ostart, double p_ostop) {
return Math::lerp(p_ostart, p_ostop, Math::inverse_lerp(p_istart, p_istop, p_value));
}
inline float remap(float p_value, float p_istart, float p_istop, float p_ostart, float p_ostop) {
return Math::lerp(p_ostart, p_ostop, Math::inverse_lerp(p_istart, p_istop, p_value));
}
inline bool is_nan(float p_val) {
return std::isnan(p_val);
}
inline bool is_nan(double p_val) {
return std::isnan(p_val);
}
inline bool is_inf(float p_val) {
return std::isinf(p_val);
}
inline bool is_inf(double p_val) {
return std::isinf(p_val);
}
inline bool is_equal_approx(float a, float b) {
// Check for exact equality first, required to handle "infinity" values.
if (a == b) {
return true;
}
// Then check for approximate equality.
float tolerance = (float)CMP_EPSILON * abs(a);
if (tolerance < (float)CMP_EPSILON) {
tolerance = (float)CMP_EPSILON;
}
return abs(a - b) < tolerance;
}
inline bool is_equal_approx(float a, float b, float tolerance) {
// Check for exact equality first, required to handle "infinity" values.
if (a == b) {
return true;
}
// Then check for approximate equality.
return abs(a - b) < tolerance;
}
inline bool is_zero_approx(float s) {
return abs(s) < (float)CMP_EPSILON;
}
inline bool is_equal_approx(double a, double b) {
// Check for exact equality first, required to handle "infinity" values.
if (a == b) {
return true;
}
// Then check for approximate equality.
double tolerance = CMP_EPSILON * abs(a);
if (tolerance < CMP_EPSILON) {
tolerance = CMP_EPSILON;
}
return abs(a - b) < tolerance;
}
inline bool is_equal_approx(double a, double b, double tolerance) {
// Check for exact equality first, required to handle "infinity" values.
if (a == b) {
return true;
}
// Then check for approximate equality.
return abs(a - b) < tolerance;
}
inline bool is_zero_approx(double s) {
return abs(s) < CMP_EPSILON;
}
inline float absf(float g) {
union {
float f;
uint32_t i;
} u;
u.f = g;
u.i &= 2147483647u;
return u.f;
}
inline double absd(double g) {
union {
double d;
uint64_t i;
} u;
u.d = g;
u.i &= (uint64_t)9223372036854775807ull;
return u.d;
}
inline double smoothstep(double p_from, double p_to, double p_weight) {
if (is_equal_approx(static_cast<real_t>(p_from), static_cast<real_t>(p_to))) {
return p_from;
}
double x = clamp((p_weight - p_from) / (p_to - p_from), 0.0, 1.0);
return x * x * (3.0 - 2.0 * x);
}
inline float smoothstep(float p_from, float p_to, float p_weight) {
if (is_equal_approx(p_from, p_to)) {
return p_from;
}
float x = clamp((p_weight - p_from) / (p_to - p_from), 0.0f, 1.0f);
return x * x * (3.0f - 2.0f * x);
}
inline double move_toward(double p_from, double p_to, double p_delta) {
return std::abs(p_to - p_from) <= p_delta ? p_to : p_from + sign(p_to - p_from) * p_delta;
}
inline float move_toward(float p_from, float p_to, float p_delta) {
return std::abs(p_to - p_from) <= p_delta ? p_to : p_from + sign(p_to - p_from) * p_delta;
}
inline double linear2db(double p_linear) {
return log(p_linear) * 8.6858896380650365530225783783321;
}
inline float linear2db(float p_linear) {
return log(p_linear) * 8.6858896380650365530225783783321f;
}
inline double db2linear(double p_db) {
return exp(p_db * 0.11512925464970228420089957273422);
}
inline float db2linear(float p_db) {
return exp(p_db * 0.11512925464970228420089957273422f);
}
inline double round(double p_val) {
return (p_val >= 0) ? floor(p_val + 0.5) : -floor(-p_val + 0.5);
}
inline float round(float p_val) {
return (p_val >= 0) ? floor(p_val + 0.5f) : -floor(-p_val + 0.5f);
}
inline int64_t wrapi(int64_t value, int64_t min, int64_t max) {
int64_t range = max - min;
return range == 0 ? min : min + ((((value - min) % range) + range) % range);
}
inline float wrapf(real_t value, real_t min, real_t max) {
const real_t range = max - min;
return is_zero_approx(range) ? min : value - (range * floor((value - min) / range));
}
inline float fract(float value) {
return value - floor(value);
}
inline double fract(double value) {
return value - floor(value);
}
inline float pingpong(float value, float length) {
return (length != 0.0f) ? abs(fract((value - length) / (length * 2.0f)) * length * 2.0f - length) : 0.0f;
}
inline double pingpong(double value, double length) {
return (length != 0.0) ? abs(fract((value - length) / (length * 2.0)) * length * 2.0 - length) : 0.0;
}
// This function should be as fast as possible and rounding mode should not matter.
inline int fast_ftoi(float a) {
static int b;
#if (defined(_WIN32_WINNT) && _WIN32_WINNT >= 0x0603) || WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP // windows 8 phone?
b = (int)((a > 0.0) ? (a + 0.5) : (a - 0.5));
#elif defined(_MSC_VER) && _MSC_VER < 1800
__asm fld a __asm fistp b
/*#elif defined( __GNUC__ ) && ( defined( __i386__ ) || defined( __x86_64__ ) )
// use AT&T inline assembly style, document that
// we use memory as output (=m) and input (m)
__asm__ __volatile__ (
"flds %1 \n\t"
"fistpl %0 \n\t"
: "=m" (b)
: "m" (a));*/
#else
b = lrintf(a); // assuming everything but msvc 2012 or earlier has lrint
#endif
return b;
}
inline double snapped(double p_value, double p_step) {
if (p_step != 0) {
p_value = Math::floor(p_value / p_step + 0.5) * p_step;
}
return p_value;
}
inline float snap_scalar(float p_offset, float p_step, float p_target) {
return p_step != 0 ? Math::snapped(p_target - p_offset, p_step) + p_offset : p_target;
}
inline float snap_scalar_separation(float p_offset, float p_step, float p_target, float p_separation) {
if (p_step != 0) {
float a = Math::snapped(p_target - p_offset, p_step + p_separation) + p_offset;
float b = a;
if (p_target >= 0) {
b -= p_separation;
} else {
b += p_step;
}
return (Math::abs(p_target - a) < Math::abs(p_target - b)) ? a : b;
}
return p_target;
}
} // namespace Math
} // namespace godot
#endif // GODOT_MATH_HPP

View File

@@ -0,0 +1,195 @@
/**************************************************************************/
/* memory.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_MEMORY_HPP
#define GODOT_MEMORY_HPP
#include <cstddef>
#include <cstdint>
#include <godot_cpp/core/defs.hpp>
#include <godot_cpp/core/error_macros.hpp>
#include <godot_cpp/godot.hpp>
#include <type_traits>
#ifndef PAD_ALIGN
#define PAD_ALIGN 16 //must always be greater than this at much
#endif
// p_dummy argument is added to avoid conflicts with the engine functions when both engine and GDExtension are built as a static library on iOS.
void *operator new(size_t p_size, const char *p_dummy, const char *p_description); ///< operator new that takes a description and uses MemoryStaticPool
void *operator new(size_t p_size, const char *p_dummy, void *(*p_allocfunc)(size_t p_size)); ///< operator new that takes a description and uses MemoryStaticPool
void *operator new(size_t p_size, const char *p_dummy, void *p_pointer, size_t check, const char *p_description); ///< operator new that takes a description and uses a pointer to the preallocated memory
_ALWAYS_INLINE_ void *operator new(size_t p_size, const char *p_dummy, void *p_pointer, size_t check, const char *p_description) {
return p_pointer;
}
#ifdef _MSC_VER
// When compiling with VC++ 2017, the above declarations of placement new generate many irrelevant warnings (C4291).
// The purpose of the following definitions is to muffle these warnings, not to provide a usable implementation of placement delete.
void operator delete(void *p_mem, const char *p_dummy, const char *p_description);
void operator delete(void *p_mem, const char *p_dummy, void *(*p_allocfunc)(size_t p_size));
void operator delete(void *p_mem, const char *p_dummy, void *p_pointer, size_t check, const char *p_description);
#endif
namespace godot {
class Wrapped;
class Memory {
Memory();
public:
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);
};
_ALWAYS_INLINE_ void postinitialize_handler(void *) {}
template <class T>
_ALWAYS_INLINE_ T *_post_initialize(T *p_obj) {
postinitialize_handler(p_obj);
return p_obj;
}
#define memalloc(m_size) ::godot::Memory::alloc_static(m_size)
#define memrealloc(m_mem, m_size) ::godot::Memory::realloc_static(m_mem, m_size)
#define memfree(m_mem) ::godot::Memory::free_static(m_mem)
#define memnew(m_class) ::godot::_post_initialize(new ("", "") m_class)
#define memnew_allocator(m_class, m_allocator) ::godot::_post_initialize(new ("", m_allocator::alloc) m_class)
#define memnew_placement(m_placement, m_class) ::godot::_post_initialize(new ("", m_placement, sizeof(m_class), "") m_class)
// Generic comparator used in Map, List, etc.
template <class T>
struct Comparator {
_ALWAYS_INLINE_ bool operator()(const T &p_a, const T &p_b) const { return (p_a < p_b); }
};
template <class 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) {
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>
void memdelete(T *p_class) {
godot::internal::gdextension_interface_object_destroy(p_class->_owner);
}
template <class T, class A>
void memdelete_allocator(T *p_class) {
if (!std::is_trivially_destructible<T>::value) {
p_class->~T();
}
A::free(p_class);
}
class DefaultAllocator {
public:
_ALWAYS_INLINE_ static void *alloc(size_t p_memory) { return Memory::alloc_static(p_memory); }
_ALWAYS_INLINE_ static void free(void *p_ptr) { Memory::free_static(p_ptr); }
};
template <class T>
class DefaultTypedAllocator {
public:
template <class... Args>
_ALWAYS_INLINE_ T *new_allocation(const Args &&...p_args) { return memnew(T(p_args...)); }
_ALWAYS_INLINE_ void delete_allocation(T *p_allocation) { memdelete(p_allocation); }
};
#define memnew_arr(m_class, m_count) memnew_arr_template<m_class>(m_count)
template <typename T>
T *memnew_arr_template(size_t p_elements, const char *p_descr = "") {
if (p_elements == 0) {
return nullptr;
}
/** overloading operator new[] cannot be done , because it may not return the real allocated address (it may pad the 'element count' before the actual array). Because of that, it must be done by hand. This is the
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);
T *failptr = nullptr; // Get rid of a warning.
ERR_FAIL_NULL_V(mem, failptr);
*(mem - 1) = p_elements;
if (!std::is_trivially_destructible<T>::value) {
T *elems = (T *)mem;
/* call operator new */
for (size_t i = 0; i < p_elements; i++) {
new ("", &elems[i], sizeof(T), p_descr) T;
}
}
return (T *)mem;
}
template <typename T>
void memdelete_arr(T *p_class) {
uint64_t *ptr = (uint64_t *)p_class;
if (!std::is_trivially_destructible<T>::value) {
uint64_t elem_count = *(ptr - 1);
for (uint64_t i = 0; i < elem_count; i++) {
p_class[i].~T();
}
}
Memory::free_static(ptr, true);
}
struct _GlobalNil {
int color = 1;
_GlobalNil *right;
_GlobalNil *left;
_GlobalNil *parent;
_GlobalNil();
};
struct _GlobalNilClass {
static _GlobalNil _nil;
};
} // namespace godot
#endif // GODOT_MEMORY_HPP

View File

@@ -0,0 +1,733 @@
/**************************************************************************/
/* method_bind.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_METHOD_BIND_HPP
#define GODOT_METHOD_BIND_HPP
#include <godot_cpp/core/binder_common.hpp>
#include <godot_cpp/core/type_info.hpp>
#include <godot_cpp/core/memory.hpp>
#include <gdextension_interface.h>
#include <godot_cpp/classes/global_constants.hpp>
#include <string>
#include <vector>
#include <iostream>
namespace godot {
class MethodBind {
StringName name;
StringName instance_class;
int argument_count = 0;
uint32_t hint_flags = METHOD_FLAGS_DEFAULT;
bool _static = false;
bool _is_const = false;
bool _has_return = false;
bool _vararg = false;
std::vector<StringName> argument_names;
GDExtensionVariantType *argument_types = nullptr;
std::vector<Variant> default_arguments;
protected:
virtual GDExtensionVariantType gen_argument_type(int p_arg) const = 0;
virtual PropertyInfo gen_argument_type_info(int p_arg) const = 0;
void generate_argument_types(int p_count);
void set_const(bool p_const);
void set_return(bool p_return);
void set_static(bool p_static);
void set_vararg(bool p_vararg);
void set_argument_count(int p_count);
public:
StringName get_name() const;
void set_name(const StringName &p_name);
_FORCE_INLINE_ int get_default_argument_count() const { return (int)default_arguments.size(); }
_FORCE_INLINE_ const std::vector<Variant> &get_default_arguments() const { return default_arguments; }
_FORCE_INLINE_ Variant has_default_argument(int p_arg) const {
const int num_default_args = (int)(default_arguments.size());
const int idx = p_arg - (argument_count - num_default_args);
if (idx < 0 || idx >= num_default_args) {
return false;
} else {
return true;
}
}
_FORCE_INLINE_ Variant get_default_argument(int p_arg) const {
const int num_default_args = (int)(default_arguments.size());
const int idx = p_arg - (argument_count - num_default_args);
if (idx < 0 || idx >= num_default_args) {
return Variant();
} else {
return default_arguments[idx];
}
}
_FORCE_INLINE_ StringName get_instance_class() const { return instance_class; }
_FORCE_INLINE_ void set_instance_class(StringName p_class) { instance_class = p_class; }
_FORCE_INLINE_ int get_argument_count() const { return argument_count; }
_FORCE_INLINE_ bool is_const() const { return _is_const; }
_FORCE_INLINE_ bool is_static() const { return _static; }
_FORCE_INLINE_ bool is_vararg() const { return _vararg; }
_FORCE_INLINE_ bool has_return() const { return _has_return; }
_FORCE_INLINE_ uint32_t get_hint_flags() const { return hint_flags | (is_const() ? GDEXTENSION_METHOD_FLAG_CONST : 0) | (is_vararg() ? GDEXTENSION_METHOD_FLAG_VARARG : 0) | (is_static() ? GDEXTENSION_METHOD_FLAG_STATIC : 0); }
_FORCE_INLINE_ void set_hint_flags(uint32_t p_hint_flags) { hint_flags = p_hint_flags; }
void set_argument_names(const std::vector<StringName> &p_names);
std::vector<StringName> get_argument_names() const;
void set_default_arguments(const std::vector<Variant> &p_default_arguments) { default_arguments = p_default_arguments; }
_FORCE_INLINE_ GDExtensionVariantType get_argument_type(int p_argument) const {
ERR_FAIL_COND_V(p_argument < -1 || p_argument > argument_count, GDEXTENSION_VARIANT_TYPE_NIL);
return argument_types[p_argument + 1];
}
PropertyInfo get_argument_info(int p_argument) const;
virtual GDExtensionClassMethodArgumentMetadata get_argument_metadata(int p_argument) const = 0;
std::vector<PropertyInfo> get_arguments_info_list() const {
std::vector<PropertyInfo> vec;
// First element is return value
vec.reserve(argument_count + 1);
for (int i = 0; i < argument_count + 1; i++) {
vec.push_back(get_argument_info(i - 1));
}
return vec;
}
std::vector<GDExtensionClassMethodArgumentMetadata> get_arguments_metadata_list() const {
std::vector<GDExtensionClassMethodArgumentMetadata> vec;
// First element is return value
vec.reserve(argument_count + 1);
for (int i = 0; i < argument_count; i++) {
vec.push_back(get_argument_metadata(i - 1));
}
return vec;
}
virtual Variant call(GDExtensionClassInstancePtr p_instance, const GDExtensionConstVariantPtr *p_args, GDExtensionInt p_argument_count, GDExtensionCallError &r_error) const = 0;
virtual void ptrcall(GDExtensionClassInstancePtr p_instance, const GDExtensionConstTypePtr *p_args, GDExtensionTypePtr r_return) const = 0;
static void bind_call(void *p_method_userdata, GDExtensionClassInstancePtr p_instance, const GDExtensionConstVariantPtr *p_args, GDExtensionInt p_argument_count, GDExtensionVariantPtr r_return, GDExtensionCallError *r_error);
static void bind_ptrcall(void *p_method_userdata, GDExtensionClassInstancePtr p_instance, const GDExtensionConstTypePtr *p_args, GDExtensionTypePtr r_return);
virtual ~MethodBind();
};
template <class Derived, class T, class R, bool should_returns>
class MethodBindVarArgBase : public MethodBind {
protected:
R(T::*method)
(const Variant **, GDExtensionInt, GDExtensionCallError &);
std::vector<PropertyInfo> arguments;
public:
virtual PropertyInfo gen_argument_type_info(int p_arg) const {
if (p_arg < 0) {
return _gen_return_type_info();
} else if ((size_t)(p_arg) < arguments.size()) {
return arguments[p_arg];
} else {
return make_property_info(Variant::Type::NIL, "vararg", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_NIL_IS_VARIANT);
}
}
virtual GDExtensionVariantType gen_argument_type(int p_arg) const {
return static_cast<GDExtensionVariantType>(gen_argument_type_info(p_arg).type);
}
virtual GDExtensionClassMethodArgumentMetadata get_argument_metadata(int) const {
return GDEXTENSION_METHOD_ARGUMENT_METADATA_NONE;
}
virtual void ptrcall(GDExtensionClassInstancePtr p_instance, const GDExtensionConstTypePtr *p_args, GDExtensionTypePtr r_return) const {
ERR_FAIL(); // Can't call.
}
MethodBindVarArgBase(
R (T::*p_method)(const Variant **, GDExtensionInt, GDExtensionCallError &),
const MethodInfo &p_method_info,
bool p_return_nil_is_variant) :
method(p_method) {
set_vararg(true);
set_const(true);
set_argument_count(p_method_info.arguments.size());
if (p_method_info.arguments.size()) {
arguments = p_method_info.arguments;
std::vector<StringName> names;
names.reserve(p_method_info.arguments.size());
for (size_t i = 0; i < p_method_info.arguments.size(); i++) {
names.push_back(p_method_info.arguments[i].name);
}
set_argument_names(names);
}
generate_argument_types((int)p_method_info.arguments.size());
set_return(should_returns);
}
~MethodBindVarArgBase() {}
private:
PropertyInfo _gen_return_type_info() const {
return reinterpret_cast<const Derived *>(this)->_gen_return_type_info_impl();
}
};
template <class T>
class MethodBindVarArgT : public MethodBindVarArgBase<MethodBindVarArgT<T>, T, void, false> {
friend class MethodBindVarArgBase<MethodBindVarArgT<T>, T, void, false>;
public:
virtual Variant call(GDExtensionClassInstancePtr p_instance, const GDExtensionConstVariantPtr *p_args, GDExtensionInt p_argument_count, GDExtensionCallError &r_error) const {
(static_cast<T *>(p_instance)->*MethodBindVarArgBase<MethodBindVarArgT<T>, T, void, false>::method)((const Variant **)p_args, p_argument_count, r_error);
return {};
}
MethodBindVarArgT(
void (T::*p_method)(const Variant **, GDExtensionInt, GDExtensionCallError &),
const MethodInfo &p_method_info,
bool p_return_nil_is_variant) :
MethodBindVarArgBase<MethodBindVarArgT<T>, T, void, false>(p_method, p_method_info, p_return_nil_is_variant) {
}
private:
PropertyInfo _gen_return_type_info_impl() const {
return {};
}
};
template <class T>
MethodBind *create_vararg_method_bind(void (T::*p_method)(const Variant **, GDExtensionInt, GDExtensionCallError &), const MethodInfo &p_info, bool p_return_nil_is_variant) {
MethodBind *a = memnew((MethodBindVarArgT<T>)(p_method, p_info, p_return_nil_is_variant));
a->set_instance_class(T::get_class_static());
return a;
}
template <class T, class R>
class MethodBindVarArgTR : public MethodBindVarArgBase<MethodBindVarArgTR<T, R>, T, R, true> {
friend class MethodBindVarArgBase<MethodBindVarArgTR<T, R>, T, R, true>;
public:
virtual Variant call(GDExtensionClassInstancePtr p_instance, const GDExtensionConstVariantPtr *p_args, GDExtensionInt p_argument_count, GDExtensionCallError &r_error) const {
return (static_cast<T *>(p_instance)->*MethodBindVarArgBase<MethodBindVarArgTR<T, R>, T, R, true>::method)((const Variant **)p_args, p_argument_count, r_error);
}
MethodBindVarArgTR(
R (T::*p_method)(const Variant **, GDExtensionInt, GDExtensionCallError &),
const MethodInfo &p_info,
bool p_return_nil_is_variant) :
MethodBindVarArgBase<MethodBindVarArgTR<T, R>, T, R, true>(p_method, p_info, p_return_nil_is_variant) {
}
private:
PropertyInfo _gen_return_type_info_impl() const {
return GetTypeInfo<R>::get_class_info();
}
};
template <class T, class R>
MethodBind *create_vararg_method_bind(R (T::*p_method)(const Variant **, GDExtensionInt, GDExtensionCallError &), const MethodInfo &p_info, bool p_return_nil_is_variant) {
MethodBind *a = memnew((MethodBindVarArgTR<T, R>)(p_method, p_info, p_return_nil_is_variant));
a->set_instance_class(T::get_class_static());
return a;
}
#ifndef TYPED_METHOD_BIND
class _gde_UnexistingClass;
#define MB_T _gde_UnexistingClass
#else
#define MB_T T
#endif
// No return, not const.
#ifdef TYPED_METHOD_BIND
template <class T, class... P>
#else
template <class... P>
#endif // TYPED_METHOD_BIND
class MethodBindT : public MethodBind {
void (MB_T::*method)(P...);
protected:
// GCC raises warnings in the case P = {} as the comparison is always false...
#if defined(__GNUC__) && !defined(__clang__)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wlogical-op"
#endif
virtual GDExtensionVariantType gen_argument_type(int p_arg) const {
if (p_arg >= 0 && p_arg < (int)sizeof...(P)) {
return call_get_argument_type<P...>(p_arg);
} else {
return GDEXTENSION_VARIANT_TYPE_NIL;
}
}
virtual PropertyInfo gen_argument_type_info(int p_arg) const {
PropertyInfo pi;
if (p_arg >= 0 && p_arg < (int)sizeof...(P)) {
call_get_argument_type_info<P...>(p_arg, pi);
} else {
pi = PropertyInfo();
}
return pi;
}
#if defined(__GNUC__) && !defined(__clang__)
#pragma GCC diagnostic pop
#endif
public:
virtual GDExtensionClassMethodArgumentMetadata get_argument_metadata(int p_argument) const {
return call_get_argument_metadata<P...>(p_argument);
}
virtual Variant call(GDExtensionClassInstancePtr p_instance, const GDExtensionConstVariantPtr *p_args, GDExtensionInt p_argument_count, GDExtensionCallError &r_error) const {
#ifdef TYPED_METHOD_BIND
call_with_variant_args_dv(static_cast<T *>(p_instance), method, p_args, (int)p_argument_count, r_error, get_default_arguments());
#else
call_with_variant_args_dv(reinterpret_cast<MB_T *>(p_instance), method, p_args, p_argument_count, r_error, get_default_arguments());
#endif
return Variant();
}
virtual void ptrcall(GDExtensionClassInstancePtr p_instance, const GDExtensionConstTypePtr *p_args, GDExtensionTypePtr r_ret) const {
#ifdef TYPED_METHOD_BIND
call_with_ptr_args<T, P...>(static_cast<T *>(p_instance), method, p_args, nullptr);
#else
call_with_ptr_args<MB_T, P...>(reinterpret_cast<MB_T *>(p_instance), method, p_args, nullptr);
#endif // TYPED_METHOD_BIND
}
MethodBindT(void (MB_T::*p_method)(P...)) {
method = p_method;
generate_argument_types(sizeof...(P));
set_argument_count(sizeof...(P));
}
};
template <class T, class... P>
MethodBind *create_method_bind(void (T::*p_method)(P...)) {
#ifdef TYPED_METHOD_BIND
MethodBind *a = memnew((MethodBindT<T, P...>)(p_method));
#else
MethodBind *a = memnew((MethodBindT<P...>)(reinterpret_cast<void (MB_T::*)(P...)>(p_method)));
#endif // TYPED_METHOD_BIND
a->set_instance_class(T::get_class_static());
return a;
}
// No return, const.
#ifdef TYPED_METHOD_BIND
template <class T, class... P>
#else
template <class... P>
#endif // TYPED_METHOD_BIND
class MethodBindTC : public MethodBind {
void (MB_T::*method)(P...) const;
protected:
// GCC raises warnings in the case P = {} as the comparison is always false...
#if defined(__GNUC__) && !defined(__clang__)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wlogical-op"
#endif
virtual GDExtensionVariantType gen_argument_type(int p_arg) const {
if (p_arg >= 0 && p_arg < (int)sizeof...(P)) {
return call_get_argument_type<P...>(p_arg);
} else {
return GDEXTENSION_VARIANT_TYPE_NIL;
}
}
virtual PropertyInfo gen_argument_type_info(int p_arg) const {
PropertyInfo pi;
if (p_arg >= 0 && p_arg < (int)sizeof...(P)) {
call_get_argument_type_info<P...>(p_arg, pi);
} else {
pi = PropertyInfo();
}
return pi;
}
#if defined(__GNUC__) && !defined(__clang__)
#pragma GCC diagnostic pop
#endif
public:
virtual GDExtensionClassMethodArgumentMetadata get_argument_metadata(int p_argument) const {
return call_get_argument_metadata<P...>(p_argument);
}
virtual Variant call(GDExtensionClassInstancePtr p_instance, const GDExtensionConstVariantPtr *p_args, GDExtensionInt p_argument_count, GDExtensionCallError &r_error) const {
#ifdef TYPED_METHOD_BIND
call_with_variant_argsc_dv(static_cast<T *>(p_instance), method, p_args, (int)p_argument_count, r_error, get_default_arguments());
#else
call_with_variant_argsc_dv(reinterpret_cast<MB_T *>(p_instance), method, p_args, p_argument_count, r_error, get_default_arguments());
#endif
return Variant();
}
virtual void ptrcall(GDExtensionClassInstancePtr p_instance, const GDExtensionConstTypePtr *p_args, GDExtensionTypePtr r_ret) const {
#ifdef TYPED_METHOD_BIND
call_with_ptr_args<T, P...>(static_cast<T *>(p_instance), method, p_args, nullptr);
#else
call_with_ptr_args<MB_T, P...>(reinterpret_cast<MB_T *>(p_instance), method, p_args, nullptr);
#endif // TYPED_METHOD_BIND
}
MethodBindTC(void (MB_T::*p_method)(P...) const) {
method = p_method;
generate_argument_types(sizeof...(P));
set_argument_count(sizeof...(P));
}
};
template <class T, class... P>
MethodBind *create_method_bind(void (T::*p_method)(P...) const) {
#ifdef TYPED_METHOD_BIND
MethodBind *a = memnew((MethodBindTC<T, P...>)(p_method));
#else
MethodBind *a = memnew((MethodBindTC<P...>)(reinterpret_cast<void (MB_T::*)(P...) const>(p_method)));
#endif // TYPED_METHOD_BIND
a->set_instance_class(T::get_class_static());
return a;
}
// Return, not const.
#ifdef TYPED_METHOD_BIND
template <class T, class R, class... P>
#else
template <class R, class... P>
#endif // TYPED_METHOD_BIND
class MethodBindTR : public MethodBind {
R(MB_T::*method)
(P...);
protected:
// GCC raises warnings in the case P = {} as the comparison is always false...
#if defined(__GNUC__) && !defined(__clang__)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wlogical-op"
#endif
virtual GDExtensionVariantType gen_argument_type(int p_arg) const {
if (p_arg >= 0 && p_arg < (int)sizeof...(P)) {
return call_get_argument_type<P...>(p_arg);
} else {
return GDExtensionVariantType(GetTypeInfo<R>::VARIANT_TYPE);
}
}
virtual PropertyInfo gen_argument_type_info(int p_arg) const {
if (p_arg >= 0 && p_arg < (int)sizeof...(P)) {
PropertyInfo pi;
call_get_argument_type_info<P...>(p_arg, pi);
return pi;
} else {
return GetTypeInfo<R>::get_class_info();
}
}
#if defined(__GNUC__) && !defined(__clang__)
#pragma GCC diagnostic pop
#endif
public:
virtual GDExtensionClassMethodArgumentMetadata get_argument_metadata(int p_argument) const {
if (p_argument >= 0) {
return call_get_argument_metadata<P...>(p_argument);
} else {
return GetTypeInfo<R>::METADATA;
}
}
virtual Variant call(GDExtensionClassInstancePtr p_instance, const GDExtensionConstVariantPtr *p_args, GDExtensionInt p_argument_count, GDExtensionCallError &r_error) const {
Variant ret;
#ifdef TYPED_METHOD_BIND
call_with_variant_args_ret_dv(static_cast<T *>(p_instance), method, p_args, (int)p_argument_count, ret, r_error, get_default_arguments());
#else
call_with_variant_args_ret_dv((MB_T *)p_instance, method, p_args, p_argument_count, ret, r_error, get_default_arguments());
#endif
return ret;
}
virtual void ptrcall(GDExtensionClassInstancePtr p_instance, const GDExtensionConstTypePtr *p_args, GDExtensionTypePtr r_ret) const {
#ifdef TYPED_METHOD_BIND
call_with_ptr_args<T, R, P...>(static_cast<T *>(p_instance), method, p_args, r_ret);
#else
call_with_ptr_args<MB_T, R, P...>(reinterpret_cast<MB_T *>(p_instance), method, p_args, r_ret);
#endif // TYPED_METHOD_BIND
}
MethodBindTR(R (MB_T::*p_method)(P...)) {
method = p_method;
generate_argument_types(sizeof...(P));
set_argument_count(sizeof...(P));
set_return(true);
}
};
template <class T, class R, class... P>
MethodBind *create_method_bind(R (T::*p_method)(P...)) {
#ifdef TYPED_METHOD_BIND
MethodBind *a = memnew((MethodBindTR<T, R, P...>)(p_method));
#else
MethodBind *a = memnew((MethodBindTR<R, P...>)(reinterpret_cast<R (MB_T::*)(P...)>(p_method)));
#endif // TYPED_METHOD_BIND
a->set_instance_class(T::get_class_static());
return a;
}
// Return, const.
#ifdef TYPED_METHOD_BIND
template <class T, class R, class... P>
#else
template <class R, class... P>
#endif // TYPED_METHOD_BIND
class MethodBindTRC : public MethodBind {
R(MB_T::*method)
(P...) const;
protected:
// GCC raises warnings in the case P = {} as the comparison is always false...
#if defined(__GNUC__) && !defined(__clang__)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wlogical-op"
#endif
virtual GDExtensionVariantType gen_argument_type(int p_arg) const {
if (p_arg >= 0 && p_arg < (int)sizeof...(P)) {
return call_get_argument_type<P...>(p_arg);
} else {
return GDExtensionVariantType(GetTypeInfo<R>::VARIANT_TYPE);
}
}
virtual PropertyInfo gen_argument_type_info(int p_arg) const {
if (p_arg >= 0 && p_arg < (int)sizeof...(P)) {
PropertyInfo pi;
call_get_argument_type_info<P...>(p_arg, pi);
return pi;
} else {
return GetTypeInfo<R>::get_class_info();
}
}
#if defined(__GNUC__) && !defined(__clang__)
#pragma GCC diagnostic pop
#endif
public:
virtual GDExtensionClassMethodArgumentMetadata get_argument_metadata(int p_argument) const {
if (p_argument >= 0) {
return call_get_argument_metadata<P...>(p_argument);
} else {
return GetTypeInfo<R>::METADATA;
}
}
virtual Variant call(GDExtensionClassInstancePtr p_instance, const GDExtensionConstVariantPtr *p_args, GDExtensionInt p_argument_count, GDExtensionCallError &r_error) const {
Variant ret;
#ifdef TYPED_METHOD_BIND
call_with_variant_args_retc_dv(static_cast<T *>(p_instance), method, p_args, (int)p_argument_count, ret, r_error, get_default_arguments());
#else
call_with_variant_args_retc_dv((MB_T *)p_instance, method, p_args, p_argument_count, ret, r_error, get_default_arguments());
#endif
return ret;
}
virtual void ptrcall(GDExtensionClassInstancePtr p_instance, const GDExtensionConstTypePtr *p_args, GDExtensionTypePtr r_ret) const {
#ifdef TYPED_METHOD_BIND
call_with_ptr_args<T, R, P...>(static_cast<T *>(p_instance), method, p_args, r_ret);
#else
call_with_ptr_args<MB_T, R, P...>(reinterpret_cast<MB_T *>(p_instance), method, p_args, r_ret);
#endif // TYPED_METHOD_BIND
}
MethodBindTRC(R (MB_T::*p_method)(P...) const) {
method = p_method;
generate_argument_types(sizeof...(P));
set_argument_count(sizeof...(P));
set_return(true);
}
};
template <class T, class R, class... P>
MethodBind *create_method_bind(R (T::*p_method)(P...) const) {
#ifdef TYPED_METHOD_BIND
MethodBind *a = memnew((MethodBindTRC<T, R, P...>)(p_method));
#else
MethodBind *a = memnew((MethodBindTRC<R, P...>)(reinterpret_cast<R (MB_T::*)(P...) const>(p_method)));
#endif // TYPED_METHOD_BIND
a->set_instance_class(T::get_class_static());
return a;
}
// STATIC BINDS
// no return
template <class... P>
class MethodBindTS : public MethodBind {
void (*function)(P...);
protected:
// GCC raises warnings in the case P = {} as the comparison is always false...
#if defined(__GNUC__) && !defined(__clang__)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wlogical-op"
#endif
virtual GDExtensionVariantType gen_argument_type(int p_arg) const {
if (p_arg >= 0 && p_arg < (int)sizeof...(P)) {
return call_get_argument_type<P...>(p_arg);
} else {
return GDEXTENSION_VARIANT_TYPE_NIL;
}
}
virtual PropertyInfo gen_argument_type_info(int p_arg) const {
PropertyInfo pi;
if (p_arg >= 0 && p_arg < (int)sizeof...(P)) {
call_get_argument_type_info<P...>(p_arg, pi);
} else {
pi = PropertyInfo();
}
return pi;
}
#if defined(__GNUC__) && !defined(__clang__)
#pragma GCC diagnostic pop
#endif
public:
virtual GDExtensionClassMethodArgumentMetadata get_argument_metadata(int p_arg) const {
return call_get_argument_metadata<P...>(p_arg);
}
virtual Variant call(GDExtensionClassInstancePtr p_object, const GDExtensionConstVariantPtr *p_args, GDExtensionInt p_arg_count, GDExtensionCallError &r_error) const {
(void)p_object; // unused
call_with_variant_args_static_dv(function, p_args, p_arg_count, r_error, get_default_arguments());
return Variant();
}
virtual void ptrcall(GDExtensionClassInstancePtr p_object, const GDExtensionConstTypePtr *p_args, GDExtensionTypePtr r_ret) const {
(void)p_object;
(void)r_ret;
call_with_ptr_args_static_method(function, p_args);
}
MethodBindTS(void (*p_function)(P...)) {
function = p_function;
generate_argument_types(sizeof...(P));
set_argument_count(sizeof...(P));
set_static(true);
}
};
template <class... P>
MethodBind *create_static_method_bind(void (*p_method)(P...)) {
MethodBind *a = memnew((MethodBindTS<P...>)(p_method));
return a;
}
// return
template <class R, class... P>
class MethodBindTRS : public MethodBind {
R(*function)
(P...);
protected:
// GCC raises warnings in the case P = {} as the comparison is always false...
#if defined(__GNUC__) && !defined(__clang__)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wlogical-op"
#endif
virtual GDExtensionVariantType gen_argument_type(int p_arg) const {
if (p_arg >= 0 && p_arg < (int)sizeof...(P)) {
return call_get_argument_type<P...>(p_arg);
} else {
return GDExtensionVariantType(GetTypeInfo<R>::VARIANT_TYPE);
}
}
virtual PropertyInfo gen_argument_type_info(int p_arg) const {
if (p_arg >= 0 && p_arg < (int)sizeof...(P)) {
PropertyInfo pi;
call_get_argument_type_info<P...>(p_arg, pi);
return pi;
} else {
return GetTypeInfo<R>::get_class_info();
}
}
#if defined(__GNUC__) && !defined(__clang__)
#pragma GCC diagnostic pop
#endif
public:
virtual GDExtensionClassMethodArgumentMetadata get_argument_metadata(int p_arg) const {
if (p_arg >= 0) {
return call_get_argument_metadata<P...>(p_arg);
} else {
return GetTypeInfo<R>::METADATA;
}
}
virtual Variant call(GDExtensionClassInstancePtr p_object, const GDExtensionConstVariantPtr *p_args, GDExtensionInt p_arg_count, GDExtensionCallError &r_error) const {
Variant ret;
call_with_variant_args_static_ret_dv(function, p_args, p_arg_count, ret, r_error, get_default_arguments());
return ret;
}
virtual void ptrcall(GDExtensionClassInstancePtr p_object, const GDExtensionConstTypePtr *p_args, GDExtensionTypePtr r_ret) const {
(void)p_object;
call_with_ptr_args_static_method_ret(function, p_args, r_ret);
}
MethodBindTRS(R (*p_function)(P...)) {
function = p_function;
generate_argument_types(sizeof...(P));
set_argument_count(sizeof...(P));
set_static(true);
set_return(true);
}
};
template <class R, class... P>
MethodBind *create_static_method_bind(R (*p_method)(P...)) {
MethodBind *a = memnew((MethodBindTRS<R, P...>)(p_method));
return a;
}
} // namespace godot
#endif // GODOT_METHOD_BIND_HPP

View File

@@ -0,0 +1,237 @@
/**************************************************************************/
/* method_ptrcall.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_METHOD_PTRCALL_HPP
#define GODOT_METHOD_PTRCALL_HPP
#include <godot_cpp/core/defs.hpp>
#include <godot_cpp/core/object.hpp>
#include <godot_cpp/godot.hpp>
#include <godot_cpp/variant/variant.hpp>
namespace godot {
template <class T>
struct PtrToArg {};
#define MAKE_PTRARG(m_type) \
template <> \
struct PtrToArg<m_type> { \
_FORCE_INLINE_ static m_type convert(const void *p_ptr) { \
return *reinterpret_cast<const m_type *>(p_ptr); \
} \
typedef m_type EncodeT; \
_FORCE_INLINE_ static void encode(m_type p_val, void *p_ptr) { \
*reinterpret_cast<m_type *>(p_ptr) = p_val; \
} \
}; \
template <> \
struct PtrToArg<const m_type &> { \
_FORCE_INLINE_ static m_type convert(const void *p_ptr) { \
return *reinterpret_cast<const m_type *>(p_ptr); \
} \
typedef m_type EncodeT; \
_FORCE_INLINE_ static void encode(m_type p_val, void *p_ptr) { \
*reinterpret_cast<m_type *>(p_ptr) = p_val; \
} \
}
#define MAKE_PTRARGCONV(m_type, m_conv) \
template <> \
struct PtrToArg<m_type> { \
_FORCE_INLINE_ static m_type convert(const void *p_ptr) { \
return static_cast<m_type>(*reinterpret_cast<const m_conv *>(p_ptr)); \
} \
typedef m_conv EncodeT; \
_FORCE_INLINE_ static void encode(m_type p_val, void *p_ptr) { \
*reinterpret_cast<m_conv *>(p_ptr) = static_cast<m_conv>(p_val); \
} \
_FORCE_INLINE_ static m_conv encode_arg(m_type p_val) { \
return static_cast<m_conv>(p_val); \
} \
}; \
template <> \
struct PtrToArg<const m_type &> { \
_FORCE_INLINE_ static m_type convert(const void *p_ptr) { \
return static_cast<m_type>(*reinterpret_cast<const m_conv *>(p_ptr)); \
} \
typedef m_conv EncodeT; \
_FORCE_INLINE_ static void encode(m_type p_val, void *p_ptr) { \
*reinterpret_cast<m_conv *>(p_ptr) = static_cast<m_conv>(p_val); \
} \
_FORCE_INLINE_ static m_conv encode_arg(m_type p_val) { \
return static_cast<m_conv>(p_val); \
} \
}
#define MAKE_PTRARG_BY_REFERENCE(m_type) \
template <> \
struct PtrToArg<m_type> { \
_FORCE_INLINE_ static m_type convert(const void *p_ptr) { \
return *reinterpret_cast<const m_type *>(p_ptr); \
} \
typedef m_type EncodeT; \
_FORCE_INLINE_ static void encode(const m_type &p_val, void *p_ptr) { \
*reinterpret_cast<m_type *>(p_ptr) = p_val; \
} \
}; \
template <> \
struct PtrToArg<const m_type &> { \
_FORCE_INLINE_ static m_type convert(const void *p_ptr) { \
return *reinterpret_cast<const m_type *>(p_ptr); \
} \
typedef m_type EncodeT; \
_FORCE_INLINE_ static void encode(const m_type &p_val, void *p_ptr) { \
*reinterpret_cast<m_type *>(p_ptr) = p_val; \
} \
}
MAKE_PTRARGCONV(bool, uint8_t);
// Integer types.
MAKE_PTRARGCONV(uint8_t, int64_t);
MAKE_PTRARGCONV(int8_t, int64_t);
MAKE_PTRARGCONV(uint16_t, int64_t);
MAKE_PTRARGCONV(int16_t, int64_t);
MAKE_PTRARGCONV(uint32_t, int64_t);
MAKE_PTRARGCONV(int32_t, int64_t);
MAKE_PTRARG(int64_t);
MAKE_PTRARG(uint64_t);
// Float types
MAKE_PTRARGCONV(float, double);
MAKE_PTRARG(double);
MAKE_PTRARG(String);
MAKE_PTRARG(Vector2);
MAKE_PTRARG(Vector2i);
MAKE_PTRARG(Rect2);
MAKE_PTRARG(Rect2i);
MAKE_PTRARG_BY_REFERENCE(Vector3);
MAKE_PTRARG_BY_REFERENCE(Vector3i);
MAKE_PTRARG(Transform2D);
MAKE_PTRARG_BY_REFERENCE(Vector4);
MAKE_PTRARG_BY_REFERENCE(Vector4i);
MAKE_PTRARG_BY_REFERENCE(Plane);
MAKE_PTRARG(Quaternion);
MAKE_PTRARG_BY_REFERENCE(AABB);
MAKE_PTRARG_BY_REFERENCE(Basis);
MAKE_PTRARG_BY_REFERENCE(Transform3D);
MAKE_PTRARG_BY_REFERENCE(Projection);
MAKE_PTRARG_BY_REFERENCE(Color);
MAKE_PTRARG(StringName);
MAKE_PTRARG(NodePath);
MAKE_PTRARG(RID);
// Object doesn't need this.
MAKE_PTRARG(Callable);
MAKE_PTRARG(Signal);
MAKE_PTRARG(Dictionary);
MAKE_PTRARG(Array);
MAKE_PTRARG(PackedByteArray);
MAKE_PTRARG(PackedInt32Array);
MAKE_PTRARG(PackedInt64Array);
MAKE_PTRARG(PackedFloat32Array);
MAKE_PTRARG(PackedFloat64Array);
MAKE_PTRARG(PackedStringArray);
MAKE_PTRARG(PackedVector2Array);
MAKE_PTRARG(PackedVector3Array);
MAKE_PTRARG(PackedColorArray);
MAKE_PTRARG_BY_REFERENCE(Variant);
// This is for Object.
template <class T>
struct PtrToArg<T *> {
static_assert(std::is_base_of<Object, T>::value, "Cannot encode non-Object value as an Object");
_FORCE_INLINE_ static T *convert(const void *p_ptr) {
return reinterpret_cast<T *>(godot::internal::get_object_instance_binding(*reinterpret_cast<GDExtensionObjectPtr *>(const_cast<void *>(p_ptr))));
}
typedef Object *EncodeT;
_FORCE_INLINE_ static void encode(T *p_var, void *p_ptr) {
*reinterpret_cast<const void **>(p_ptr) = p_var ? p_var->_owner : nullptr;
}
};
template <class T>
struct PtrToArg<const T *> {
static_assert(std::is_base_of<Object, T>::value, "Cannot encode non-Object value as an Object");
_FORCE_INLINE_ static const T *convert(const void *p_ptr) {
return reinterpret_cast<const T *>(godot::internal::get_object_instance_binding(*reinterpret_cast<GDExtensionObjectPtr *>(const_cast<void *>(p_ptr))));
}
typedef const Object *EncodeT;
_FORCE_INLINE_ static void encode(T *p_var, void *p_ptr) {
*reinterpret_cast<const void **>(p_ptr) = p_var ? p_var->_owner : nullptr;
}
};
// Pointers.
#define GDVIRTUAL_NATIVE_PTR(m_type) \
template <> \
struct PtrToArg<m_type *> { \
_FORCE_INLINE_ static m_type *convert(const void *p_ptr) { \
return (m_type *)(*(void **)p_ptr); \
} \
typedef m_type *EncodeT; \
_FORCE_INLINE_ static void encode(m_type *p_var, void *p_ptr) { \
*reinterpret_cast<m_type **>(p_ptr) = p_var; \
} \
}; \
\
template <> \
struct PtrToArg<const m_type *> { \
_FORCE_INLINE_ static const m_type *convert(const void *p_ptr) { \
return (const m_type *)(*(const void **)p_ptr); \
} \
typedef const m_type *EncodeT; \
_FORCE_INLINE_ static void encode(const m_type *p_var, void *p_ptr) { \
*reinterpret_cast<const m_type **>(p_ptr) = p_var; \
} \
}
GDVIRTUAL_NATIVE_PTR(void);
GDVIRTUAL_NATIVE_PTR(bool);
GDVIRTUAL_NATIVE_PTR(char);
GDVIRTUAL_NATIVE_PTR(char16_t);
GDVIRTUAL_NATIVE_PTR(char32_t);
GDVIRTUAL_NATIVE_PTR(wchar_t);
GDVIRTUAL_NATIVE_PTR(uint8_t);
GDVIRTUAL_NATIVE_PTR(uint8_t *);
GDVIRTUAL_NATIVE_PTR(int8_t);
GDVIRTUAL_NATIVE_PTR(uint16_t);
GDVIRTUAL_NATIVE_PTR(int16_t);
GDVIRTUAL_NATIVE_PTR(uint32_t);
GDVIRTUAL_NATIVE_PTR(int32_t);
GDVIRTUAL_NATIVE_PTR(int64_t);
GDVIRTUAL_NATIVE_PTR(uint64_t);
GDVIRTUAL_NATIVE_PTR(float);
GDVIRTUAL_NATIVE_PTR(double);
} // namespace godot
#endif // GODOT_METHOD_PTRCALL_HPP

View File

@@ -0,0 +1,59 @@
/**************************************************************************/
/* mutex_lock.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_MUTEX_LOCK_HPP
#define GODOT_MUTEX_LOCK_HPP
#include <godot_cpp/classes/mutex.hpp>
namespace godot {
class MutexLock {
const Mutex &mutex;
public:
_ALWAYS_INLINE_ explicit MutexLock(const Mutex &p_mutex) :
mutex(p_mutex) {
const_cast<Mutex *>(&mutex)->lock();
}
_ALWAYS_INLINE_ ~MutexLock() {
const_cast<Mutex *>(&mutex)->unlock();
}
};
#define _THREAD_SAFE_CLASS_ mutable Mutex _thread_safe_;
#define _THREAD_SAFE_METHOD_ MutexLock _thread_safe_method_(_thread_safe_);
#define _THREAD_SAFE_LOCK_ _thread_safe_.lock();
#define _THREAD_SAFE_UNLOCK_ _thread_safe_.unlock();
} // namespace godot
#endif // GODOT_MUTEX_LOCK_HPP

View File

@@ -0,0 +1,150 @@
/**************************************************************************/
/* object.hpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#ifndef GODOT_OBJECT_HPP
#define GODOT_OBJECT_HPP
#include <godot_cpp/core/defs.hpp>
#include <godot_cpp/core/object_id.hpp>
#include <godot_cpp/core/property_info.hpp>
#include <godot_cpp/variant/variant.hpp>
#include <godot_cpp/classes/object.hpp>
#include <godot_cpp/godot.hpp>
#include <gdextension_interface.h>
#include <vector>
#define ADD_SIGNAL(m_signal) godot::ClassDB::add_signal(get_class_static(), m_signal)
#define ADD_GROUP(m_name, m_prefix) godot::ClassDB::add_property_group(get_class_static(), m_name, m_prefix)
#define ADD_SUBGROUP(m_name, m_prefix) godot::ClassDB::add_property_subgroup(get_class_static(), m_name, m_prefix)
#define ADD_PROPERTY(m_property, m_setter, m_getter) godot::ClassDB::add_property(get_class_static(), m_property, m_setter, m_getter)
#define ADD_PROPERTYI(m_property, m_setter, m_getter, m_index) godot::ClassDB::add_property(get_class_static(), m_property, m_setter, m_getter, m_index)
namespace godot {
namespace internal {
Object *get_object_instance_binding(GodotObject *);
} // namespace internal
struct MethodInfo {
StringName name;
PropertyInfo return_val;
uint32_t flags;
int id = 0;
std::vector<PropertyInfo> arguments;
std::vector<Variant> default_arguments;
inline bool operator==(const MethodInfo &p_method) const { return id == p_method.id; }
inline bool operator<(const MethodInfo &p_method) const { return id == p_method.id ? (name < p_method.name) : (id < p_method.id); }
operator Dictionary() const;
static MethodInfo from_dict(const Dictionary &p_dict);
MethodInfo();
MethodInfo(StringName p_name);
template <class... Args>
MethodInfo(StringName p_name, const Args &...args);
MethodInfo(Variant::Type ret);
MethodInfo(Variant::Type ret, StringName p_name);
template <class... Args>
MethodInfo(Variant::Type ret, StringName p_name, const Args &...args);
MethodInfo(const PropertyInfo &p_ret, StringName p_name);
template <class... Args>
MethodInfo(const PropertyInfo &p_ret, StringName p_name, const Args &...);
};
template <class... Args>
MethodInfo::MethodInfo(StringName p_name, const Args &...args) :
name(p_name), flags(GDEXTENSION_METHOD_FLAG_NORMAL) {
arguments = { args... };
}
template <class... Args>
MethodInfo::MethodInfo(Variant::Type ret, StringName p_name, const Args &...args) :
name(p_name), flags(GDEXTENSION_METHOD_FLAG_NORMAL) {
return_val.type = ret;
arguments = { args... };
}
template <class... Args>
MethodInfo::MethodInfo(const PropertyInfo &p_ret, StringName p_name, const Args &...args) :
name(p_name), return_val(p_ret), flags(GDEXTENSION_METHOD_FLAG_NORMAL) {
arguments = { args... };
}
class ObjectDB {
public:
static Object *get_instance(uint64_t p_object_id) {
GDExtensionObjectPtr obj = internal::gdextension_interface_object_get_instance_from_id(p_object_id);
if (obj == nullptr) {
return nullptr;
}
return internal::get_object_instance_binding(obj);
}
};
template <class T>
T *Object::cast_to(Object *p_object) {
if (p_object == nullptr) {
return nullptr;
}
StringName class_name = T::get_class_static();
GDExtensionObjectPtr casted = internal::gdextension_interface_object_cast_to(p_object->_owner, internal::gdextension_interface_classdb_get_class_tag(class_name._native_ptr()));
if (casted == nullptr) {
return nullptr;
}
return dynamic_cast<T *>(internal::get_object_instance_binding(casted));
}
template <class T>
const T *Object::cast_to(const Object *p_object) {
if (p_object == nullptr) {
return nullptr;
}
StringName class_name = T::get_class_static();
GDExtensionObjectPtr casted = internal::gdextension_interface_object_cast_to(p_object->_owner, internal::gdextension_interface_classdb_get_class_tag(class_name._native_ptr()));
if (casted == nullptr) {
return nullptr;
}
return dynamic_cast<const T *>(internal::get_object_instance_binding(casted));
}
} // namespace godot
#endif // GODOT_OBJECT_HPP

View File

@@ -0,0 +1,62 @@
/**************************************************************************/
/* object_id.hpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#ifndef GODOT_OBJECT_ID_HPP
#define GODOT_OBJECT_ID_HPP
#include <godot_cpp/core/defs.hpp>
namespace godot {
class ObjectID {
uint64_t id = 0;
public:
_FORCE_INLINE_ bool is_ref_counted() const { return (id & (uint64_t(1) << 63)) != 0; }
_FORCE_INLINE_ bool is_valid() const { return id != 0; }
_FORCE_INLINE_ bool is_null() const { return id == 0; }
_FORCE_INLINE_ operator uint64_t() const { return id; }
_FORCE_INLINE_ operator int64_t() const { return id; }
_FORCE_INLINE_ bool operator==(const ObjectID &p_id) const { return id == p_id.id; }
_FORCE_INLINE_ bool operator!=(const ObjectID &p_id) const { return id != p_id.id; }
_FORCE_INLINE_ bool operator<(const ObjectID &p_id) const { return id < p_id.id; }
_FORCE_INLINE_ void operator=(int64_t p_int64) { id = p_int64; }
_FORCE_INLINE_ void operator=(uint64_t p_uint64) { id = p_uint64; }
_FORCE_INLINE_ ObjectID() {}
_FORCE_INLINE_ explicit ObjectID(const uint64_t p_id) { id = p_id; }
_FORCE_INLINE_ explicit ObjectID(const int64_t p_id) { id = p_id; }
};
} // namespace godot
#endif // GODOT_OBJECT_ID_HPP

View File

@@ -0,0 +1,87 @@
/**************************************************************************/
/* property_info.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_PROPERTY_INFO_HPP
#define GODOT_PROPERTY_INFO_HPP
#include <godot_cpp/core/defs.hpp>
#include <godot_cpp/classes/global_constants.hpp>
#include <godot_cpp/variant/variant.hpp>
#include <godot_cpp/godot.hpp>
#include <gdextension_interface.h>
namespace godot {
struct PropertyInfo {
Variant::Type type = Variant::NIL;
StringName name;
StringName class_name;
uint32_t hint = 0;
String hint_string;
uint32_t usage = 7;
PropertyInfo() = default;
PropertyInfo(Variant::Type p_type, const StringName &p_name, PropertyHint p_hint = PROPERTY_HINT_NONE, const String &p_hint_string = "", uint32_t p_usage = PROPERTY_USAGE_DEFAULT, const StringName &p_class_name = "") :
type(p_type),
name(p_name),
hint(p_hint),
hint_string(p_hint_string),
usage(p_usage) {
if (hint == PROPERTY_HINT_RESOURCE_TYPE) {
class_name = hint_string;
} else {
class_name = p_class_name;
}
}
PropertyInfo(GDExtensionVariantType p_type, const StringName &p_name, PropertyHint p_hint = PROPERTY_HINT_NONE, const String &p_hint_string = "", uint32_t p_usage = PROPERTY_USAGE_DEFAULT, const StringName &p_class_name = "") :
PropertyInfo((Variant::Type)p_type, p_name, p_hint, p_hint_string, p_usage, p_class_name) {}
PropertyInfo(const GDExtensionPropertyInfo *p_info) :
PropertyInfo(p_info->type, *reinterpret_cast<StringName *>(p_info->name), (PropertyHint)p_info->hint, *reinterpret_cast<String *>(p_info->hint_string), p_info->usage, *reinterpret_cast<StringName *>(p_info->class_name)) {}
void _update(GDExtensionPropertyInfo *p_info) {
p_info->type = (GDExtensionVariantType)type;
*(reinterpret_cast<StringName *>(p_info->name)) = name;
p_info->hint = hint;
*(reinterpret_cast<String *>(p_info->hint_string)) = hint_string;
p_info->usage = usage;
*(reinterpret_cast<StringName *>(p_info->class_name)) = class_name;
}
};
} // namespace godot
#endif // GODOT_PROPERTY_INFO_HPP

View File

@@ -0,0 +1,402 @@
/**************************************************************************/
/* type_info.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_TYPE_INFO_HPP
#define GODOT_TYPE_INFO_HPP
#include <godot_cpp/core/object.hpp>
#include <godot_cpp/variant/typed_array.hpp>
#include <godot_cpp/variant/variant.hpp>
#include <gdextension_interface.h>
namespace godot {
template <bool C, typename T = void>
struct EnableIf {
typedef T type;
};
template <typename T>
struct EnableIf<false, T> {
};
template <typename, typename>
struct TypesAreSame {
static bool const value = false;
};
template <typename A>
struct TypesAreSame<A, A> {
static bool const value = true;
};
template <typename B, typename D>
struct TypeInherits {
static D *get_d();
static char (&test(B *))[1];
static char (&test(...))[2];
static bool const value = sizeof(test(get_d())) == sizeof(char) &&
!TypesAreSame<B volatile const, void volatile const>::value;
};
static PropertyInfo make_property_info(Variant::Type p_type, const StringName &p_name, uint32_t p_hint = PROPERTY_HINT_NONE, const String &p_hint_string = "", uint32_t p_usage = PROPERTY_USAGE_DEFAULT, const StringName &p_class_name = "") {
PropertyInfo info;
info.type = p_type;
info.name = p_name;
info.hint = p_hint;
info.hint_string = p_hint_string;
info.usage = p_usage;
if (p_hint == PROPERTY_HINT_RESOURCE_TYPE) {
info.class_name = p_hint_string;
} else {
info.class_name = p_class_name;
}
return info;
}
// If the compiler fails because it's trying to instantiate the primary 'GetTypeInfo' template
// instead of one of the specializations, it's most likely because the type 'T' is not supported.
// If 'T' is a class that inherits 'Object', make sure it can see the actual class declaration
// 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>
struct GetTypeInfo;
#define MAKE_TYPE_INFO(m_type, m_var_type) \
template <> \
struct GetTypeInfo<m_type> { \
static constexpr GDExtensionVariantType VARIANT_TYPE = m_var_type; \
static constexpr GDExtensionClassMethodArgumentMetadata METADATA = GDEXTENSION_METHOD_ARGUMENT_METADATA_NONE; \
static inline PropertyInfo get_class_info() { \
return make_property_info((Variant::Type)VARIANT_TYPE, ""); \
} \
}; \
template <> \
struct GetTypeInfo<const m_type &> { \
static constexpr GDExtensionVariantType VARIANT_TYPE = m_var_type; \
static constexpr GDExtensionClassMethodArgumentMetadata METADATA = GDEXTENSION_METHOD_ARGUMENT_METADATA_NONE; \
static inline PropertyInfo get_class_info() { \
return make_property_info((Variant::Type)VARIANT_TYPE, ""); \
} \
};
#define MAKE_TYPE_INFO_WITH_META(m_type, m_var_type, m_metadata) \
template <> \
struct GetTypeInfo<m_type> { \
static constexpr GDExtensionVariantType VARIANT_TYPE = m_var_type; \
static constexpr GDExtensionClassMethodArgumentMetadata METADATA = m_metadata; \
static inline PropertyInfo get_class_info() { \
return make_property_info((Variant::Type)VARIANT_TYPE, ""); \
} \
}; \
template <> \
struct GetTypeInfo<const m_type &> { \
static constexpr GDExtensionVariantType VARIANT_TYPE = m_var_type; \
static constexpr GDExtensionClassMethodArgumentMetadata METADATA = m_metadata; \
static inline PropertyInfo get_class_info() { \
return make_property_info((Variant::Type)VARIANT_TYPE, ""); \
} \
};
MAKE_TYPE_INFO(bool, GDEXTENSION_VARIANT_TYPE_BOOL)
MAKE_TYPE_INFO_WITH_META(uint8_t, GDEXTENSION_VARIANT_TYPE_INT, GDEXTENSION_METHOD_ARGUMENT_METADATA_INT_IS_UINT8)
MAKE_TYPE_INFO_WITH_META(int8_t, GDEXTENSION_VARIANT_TYPE_INT, GDEXTENSION_METHOD_ARGUMENT_METADATA_INT_IS_INT8)
MAKE_TYPE_INFO_WITH_META(uint16_t, GDEXTENSION_VARIANT_TYPE_INT, GDEXTENSION_METHOD_ARGUMENT_METADATA_INT_IS_UINT16)
MAKE_TYPE_INFO_WITH_META(int16_t, GDEXTENSION_VARIANT_TYPE_INT, GDEXTENSION_METHOD_ARGUMENT_METADATA_INT_IS_INT16)
MAKE_TYPE_INFO_WITH_META(uint32_t, GDEXTENSION_VARIANT_TYPE_INT, GDEXTENSION_METHOD_ARGUMENT_METADATA_INT_IS_UINT32)
MAKE_TYPE_INFO_WITH_META(int32_t, GDEXTENSION_VARIANT_TYPE_INT, GDEXTENSION_METHOD_ARGUMENT_METADATA_INT_IS_INT32)
MAKE_TYPE_INFO_WITH_META(uint64_t, GDEXTENSION_VARIANT_TYPE_INT, GDEXTENSION_METHOD_ARGUMENT_METADATA_INT_IS_UINT64)
MAKE_TYPE_INFO_WITH_META(int64_t, GDEXTENSION_VARIANT_TYPE_INT, GDEXTENSION_METHOD_ARGUMENT_METADATA_INT_IS_INT64)
MAKE_TYPE_INFO(char16_t, GDEXTENSION_VARIANT_TYPE_INT)
MAKE_TYPE_INFO(char32_t, GDEXTENSION_VARIANT_TYPE_INT)
MAKE_TYPE_INFO_WITH_META(float, GDEXTENSION_VARIANT_TYPE_FLOAT, GDEXTENSION_METHOD_ARGUMENT_METADATA_REAL_IS_FLOAT)
MAKE_TYPE_INFO_WITH_META(double, GDEXTENSION_VARIANT_TYPE_FLOAT, GDEXTENSION_METHOD_ARGUMENT_METADATA_REAL_IS_DOUBLE)
MAKE_TYPE_INFO(String, GDEXTENSION_VARIANT_TYPE_STRING)
MAKE_TYPE_INFO(Vector2, GDEXTENSION_VARIANT_TYPE_VECTOR2)
MAKE_TYPE_INFO(Vector2i, GDEXTENSION_VARIANT_TYPE_VECTOR2I)
MAKE_TYPE_INFO(Rect2, GDEXTENSION_VARIANT_TYPE_RECT2)
MAKE_TYPE_INFO(Rect2i, GDEXTENSION_VARIANT_TYPE_RECT2I)
MAKE_TYPE_INFO(Vector3, GDEXTENSION_VARIANT_TYPE_VECTOR3)
MAKE_TYPE_INFO(Vector3i, GDEXTENSION_VARIANT_TYPE_VECTOR3I)
MAKE_TYPE_INFO(Transform2D, GDEXTENSION_VARIANT_TYPE_TRANSFORM2D)
MAKE_TYPE_INFO(Vector4, GDEXTENSION_VARIANT_TYPE_VECTOR4)
MAKE_TYPE_INFO(Vector4i, GDEXTENSION_VARIANT_TYPE_VECTOR4I)
MAKE_TYPE_INFO(Plane, GDEXTENSION_VARIANT_TYPE_PLANE)
MAKE_TYPE_INFO(Quaternion, GDEXTENSION_VARIANT_TYPE_QUATERNION)
MAKE_TYPE_INFO(AABB, GDEXTENSION_VARIANT_TYPE_AABB)
MAKE_TYPE_INFO(Basis, GDEXTENSION_VARIANT_TYPE_BASIS)
MAKE_TYPE_INFO(Transform3D, GDEXTENSION_VARIANT_TYPE_TRANSFORM3D)
MAKE_TYPE_INFO(Projection, GDEXTENSION_VARIANT_TYPE_PROJECTION)
MAKE_TYPE_INFO(Color, GDEXTENSION_VARIANT_TYPE_COLOR)
MAKE_TYPE_INFO(StringName, GDEXTENSION_VARIANT_TYPE_STRING_NAME)
MAKE_TYPE_INFO(NodePath, GDEXTENSION_VARIANT_TYPE_NODE_PATH)
MAKE_TYPE_INFO(RID, GDEXTENSION_VARIANT_TYPE_RID)
MAKE_TYPE_INFO(Callable, GDEXTENSION_VARIANT_TYPE_CALLABLE)
MAKE_TYPE_INFO(Signal, GDEXTENSION_VARIANT_TYPE_SIGNAL)
MAKE_TYPE_INFO(Dictionary, GDEXTENSION_VARIANT_TYPE_DICTIONARY)
MAKE_TYPE_INFO(Array, GDEXTENSION_VARIANT_TYPE_ARRAY)
MAKE_TYPE_INFO(PackedByteArray, GDEXTENSION_VARIANT_TYPE_PACKED_BYTE_ARRAY)
MAKE_TYPE_INFO(PackedInt32Array, GDEXTENSION_VARIANT_TYPE_PACKED_INT32_ARRAY)
MAKE_TYPE_INFO(PackedInt64Array, GDEXTENSION_VARIANT_TYPE_PACKED_INT64_ARRAY)
MAKE_TYPE_INFO(PackedFloat32Array, GDEXTENSION_VARIANT_TYPE_PACKED_FLOAT32_ARRAY)
MAKE_TYPE_INFO(PackedFloat64Array, GDEXTENSION_VARIANT_TYPE_PACKED_FLOAT64_ARRAY)
MAKE_TYPE_INFO(PackedStringArray, GDEXTENSION_VARIANT_TYPE_PACKED_STRING_ARRAY)
MAKE_TYPE_INFO(PackedVector2Array, GDEXTENSION_VARIANT_TYPE_PACKED_VECTOR2_ARRAY)
MAKE_TYPE_INFO(PackedVector3Array, GDEXTENSION_VARIANT_TYPE_PACKED_VECTOR3_ARRAY)
MAKE_TYPE_INFO(PackedColorArray, GDEXTENSION_VARIANT_TYPE_PACKED_COLOR_ARRAY)
// For variant.
template <>
struct GetTypeInfo<Variant> {
static constexpr GDExtensionVariantType VARIANT_TYPE = GDEXTENSION_VARIANT_TYPE_NIL;
static constexpr GDExtensionClassMethodArgumentMetadata METADATA = GDEXTENSION_METHOD_ARGUMENT_METADATA_NONE;
static inline PropertyInfo get_class_info() {
return make_property_info(Variant::Type::NIL, "", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_NIL_IS_VARIANT);
}
};
template <>
struct GetTypeInfo<const Variant &> {
static constexpr GDExtensionVariantType VARIANT_TYPE = GDEXTENSION_VARIANT_TYPE_NIL;
static constexpr GDExtensionClassMethodArgumentMetadata METADATA = GDEXTENSION_METHOD_ARGUMENT_METADATA_NONE;
static inline PropertyInfo get_class_info() {
return make_property_info(Variant::Type::NIL, "", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_NIL_IS_VARIANT);
}
};
template <typename T>
struct GetTypeInfo<T *, typename EnableIf<TypeInherits<Object, T>::value>::type> {
static const GDExtensionVariantType VARIANT_TYPE = GDEXTENSION_VARIANT_TYPE_OBJECT;
static const GDExtensionClassMethodArgumentMetadata METADATA = GDEXTENSION_METHOD_ARGUMENT_METADATA_NONE;
static inline PropertyInfo get_class_info() {
return make_property_info(Variant::Type::OBJECT, "", PROPERTY_HINT_RESOURCE_TYPE, T::get_class_static());
}
};
template <typename T>
struct GetTypeInfo<const T *, typename EnableIf<TypeInherits<Object, T>::value>::type> {
static const GDExtensionVariantType VARIANT_TYPE = GDEXTENSION_VARIANT_TYPE_OBJECT;
static const GDExtensionClassMethodArgumentMetadata METADATA = GDEXTENSION_METHOD_ARGUMENT_METADATA_NONE;
static inline PropertyInfo get_class_info() {
return make_property_info(Variant::Type::OBJECT, "", PROPERTY_HINT_RESOURCE_TYPE, T::get_class_static());
}
};
inline String enum_qualified_name_to_class_info_name(const String &p_qualified_name) {
PackedStringArray parts = p_qualified_name.split("::", false);
if (parts.size() <= 2) {
return String(".").join(parts);
}
// Contains namespace. We only want the class and enum names.
return parts[parts.size() - 2] + "." + parts[parts.size() - 1];
}
#define TEMPL_MAKE_ENUM_TYPE_INFO(m_enum, m_impl) \
template <> \
struct GetTypeInfo<m_impl> { \
static const Variant::Type VARIANT_TYPE = Variant::INT; \
static const GDExtensionClassMethodArgumentMetadata METADATA = GDEXTENSION_METHOD_ARGUMENT_METADATA_NONE; \
static inline PropertyInfo get_class_info() { \
return make_property_info(Variant::Type::INT, "", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_CLASS_IS_ENUM, \
enum_qualified_name_to_class_info_name(#m_enum)); \
} \
};
#define MAKE_ENUM_TYPE_INFO(m_enum) \
TEMPL_MAKE_ENUM_TYPE_INFO(m_enum, m_enum) \
TEMPL_MAKE_ENUM_TYPE_INFO(m_enum, m_enum const) \
TEMPL_MAKE_ENUM_TYPE_INFO(m_enum, m_enum &) \
TEMPL_MAKE_ENUM_TYPE_INFO(m_enum, const m_enum &)
template <typename T>
inline StringName _gde_constant_get_enum_name(T param, StringName p_constant) {
if (GetTypeInfo<T>::VARIANT_TYPE == Variant::NIL) {
ERR_PRINT(("Missing VARIANT_ENUM_CAST for constant's enum: " + String(p_constant)).utf8().get_data());
}
return GetTypeInfo<T>::get_class_info().class_name;
}
template <class T>
class BitField {
int64_t value = 0;
public:
_FORCE_INLINE_ void set_flag(T p_flag) { value |= p_flag; }
_FORCE_INLINE_ bool has_flag(T p_flag) const { return value & p_flag; }
_FORCE_INLINE_ void clear_flag(T p_flag) { return value &= ~p_flag; }
_FORCE_INLINE_ BitField(int64_t p_value) { value = p_value; }
_FORCE_INLINE_ operator int64_t() const { return value; }
_FORCE_INLINE_ operator Variant() const { return value; }
};
#define TEMPL_MAKE_BITFIELD_TYPE_INFO(m_enum, m_impl) \
template <> \
struct GetTypeInfo<m_impl> { \
static const Variant::Type VARIANT_TYPE = Variant::INT; \
static const GDExtensionClassMethodArgumentMetadata METADATA = GDEXTENSION_METHOD_ARGUMENT_METADATA_NONE; \
static inline PropertyInfo get_class_info() { \
return make_property_info(Variant::Type::INT, "", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_CLASS_IS_BITFIELD, \
enum_qualified_name_to_class_info_name(#m_enum)); \
} \
}; \
template <> \
struct GetTypeInfo<BitField<m_impl>> { \
static const Variant::Type VARIANT_TYPE = Variant::INT; \
static const GDExtensionClassMethodArgumentMetadata METADATA = GDEXTENSION_METHOD_ARGUMENT_METADATA_NONE; \
static inline PropertyInfo get_class_info() { \
return make_property_info(Variant::Type::INT, "", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_CLASS_IS_BITFIELD, \
enum_qualified_name_to_class_info_name(#m_enum)); \
} \
};
#define MAKE_BITFIELD_TYPE_INFO(m_enum) \
TEMPL_MAKE_BITFIELD_TYPE_INFO(m_enum, m_enum) \
TEMPL_MAKE_BITFIELD_TYPE_INFO(m_enum, m_enum const) \
TEMPL_MAKE_BITFIELD_TYPE_INFO(m_enum, m_enum &) \
TEMPL_MAKE_BITFIELD_TYPE_INFO(m_enum, const m_enum &)
template <typename T>
inline StringName _gde_constant_get_bitfield_name(T param, StringName p_constant) {
if (GetTypeInfo<T>::VARIANT_TYPE == Variant::NIL) {
ERR_PRINT(("Missing VARIANT_ENUM_CAST for constant's bitfield: " + String(p_constant)).utf8().get_data());
}
return GetTypeInfo<BitField<T>>::get_class_info().class_name;
}
template <class T>
struct PtrToArg<TypedArray<T>> {
_FORCE_INLINE_ static TypedArray<T> convert(const void *p_ptr) {
return TypedArray<T>(*reinterpret_cast<const Array *>(p_ptr));
}
typedef Array EncodeT;
_FORCE_INLINE_ static void encode(TypedArray<T> p_val, void *p_ptr) {
*reinterpret_cast<Array *>(p_ptr) = p_val;
}
};
template <class T>
struct PtrToArg<const TypedArray<T> &> {
typedef Array EncodeT;
_FORCE_INLINE_ static TypedArray<T>
convert(const void *p_ptr) {
return TypedArray<T>(*reinterpret_cast<const Array *>(p_ptr));
}
};
template <typename T>
struct GetTypeInfo<TypedArray<T>> {
static constexpr GDExtensionVariantType VARIANT_TYPE = GDEXTENSION_VARIANT_TYPE_ARRAY;
static constexpr GDExtensionClassMethodArgumentMetadata METADATA = GDEXTENSION_METHOD_ARGUMENT_METADATA_NONE;
static inline PropertyInfo get_class_info() {
return make_property_info(Variant::Type::ARRAY, "", PROPERTY_HINT_ARRAY_TYPE, T::get_class_static());
}
};
template <typename T>
struct GetTypeInfo<const TypedArray<T> &> {
static constexpr GDExtensionVariantType VARIANT_TYPE = GDEXTENSION_VARIANT_TYPE_ARRAY;
static constexpr GDExtensionClassMethodArgumentMetadata METADATA = GDEXTENSION_METHOD_ARGUMENT_METADATA_NONE;
static inline PropertyInfo get_class_info() {
return make_property_info(Variant::Type::ARRAY, "", PROPERTY_HINT_ARRAY_TYPE, T::get_class_static());
}
};
#define MAKE_TYPED_ARRAY_INFO(m_type, m_variant_type) \
template <> \
struct GetTypeInfo<TypedArray<m_type>> { \
static constexpr GDExtensionVariantType VARIANT_TYPE = GDEXTENSION_VARIANT_TYPE_ARRAY; \
static constexpr GDExtensionClassMethodArgumentMetadata METADATA = GDEXTENSION_METHOD_ARGUMENT_METADATA_NONE; \
static inline PropertyInfo get_class_info() { \
return make_property_info(Variant::Type::ARRAY, "", PROPERTY_HINT_ARRAY_TYPE, Variant::get_type_name(m_variant_type).utf8().get_data()); \
} \
}; \
template <> \
struct GetTypeInfo<const TypedArray<m_type> &> { \
static constexpr GDExtensionVariantType VARIANT_TYPE = GDEXTENSION_VARIANT_TYPE_ARRAY; \
static constexpr GDExtensionClassMethodArgumentMetadata METADATA = GDEXTENSION_METHOD_ARGUMENT_METADATA_NONE; \
static inline PropertyInfo get_class_info() { \
return make_property_info(Variant::Type::ARRAY, "", PROPERTY_HINT_ARRAY_TYPE, Variant::get_type_name(m_variant_type).utf8().get_data()); \
} \
};
MAKE_TYPED_ARRAY_INFO(bool, Variant::BOOL)
MAKE_TYPED_ARRAY_INFO(uint8_t, Variant::INT)
MAKE_TYPED_ARRAY_INFO(int8_t, Variant::INT)
MAKE_TYPED_ARRAY_INFO(uint16_t, Variant::INT)
MAKE_TYPED_ARRAY_INFO(int16_t, Variant::INT)
MAKE_TYPED_ARRAY_INFO(uint32_t, Variant::INT)
MAKE_TYPED_ARRAY_INFO(int32_t, Variant::INT)
MAKE_TYPED_ARRAY_INFO(uint64_t, Variant::INT)
MAKE_TYPED_ARRAY_INFO(int64_t, Variant::INT)
MAKE_TYPED_ARRAY_INFO(float, Variant::FLOAT)
MAKE_TYPED_ARRAY_INFO(double, Variant::FLOAT)
MAKE_TYPED_ARRAY_INFO(String, Variant::STRING)
MAKE_TYPED_ARRAY_INFO(Vector2, Variant::VECTOR2)
MAKE_TYPED_ARRAY_INFO(Vector2i, Variant::VECTOR2I)
MAKE_TYPED_ARRAY_INFO(Rect2, Variant::RECT2)
MAKE_TYPED_ARRAY_INFO(Rect2i, Variant::RECT2I)
MAKE_TYPED_ARRAY_INFO(Vector3, Variant::VECTOR3)
MAKE_TYPED_ARRAY_INFO(Vector3i, Variant::VECTOR3I)
MAKE_TYPED_ARRAY_INFO(Transform2D, Variant::TRANSFORM2D)
MAKE_TYPED_ARRAY_INFO(Plane, Variant::PLANE)
MAKE_TYPED_ARRAY_INFO(Quaternion, Variant::QUATERNION)
MAKE_TYPED_ARRAY_INFO(AABB, Variant::AABB)
MAKE_TYPED_ARRAY_INFO(Basis, Variant::BASIS)
MAKE_TYPED_ARRAY_INFO(Transform3D, Variant::TRANSFORM3D)
MAKE_TYPED_ARRAY_INFO(Color, Variant::COLOR)
MAKE_TYPED_ARRAY_INFO(StringName, Variant::STRING_NAME)
MAKE_TYPED_ARRAY_INFO(NodePath, Variant::NODE_PATH)
MAKE_TYPED_ARRAY_INFO(RID, Variant::RID)
MAKE_TYPED_ARRAY_INFO(Callable, Variant::CALLABLE)
MAKE_TYPED_ARRAY_INFO(Signal, Variant::SIGNAL)
MAKE_TYPED_ARRAY_INFO(Dictionary, Variant::DICTIONARY)
MAKE_TYPED_ARRAY_INFO(Array, Variant::ARRAY)
/*
MAKE_TYPED_ARRAY_INFO(Vector<uint8_t>, Variant::PACKED_BYTE_ARRAY)
MAKE_TYPED_ARRAY_INFO(Vector<int32_t>, Variant::PACKED_INT32_ARRAY)
MAKE_TYPED_ARRAY_INFO(Vector<int64_t>, Variant::PACKED_INT64_ARRAY)
MAKE_TYPED_ARRAY_INFO(Vector<float>, Variant::PACKED_FLOAT32_ARRAY)
MAKE_TYPED_ARRAY_INFO(Vector<double>, Variant::PACKED_FLOAT64_ARRAY)
MAKE_TYPED_ARRAY_INFO(Vector<String>, Variant::PACKED_STRING_ARRAY)
MAKE_TYPED_ARRAY_INFO(Vector<Vector2>, Variant::PACKED_VECTOR2_ARRAY)
MAKE_TYPED_ARRAY_INFO(Vector<Vector3>, Variant::PACKED_VECTOR3_ARRAY)
MAKE_TYPED_ARRAY_INFO(Vector<Color>, Variant::PACKED_COLOR_ARRAY)
*/
#define CLASS_INFO(m_type) (GetTypeInfo<m_type *>::get_class_info())
} // namespace godot
#endif // GODOT_TYPE_INFO_HPP

249
include/godot_cpp/godot.hpp Normal file
View File

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

View File

@@ -0,0 +1,402 @@
/**************************************************************************/
/* cowdata.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_COWDATA_HPP
#define GODOT_COWDATA_HPP
#include <godot_cpp/classes/global_constants.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>
class Vector;
template <class T, class V>
class VMap;
template <class T>
class CharStringT;
// 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>
class CowData {
template <class TV>
friend class Vector;
template <class TV, class VV>
friend class VMap;
template <class TS>
friend class CharStringT;
private:
mutable T *_ptr = nullptr;
// internal helpers
_FORCE_INLINE_ SafeNumeric<uint32_t> *_get_refcount() const {
if (!_ptr) {
return nullptr;
}
return reinterpret_cast<SafeNumeric<uint32_t> *>(_ptr) - 2;
}
_FORCE_INLINE_ uint32_t *_get_size() const {
if (!_ptr) {
return nullptr;
}
return reinterpret_cast<uint32_t *>(_ptr) - 1;
}
_FORCE_INLINE_ T *_get_data() const {
if (!_ptr) {
return nullptr;
}
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 (unlikely(p_elements == 0)) {
*out = 0;
return true;
}
#if defined(__GNUC__)
size_t o;
size_t 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)) {
return false; // No longer allocated here.
}
#else
// Speed is more important than correctness here, do the operations unchecked
// and hope for the best.
*out = _get_alloc_size(p_elements);
#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();
public:
void operator=(const CowData<T> &p_from) { _ref(p_from); }
_FORCE_INLINE_ T *ptrw() {
_copy_on_write();
return (T *)_get_data();
}
_FORCE_INLINE_ const T *ptr() const {
return _get_data();
}
_FORCE_INLINE_ int size() const {
uint32_t *size = (uint32_t *)_get_size();
if (size) {
return *size;
} else {
return 0;
}
}
_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) {
ERR_FAIL_INDEX(p_index, size());
_copy_on_write();
_get_data()[p_index] = p_elem;
}
_FORCE_INLINE_ T &get_m(int p_index) {
CRASH_BAD_INDEX(p_index, size());
_copy_on_write();
return _get_data()[p_index];
}
_FORCE_INLINE_ const T &get(int p_index) const {
CRASH_BAD_INDEX(p_index, size());
return _get_data()[p_index];
}
Error resize(int p_size);
_FORCE_INLINE_ void remove_at(int p_index) {
ERR_FAIL_INDEX(p_index, size());
T *p = ptrw();
int len = size();
for (int i = p_index; i < len - 1; i++) {
p[i] = p[i + 1];
}
resize(len - 1);
}
Error insert(int 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--) {
set(i, get(i - 1));
}
set(p_pos, p_val);
return OK;
}
int find(const T &p_val, int p_from = 0) const;
_FORCE_INLINE_ CowData() {}
_FORCE_INLINE_ ~CowData();
_FORCE_INLINE_ CowData(CowData<T> &p_from) { _ref(p_from); }
};
template <class T>
void CowData<T>::_unref(void *p_data) {
if (!p_data) {
return;
}
SafeNumeric<uint32_t> *refc = _get_refcount();
if (refc->decrement() > 0) {
return; // still in use
}
// clean up
if (!std::is_trivially_destructible<T>::value) {
uint32_t *count = _get_size();
T *data = (T *)(count + 1);
for (uint32_t i = 0; i < *count; ++i) {
// call destructors
data[i].~T();
}
}
// free mem
Memory::free_static((uint8_t *)p_data, true);
}
template <class T>
uint32_t CowData<T>::_copy_on_write() {
if (!_ptr) {
return 0;
}
SafeNumeric<uint32_t> *refc = _get_refcount();
uint32_t rc = refc->get();
if (unlikely(rc > 1)) {
/* in use by more than me */
uint32_t current_size = *_get_size();
uint32_t *mem_new = (uint32_t *)Memory::alloc_static(_get_alloc_size(current_size), true);
new (mem_new - 2) SafeNumeric<uint32_t>(1); // refcount
*(mem_new - 1) = current_size; // size
T *_data = (T *)(mem_new);
// initialize new elements
if (std::is_trivially_copyable<T>::value) {
memcpy(mem_new, _ptr, current_size * sizeof(T));
} else {
for (uint32_t i = 0; i < current_size; i++) {
memnew_placement(&_data[i], T(_get_data()[i]));
}
}
_unref(_ptr);
_ptr = _data;
rc = 1;
}
return rc;
}
template <class T>
Error CowData<T>::resize(int p_size) {
ERR_FAIL_COND_V(p_size < 0, ERR_INVALID_PARAMETER);
int current_size = size();
if (p_size == current_size) {
return OK;
}
if (p_size == 0) {
// wants to clean up
_unref(_ptr);
_ptr = nullptr;
return OK;
}
// possibly changing size, copy on write
uint32_t rc = _copy_on_write();
size_t current_alloc_size = _get_alloc_size(current_size);
size_t alloc_size;
ERR_FAIL_COND_V(!_get_alloc_size_checked(p_size, &alloc_size), ERR_OUT_OF_MEMORY);
if (p_size > current_size) {
if (alloc_size != current_alloc_size) {
if (current_size == 0) {
// alloc from scratch
uint32_t *ptr = (uint32_t *)Memory::alloc_static(alloc_size, true);
ERR_FAIL_NULL_V(ptr, ERR_OUT_OF_MEMORY);
*(ptr - 1) = 0; // size, currently none
new (ptr - 2) SafeNumeric<uint32_t>(1); // refcount
_ptr = (T *)ptr;
} else {
uint32_t *_ptrnew = (uint32_t *)Memory::realloc_static(_ptr, alloc_size, true);
ERR_FAIL_NULL_V(_ptrnew, ERR_OUT_OF_MEMORY);
new (_ptrnew - 2) SafeNumeric<uint32_t>(rc); // refcount
_ptr = (T *)(_ptrnew);
}
}
// construct the newly created elements
if (!std::is_trivially_constructible<T>::value) {
T *elems = _get_data();
for (int i = *_get_size(); i < p_size; i++) {
memnew_placement(&elems[i], T);
}
}
*_get_size() = p_size;
} else if (p_size < current_size) {
if (!std::is_trivially_destructible<T>::value) {
// deinitialize no longer needed elements
for (uint32_t i = p_size; i < *_get_size(); i++) {
T *t = &_get_data()[i];
t->~T();
}
}
if (alloc_size != current_alloc_size) {
uint32_t *_ptrnew = (uint32_t *)Memory::realloc_static(_ptr, alloc_size, true);
ERR_FAIL_NULL_V(_ptrnew, ERR_OUT_OF_MEMORY);
new (_ptrnew - 2) SafeNumeric<uint32_t>(rc); // refcount
_ptr = (T *)(_ptrnew);
}
*_get_size() = p_size;
}
return OK;
}
template <class T>
int CowData<T>::find(const T &p_val, int p_from) const {
int ret = -1;
if (p_from < 0 || size() == 0) {
return ret;
}
for (int i = p_from; i < size(); i++) {
if (get(i) == p_val) {
ret = i;
break;
}
}
return ret;
}
template <class T>
void CowData<T>::_ref(const CowData *p_from) {
_ref(*p_from);
}
template <class T>
void CowData<T>::_ref(const CowData &p_from) {
if (_ptr == p_from._ptr) {
return; // self assign, do nothing.
}
_unref(_ptr);
_ptr = nullptr;
if (!p_from._ptr) {
return; // nothing to do
}
if (p_from._get_refcount()->conditional_increment() > 0) { // could reference
_ptr = p_from._ptr;
}
}
template <class T>
CowData<T>::~CowData() {
_unref(_ptr);
}
#if defined(__GNUC__) && !defined(__clang__)
#pragma GCC diagnostic pop
#endif
} // namespace godot
#endif // GODOT_COWDATA_HPP

View File

@@ -0,0 +1,591 @@
/**************************************************************************/
/* hash_map.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_HASH_MAP_HPP
#define GODOT_HASH_MAP_HPP
#include <godot_cpp/core/error_macros.hpp>
#include <godot_cpp/core/memory.hpp>
#include <godot_cpp/templates/hashfuncs.hpp>
#include <godot_cpp/templates/pair.hpp>
namespace godot {
/**
* A HashMap implementation that uses open addressing with Robin Hood hashing.
* Robin Hood hashing swaps out entries that have a smaller probing distance
* than the to-be-inserted entry, that evens out the average probing distance
* and enables faster lookups. Backward shift deletion is employed to further
* improve the performance and to avoid infinite loops in rare cases.
*
* Keys and values are stored in a double linked list by insertion order. This
* has a slight performance overhead on lookup, which can be mostly compensated
* using a paged allocator if required.
*
* The assignment operator copy the pairs from one map to the other.
*/
template <class TKey, class TValue>
struct HashMapElement {
HashMapElement *next = nullptr;
HashMapElement *prev = nullptr;
KeyValue<TKey, TValue> data;
HashMapElement() {}
HashMapElement(const TKey &p_key, const TValue &p_value) :
data(p_key, p_value) {}
};
template <class TKey, class TValue,
class Hasher = HashMapHasherDefault,
class Comparator = HashMapComparatorDefault<TKey>,
class Allocator = DefaultTypedAllocator<HashMapElement<TKey, TValue>>>
class HashMap {
public:
const uint32_t MIN_CAPACITY_INDEX = 2; // Use a prime.
const float MAX_OCCUPANCY = 0.75;
const uint32_t EMPTY_HASH = 0;
private:
Allocator element_alloc;
HashMapElement<TKey, TValue> **elements = nullptr;
uint32_t *hashes = nullptr;
HashMapElement<TKey, TValue> *head_element = nullptr;
HashMapElement<TKey, TValue> *tail_element = nullptr;
uint32_t capacity_index = 0;
uint32_t num_elements = 0;
_FORCE_INLINE_ uint32_t _hash(const TKey &p_key) const {
uint32_t hash = Hasher::hash(p_key);
if (unlikely(hash == EMPTY_HASH)) {
hash = EMPTY_HASH + 1;
}
return hash;
}
_FORCE_INLINE_ uint32_t _get_probe_length(uint32_t p_pos, uint32_t p_hash, uint32_t p_capacity) const {
uint32_t original_pos = p_hash % p_capacity;
return (p_pos - original_pos + p_capacity) % p_capacity;
}
bool _lookup_pos(const TKey &p_key, uint32_t &r_pos) const {
if (elements == nullptr) {
return false; // Failed lookups, no elements
}
uint32_t capacity = hash_table_size_primes[capacity_index];
uint32_t hash = _hash(p_key);
uint32_t pos = hash % capacity;
uint32_t distance = 0;
while (true) {
if (hashes[pos] == EMPTY_HASH) {
return false;
}
if (distance > _get_probe_length(pos, hashes[pos], capacity)) {
return false;
}
if (hashes[pos] == hash && Comparator::compare(elements[pos]->data.key, p_key)) {
r_pos = pos;
return true;
}
pos = (pos + 1) % capacity;
distance++;
}
}
void _insert_with_hash(uint32_t p_hash, HashMapElement<TKey, TValue> *p_value) {
uint32_t capacity = hash_table_size_primes[capacity_index];
uint32_t hash = p_hash;
HashMapElement<TKey, TValue> *value = p_value;
uint32_t distance = 0;
uint32_t pos = hash % capacity;
while (true) {
if (hashes[pos] == EMPTY_HASH) {
elements[pos] = value;
hashes[pos] = hash;
num_elements++;
return;
}
// Not an empty slot, let's check the probing length of the existing one.
uint32_t existing_probe_len = _get_probe_length(pos, hashes[pos], capacity);
if (existing_probe_len < distance) {
SWAP(hash, hashes[pos]);
SWAP(value, elements[pos]);
distance = existing_probe_len;
}
pos = (pos + 1) % capacity;
distance++;
}
}
void _resize_and_rehash(uint32_t p_new_capacity_index) {
uint32_t old_capacity = hash_table_size_primes[capacity_index];
// Capacity can't be 0.
capacity_index = MAX((uint32_t)MIN_CAPACITY_INDEX, p_new_capacity_index);
uint32_t capacity = hash_table_size_primes[capacity_index];
HashMapElement<TKey, TValue> **old_elements = elements;
uint32_t *old_hashes = hashes;
num_elements = 0;
hashes = reinterpret_cast<uint32_t *>(Memory::alloc_static(sizeof(uint32_t) * capacity));
elements = reinterpret_cast<HashMapElement<TKey, TValue> **>(Memory::alloc_static(sizeof(HashMapElement<TKey, TValue> *) * capacity));
for (uint32_t i = 0; i < capacity; i++) {
hashes[i] = 0;
elements[i] = nullptr;
}
if (old_capacity == 0) {
// Nothing to do.
return;
}
for (uint32_t i = 0; i < old_capacity; i++) {
if (old_hashes[i] == EMPTY_HASH) {
continue;
}
_insert_with_hash(old_hashes[i], old_elements[i]);
}
Memory::free_static(old_elements);
Memory::free_static(old_hashes);
}
_FORCE_INLINE_ HashMapElement<TKey, TValue> *_insert(const TKey &p_key, const TValue &p_value, bool p_front_insert = false) {
uint32_t capacity = hash_table_size_primes[capacity_index];
if (unlikely(elements == nullptr)) {
// Allocate on demand to save memory.
hashes = reinterpret_cast<uint32_t *>(Memory::alloc_static(sizeof(uint32_t) * capacity));
elements = reinterpret_cast<HashMapElement<TKey, TValue> **>(Memory::alloc_static(sizeof(HashMapElement<TKey, TValue> *) * capacity));
for (uint32_t i = 0; i < capacity; i++) {
hashes[i] = EMPTY_HASH;
elements[i] = nullptr;
}
}
uint32_t pos = 0;
bool exists = _lookup_pos(p_key, pos);
if (exists) {
elements[pos]->data.value = p_value;
return elements[pos];
} else {
if (num_elements + 1 > MAX_OCCUPANCY * capacity) {
ERR_FAIL_COND_V_MSG(capacity_index + 1 == HASH_TABLE_SIZE_MAX, nullptr, "Hash table maximum capacity reached, aborting insertion.");
_resize_and_rehash(capacity_index + 1);
}
HashMapElement<TKey, TValue> *elem = element_alloc.new_allocation(HashMapElement<TKey, TValue>(p_key, p_value));
if (tail_element == nullptr) {
head_element = elem;
tail_element = elem;
} else if (p_front_insert) {
head_element->prev = elem;
elem->next = head_element;
head_element = elem;
} else {
tail_element->next = elem;
elem->prev = tail_element;
tail_element = elem;
}
uint32_t hash = _hash(p_key);
_insert_with_hash(hash, elem);
return elem;
}
}
public:
_FORCE_INLINE_ uint32_t get_capacity() const { return hash_table_size_primes[capacity_index]; }
_FORCE_INLINE_ uint32_t size() const { return num_elements; }
/* Standard Godot Container API */
bool is_empty() const {
return num_elements == 0;
}
void clear() {
if (elements == nullptr) {
return;
}
uint32_t capacity = hash_table_size_primes[capacity_index];
for (uint32_t i = 0; i < capacity; i++) {
if (hashes[i] == EMPTY_HASH) {
continue;
}
hashes[i] = EMPTY_HASH;
element_alloc.delete_allocation(elements[i]);
elements[i] = nullptr;
}
tail_element = nullptr;
head_element = nullptr;
num_elements = 0;
}
TValue &get(const TKey &p_key) {
uint32_t pos = 0;
bool exists = _lookup_pos(p_key, pos);
CRASH_COND_MSG(!exists, "HashMap key not found.");
return elements[pos]->data.value;
}
const TValue &get(const TKey &p_key) const {
uint32_t pos = 0;
bool exists = _lookup_pos(p_key, pos);
CRASH_COND_MSG(!exists, "HashMap key not found.");
return elements[pos]->data.value;
}
const TValue *getptr(const TKey &p_key) const {
uint32_t pos = 0;
bool exists = _lookup_pos(p_key, pos);
if (exists) {
return &elements[pos]->data.value;
}
return nullptr;
}
TValue *getptr(const TKey &p_key) {
uint32_t pos = 0;
bool exists = _lookup_pos(p_key, pos);
if (exists) {
return &elements[pos]->data.value;
}
return nullptr;
}
_FORCE_INLINE_ bool has(const TKey &p_key) const {
uint32_t _pos = 0;
return _lookup_pos(p_key, _pos);
}
bool erase(const TKey &p_key) {
uint32_t pos = 0;
bool exists = _lookup_pos(p_key, pos);
if (!exists) {
return false;
}
uint32_t capacity = hash_table_size_primes[capacity_index];
uint32_t next_pos = (pos + 1) % capacity;
while (hashes[next_pos] != EMPTY_HASH && _get_probe_length(next_pos, hashes[next_pos], capacity) != 0) {
SWAP(hashes[next_pos], hashes[pos]);
SWAP(elements[next_pos], elements[pos]);
pos = next_pos;
next_pos = (pos + 1) % capacity;
}
hashes[pos] = EMPTY_HASH;
if (head_element == elements[pos]) {
head_element = elements[pos]->next;
}
if (tail_element == elements[pos]) {
tail_element = elements[pos]->prev;
}
if (elements[pos]->prev) {
elements[pos]->prev->next = elements[pos]->next;
}
if (elements[pos]->next) {
elements[pos]->next->prev = elements[pos]->prev;
}
element_alloc.delete_allocation(elements[pos]);
elements[pos] = nullptr;
num_elements--;
return true;
}
// Reserves space for a number of elements, useful to avoid many resizes and rehashes.
// If adding a known (possibly large) number of elements at once, must be larger than old capacity.
void reserve(uint32_t p_new_capacity) {
uint32_t new_index = capacity_index;
while (hash_table_size_primes[new_index] < p_new_capacity) {
ERR_FAIL_COND_MSG(new_index + 1 == (uint32_t)HASH_TABLE_SIZE_MAX, nullptr);
new_index++;
}
if (new_index == capacity_index) {
return;
}
if (elements == nullptr) {
capacity_index = new_index;
return; // Unallocated yet.
}
_resize_and_rehash(new_index);
}
/** Iterator API **/
struct ConstIterator {
_FORCE_INLINE_ const KeyValue<TKey, TValue> &operator*() const {
return E->data;
}
_FORCE_INLINE_ const KeyValue<TKey, TValue> *operator->() const { return &E->data; }
_FORCE_INLINE_ ConstIterator &operator++() {
if (E) {
E = E->next;
}
return *this;
}
_FORCE_INLINE_ ConstIterator &operator--() {
if (E) {
E = E->prev;
}
return *this;
}
_FORCE_INLINE_ bool operator==(const ConstIterator &b) const { return E == b.E; }
_FORCE_INLINE_ bool operator!=(const ConstIterator &b) const { return E != b.E; }
_FORCE_INLINE_ explicit operator bool() const {
return E != nullptr;
}
_FORCE_INLINE_ ConstIterator(const HashMapElement<TKey, TValue> *p_E) { E = p_E; }
_FORCE_INLINE_ ConstIterator() {}
_FORCE_INLINE_ ConstIterator(const ConstIterator &p_it) { E = p_it.E; }
_FORCE_INLINE_ void operator=(const ConstIterator &p_it) {
E = p_it.E;
}
private:
const HashMapElement<TKey, TValue> *E = nullptr;
};
struct Iterator {
_FORCE_INLINE_ KeyValue<TKey, TValue> &operator*() const {
return E->data;
}
_FORCE_INLINE_ KeyValue<TKey, TValue> *operator->() const { return &E->data; }
_FORCE_INLINE_ Iterator &operator++() {
if (E) {
E = E->next;
}
return *this;
}
_FORCE_INLINE_ Iterator &operator--() {
if (E) {
E = E->prev;
}
return *this;
}
_FORCE_INLINE_ bool operator==(const Iterator &b) const { return E == b.E; }
_FORCE_INLINE_ bool operator!=(const Iterator &b) const { return E != b.E; }
_FORCE_INLINE_ explicit operator bool() const {
return E != nullptr;
}
_FORCE_INLINE_ Iterator(HashMapElement<TKey, TValue> *p_E) { E = p_E; }
_FORCE_INLINE_ Iterator() {}
_FORCE_INLINE_ Iterator(const Iterator &p_it) { E = p_it.E; }
_FORCE_INLINE_ void operator=(const Iterator &p_it) {
E = p_it.E;
}
operator ConstIterator() const {
return ConstIterator(E);
}
private:
HashMapElement<TKey, TValue> *E = nullptr;
};
_FORCE_INLINE_ Iterator begin() {
return Iterator(head_element);
}
_FORCE_INLINE_ Iterator end() {
return Iterator(nullptr);
}
_FORCE_INLINE_ Iterator last() {
return Iterator(tail_element);
}
_FORCE_INLINE_ Iterator find(const TKey &p_key) {
uint32_t pos = 0;
bool exists = _lookup_pos(p_key, pos);
if (!exists) {
return end();
}
return Iterator(elements[pos]);
}
_FORCE_INLINE_ void remove(const Iterator &p_iter) {
if (p_iter) {
erase(p_iter->key);
}
}
_FORCE_INLINE_ ConstIterator begin() const {
return ConstIterator(head_element);
}
_FORCE_INLINE_ ConstIterator end() const {
return ConstIterator(nullptr);
}
_FORCE_INLINE_ ConstIterator last() const {
return ConstIterator(tail_element);
}
_FORCE_INLINE_ ConstIterator find(const TKey &p_key) const {
uint32_t pos = 0;
bool exists = _lookup_pos(p_key, pos);
if (!exists) {
return end();
}
return ConstIterator(elements[pos]);
}
/* Indexing */
const TValue &operator[](const TKey &p_key) const {
uint32_t pos = 0;
bool exists = _lookup_pos(p_key, pos);
CRASH_COND(!exists);
return elements[pos]->data.value;
}
TValue &operator[](const TKey &p_key) {
uint32_t pos = 0;
bool exists = _lookup_pos(p_key, pos);
if (!exists) {
return _insert(p_key, TValue())->data.value;
} else {
return elements[pos]->data.value;
}
}
/* Insert */
Iterator insert(const TKey &p_key, const TValue &p_value, bool p_front_insert = false) {
return Iterator(_insert(p_key, p_value, p_front_insert));
}
/* Constructors */
HashMap(const HashMap &p_other) {
reserve(hash_table_size_primes[p_other.capacity_index]);
if (p_other.num_elements == 0) {
return;
}
for (const KeyValue<TKey, TValue> &E : p_other) {
insert(E.key, E.value);
}
}
void operator=(const HashMap &p_other) {
if (this == &p_other) {
return; // Ignore self assignment.
}
if (num_elements != 0) {
clear();
}
reserve(hash_table_size_primes[p_other.capacity_index]);
if (p_other.elements == nullptr) {
return; // Nothing to copy.
}
for (const KeyValue<TKey, TValue> &E : p_other) {
insert(E.key, E.value);
}
}
HashMap(uint32_t p_initial_capacity) {
// Capacity can't be 0.
capacity_index = 0;
reserve(p_initial_capacity);
}
HashMap() {
capacity_index = MIN_CAPACITY_INDEX;
}
uint32_t debug_get_hash(uint32_t p_index) {
if (num_elements == 0) {
return 0;
}
ERR_FAIL_INDEX_V(p_index, get_capacity(), 0);
return hashes[p_index];
}
Iterator debug_get_element(uint32_t p_index) {
if (num_elements == 0) {
return Iterator();
}
ERR_FAIL_INDEX_V(p_index, get_capacity(), Iterator());
return Iterator(elements[p_index]);
}
~HashMap() {
clear();
if (elements != nullptr) {
Memory::free_static(elements);
Memory::free_static(hashes);
}
}
};
} // namespace godot
#endif // GODOT_HASH_MAP_HPP

View File

@@ -0,0 +1,477 @@
/**************************************************************************/
/* hash_set.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_HASH_SET_HPP
#define GODOT_HASH_SET_HPP
#include <godot_cpp/core/error_macros.hpp>
#include <godot_cpp/core/memory.hpp>
#include <godot_cpp/templates/hash_map.hpp>
#include <godot_cpp/templates/hashfuncs.hpp>
#include <godot_cpp/templates/pair.hpp>
namespace godot {
/**
* Implementation of Set using a bidi indexed hash map.
* Use RBSet instead of this only if the following conditions are met:
*
* - You need to keep an iterator or const pointer to Key and you intend to add/remove elements in the meantime.
* - Iteration order does matter (via operator<)
*
*/
template <class TKey,
class Hasher = HashMapHasherDefault,
class Comparator = HashMapComparatorDefault<TKey>>
class HashSet {
public:
static constexpr uint32_t MIN_CAPACITY_INDEX = 2; // Use a prime.
static constexpr float MAX_OCCUPANCY = 0.75;
static constexpr uint32_t EMPTY_HASH = 0;
private:
TKey *keys = nullptr;
uint32_t *hash_to_key = nullptr;
uint32_t *key_to_hash = nullptr;
uint32_t *hashes = nullptr;
uint32_t capacity_index = 0;
uint32_t num_elements = 0;
_FORCE_INLINE_ uint32_t _hash(const TKey &p_key) const {
uint32_t hash = Hasher::hash(p_key);
if (unlikely(hash == EMPTY_HASH)) {
hash = EMPTY_HASH + 1;
}
return hash;
}
_FORCE_INLINE_ uint32_t _get_probe_length(uint32_t p_pos, uint32_t p_hash, uint32_t p_capacity) const {
uint32_t original_pos = p_hash % p_capacity;
return (p_pos - original_pos + p_capacity) % p_capacity;
}
bool _lookup_pos(const TKey &p_key, uint32_t &r_pos) const {
if (keys == nullptr) {
return false; // Failed lookups, no elements
}
uint32_t capacity = hash_table_size_primes[capacity_index];
uint32_t hash = _hash(p_key);
uint32_t pos = hash % capacity;
uint32_t distance = 0;
while (true) {
if (hashes[pos] == EMPTY_HASH) {
return false;
}
if (distance > _get_probe_length(pos, hashes[pos], capacity)) {
return false;
}
if (hashes[pos] == hash && Comparator::compare(keys[hash_to_key[pos]], p_key)) {
r_pos = hash_to_key[pos];
return true;
}
pos = (pos + 1) % capacity;
distance++;
}
}
uint32_t _insert_with_hash(uint32_t p_hash, uint32_t p_index) {
uint32_t capacity = hash_table_size_primes[capacity_index];
uint32_t hash = p_hash;
uint32_t index = p_index;
uint32_t distance = 0;
uint32_t pos = hash % capacity;
while (true) {
if (hashes[pos] == EMPTY_HASH) {
hashes[pos] = hash;
key_to_hash[index] = pos;
hash_to_key[pos] = index;
return pos;
}
// Not an empty slot, let's check the probing length of the existing one.
uint32_t existing_probe_len = _get_probe_length(pos, hashes[pos], capacity);
if (existing_probe_len < distance) {
key_to_hash[index] = pos;
SWAP(hash, hashes[pos]);
SWAP(index, hash_to_key[pos]);
distance = existing_probe_len;
}
pos = (pos + 1) % capacity;
distance++;
}
}
void _resize_and_rehash(uint32_t p_new_capacity_index) {
// Capacity can't be 0.
capacity_index = MAX((uint32_t)MIN_CAPACITY_INDEX, p_new_capacity_index);
uint32_t capacity = hash_table_size_primes[capacity_index];
uint32_t *old_hashes = hashes;
uint32_t *old_key_to_hash = key_to_hash;
hashes = reinterpret_cast<uint32_t *>(Memory::alloc_static(sizeof(uint32_t) * capacity));
keys = reinterpret_cast<TKey *>(Memory::realloc_static(keys, sizeof(TKey) * capacity));
key_to_hash = reinterpret_cast<uint32_t *>(Memory::alloc_static(sizeof(uint32_t) * capacity));
hash_to_key = reinterpret_cast<uint32_t *>(Memory::realloc_static(hash_to_key, sizeof(uint32_t) * capacity));
for (uint32_t i = 0; i < capacity; i++) {
hashes[i] = EMPTY_HASH;
}
for (uint32_t i = 0; i < num_elements; i++) {
uint32_t h = old_hashes[old_key_to_hash[i]];
_insert_with_hash(h, i);
}
Memory::free_static(old_hashes);
Memory::free_static(old_key_to_hash);
}
_FORCE_INLINE_ int32_t _insert(const TKey &p_key) {
uint32_t capacity = hash_table_size_primes[capacity_index];
if (unlikely(keys == nullptr)) {
// Allocate on demand to save memory.
hashes = reinterpret_cast<uint32_t *>(Memory::alloc_static(sizeof(uint32_t) * capacity));
keys = reinterpret_cast<TKey *>(Memory::alloc_static(sizeof(TKey) * capacity));
key_to_hash = reinterpret_cast<uint32_t *>(Memory::alloc_static(sizeof(uint32_t) * capacity));
hash_to_key = reinterpret_cast<uint32_t *>(Memory::alloc_static(sizeof(uint32_t) * capacity));
for (uint32_t i = 0; i < capacity; i++) {
hashes[i] = EMPTY_HASH;
}
}
uint32_t pos = 0;
bool exists = _lookup_pos(p_key, pos);
if (exists) {
return pos;
} else {
if (num_elements + 1 > MAX_OCCUPANCY * capacity) {
ERR_FAIL_COND_V_MSG(capacity_index + 1 == HASH_TABLE_SIZE_MAX, -1, "Hash table maximum capacity reached, aborting insertion.");
_resize_and_rehash(capacity_index + 1);
}
uint32_t hash = _hash(p_key);
memnew_placement(&keys[num_elements], TKey(p_key));
_insert_with_hash(hash, num_elements);
num_elements++;
return num_elements - 1;
}
}
void _init_from(const HashSet &p_other) {
capacity_index = p_other.capacity_index;
num_elements = p_other.num_elements;
if (p_other.num_elements == 0) {
return;
}
uint32_t capacity = hash_table_size_primes[capacity_index];
hashes = reinterpret_cast<uint32_t *>(Memory::alloc_static(sizeof(uint32_t) * capacity));
keys = reinterpret_cast<TKey *>(Memory::alloc_static(sizeof(TKey) * capacity));
key_to_hash = reinterpret_cast<uint32_t *>(Memory::alloc_static(sizeof(uint32_t) * capacity));
hash_to_key = reinterpret_cast<uint32_t *>(Memory::alloc_static(sizeof(uint32_t) * capacity));
for (uint32_t i = 0; i < num_elements; i++) {
memnew_placement(&keys[i], TKey(p_other.keys[i]));
key_to_hash[i] = p_other.key_to_hash[i];
}
for (uint32_t i = 0; i < capacity; i++) {
hashes[i] = p_other.hashes[i];
hash_to_key[i] = p_other.hash_to_key[i];
}
}
public:
_FORCE_INLINE_ uint32_t get_capacity() const { return hash_table_size_primes[capacity_index]; }
_FORCE_INLINE_ uint32_t size() const { return num_elements; }
/* Standard Godot Container API */
bool is_empty() const {
return num_elements == 0;
}
void clear() {
if (keys == nullptr) {
return;
}
uint32_t capacity = hash_table_size_primes[capacity_index];
for (uint32_t i = 0; i < capacity; i++) {
hashes[i] = EMPTY_HASH;
}
for (uint32_t i = 0; i < num_elements; i++) {
keys[i].~TKey();
}
num_elements = 0;
}
_FORCE_INLINE_ bool has(const TKey &p_key) const {
uint32_t _pos = 0;
return _lookup_pos(p_key, _pos);
}
bool erase(const TKey &p_key) {
uint32_t pos = 0;
bool exists = _lookup_pos(p_key, pos);
if (!exists) {
return false;
}
uint32_t key_pos = pos;
pos = key_to_hash[pos]; // make hash pos
uint32_t capacity = hash_table_size_primes[capacity_index];
uint32_t next_pos = (pos + 1) % capacity;
while (hashes[next_pos] != EMPTY_HASH && _get_probe_length(next_pos, hashes[next_pos], capacity) != 0) {
uint32_t kpos = hash_to_key[pos];
uint32_t kpos_next = hash_to_key[next_pos];
SWAP(key_to_hash[kpos], key_to_hash[kpos_next]);
SWAP(hashes[next_pos], hashes[pos]);
SWAP(hash_to_key[next_pos], hash_to_key[pos]);
pos = next_pos;
next_pos = (pos + 1) % capacity;
}
hashes[pos] = EMPTY_HASH;
keys[key_pos].~TKey();
num_elements--;
if (key_pos < num_elements) {
// Not the last key, move the last one here to keep keys lineal
memnew_placement(&keys[key_pos], TKey(keys[num_elements]));
keys[num_elements].~TKey();
key_to_hash[key_pos] = key_to_hash[num_elements];
hash_to_key[key_to_hash[num_elements]] = key_pos;
}
return true;
}
// Reserves space for a number of elements, useful to avoid many resizes and rehashes.
// If adding a known (possibly large) number of elements at once, must be larger than old capacity.
void reserve(uint32_t p_new_capacity) {
uint32_t new_index = capacity_index;
while (hash_table_size_primes[new_index] < p_new_capacity) {
ERR_FAIL_COND_MSG(new_index + 1 == (uint32_t)HASH_TABLE_SIZE_MAX, nullptr);
new_index++;
}
if (new_index == capacity_index) {
return;
}
if (keys == nullptr) {
capacity_index = new_index;
return; // Unallocated yet.
}
_resize_and_rehash(new_index);
}
/** Iterator API **/
struct Iterator {
_FORCE_INLINE_ const TKey &operator*() const {
return keys[index];
}
_FORCE_INLINE_ const TKey *operator->() const {
return &keys[index];
}
_FORCE_INLINE_ Iterator &operator++() {
index++;
if (index >= (int32_t)num_keys) {
index = -1;
keys = nullptr;
num_keys = 0;
}
return *this;
}
_FORCE_INLINE_ Iterator &operator--() {
index--;
if (index < 0) {
index = -1;
keys = nullptr;
num_keys = 0;
}
return *this;
}
_FORCE_INLINE_ bool operator==(const Iterator &b) const { return keys == b.keys && index == b.index; }
_FORCE_INLINE_ bool operator!=(const Iterator &b) const { return keys != b.keys || index != b.index; }
_FORCE_INLINE_ explicit operator bool() const {
return keys != nullptr;
}
_FORCE_INLINE_ Iterator(const TKey *p_keys, uint32_t p_num_keys, int32_t p_index = -1) {
keys = p_keys;
num_keys = p_num_keys;
index = p_index;
}
_FORCE_INLINE_ Iterator() {}
_FORCE_INLINE_ Iterator(const Iterator &p_it) {
keys = p_it.keys;
num_keys = p_it.num_keys;
index = p_it.index;
}
_FORCE_INLINE_ void operator=(const Iterator &p_it) {
keys = p_it.keys;
num_keys = p_it.num_keys;
index = p_it.index;
}
private:
const TKey *keys = nullptr;
uint32_t num_keys = 0;
int32_t index = -1;
};
_FORCE_INLINE_ Iterator begin() const {
return num_elements ? Iterator(keys, num_elements, 0) : Iterator();
}
_FORCE_INLINE_ Iterator end() const {
return Iterator();
}
_FORCE_INLINE_ Iterator last() const {
if (num_elements == 0) {
return Iterator();
}
return Iterator(keys, num_elements, num_elements - 1);
}
_FORCE_INLINE_ Iterator find(const TKey &p_key) const {
uint32_t pos = 0;
bool exists = _lookup_pos(p_key, pos);
if (!exists) {
return end();
}
return Iterator(keys, num_elements, pos);
}
_FORCE_INLINE_ void remove(const Iterator &p_iter) {
if (p_iter) {
erase(*p_iter);
}
}
/* Insert */
Iterator insert(const TKey &p_key) {
uint32_t pos = _insert(p_key);
return Iterator(keys, num_elements, pos);
}
/* Constructors */
HashSet(const HashSet &p_other) {
_init_from(p_other);
}
void operator=(const HashSet &p_other) {
if (this == &p_other) {
return; // Ignore self assignment.
}
clear();
if (keys != nullptr) {
Memory::free_static(keys);
Memory::free_static(key_to_hash);
Memory::free_static(hash_to_key);
Memory::free_static(hashes);
keys = nullptr;
hashes = nullptr;
hash_to_key = nullptr;
key_to_hash = nullptr;
}
_init_from(p_other);
}
HashSet(uint32_t p_initial_capacity) {
// Capacity can't be 0.
capacity_index = 0;
reserve(p_initial_capacity);
}
HashSet() {
capacity_index = MIN_CAPACITY_INDEX;
}
void reset() {
clear();
if (keys != nullptr) {
Memory::free_static(keys);
Memory::free_static(key_to_hash);
Memory::free_static(hash_to_key);
Memory::free_static(hashes);
keys = nullptr;
hashes = nullptr;
hash_to_key = nullptr;
key_to_hash = nullptr;
}
capacity_index = MIN_CAPACITY_INDEX;
}
~HashSet() {
clear();
if (keys != nullptr) {
Memory::free_static(keys);
Memory::free_static(key_to_hash);
Memory::free_static(hash_to_key);
Memory::free_static(hashes);
}
}
};
} // namespace godot
#endif // GODOT_HASH_SET_HPP

View File

@@ -0,0 +1,526 @@
/**************************************************************************/
/* hashfuncs.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_HASHFUNCS_HPP
#define GODOT_HASHFUNCS_HPP
// Needed for fastmod.
#if defined(_MSC_VER)
#include <intrin.h>
#endif
#include <godot_cpp/core/math.hpp>
#include <godot_cpp/core/object.hpp>
#include <godot_cpp/variant/aabb.hpp>
#include <godot_cpp/variant/node_path.hpp>
#include <godot_cpp/variant/rect2.hpp>
#include <godot_cpp/variant/rect2i.hpp>
#include <godot_cpp/variant/rid.hpp>
#include <godot_cpp/variant/string.hpp>
#include <godot_cpp/variant/string_name.hpp>
#include <godot_cpp/variant/variant.hpp>
#include <godot_cpp/variant/vector2.hpp>
#include <godot_cpp/variant/vector2i.hpp>
#include <godot_cpp/variant/vector3.hpp>
#include <godot_cpp/variant/vector3i.hpp>
#include <godot_cpp/variant/vector4.hpp>
#include <godot_cpp/variant/vector4i.hpp>
/**
* Hashing functions
*/
namespace godot {
/**
* DJB2 Hash function
* @param C String
* @return 32-bits hashcode
*/
static _FORCE_INLINE_ uint32_t hash_djb2(const char *p_cstr) {
const unsigned char *chr = (const unsigned char *)p_cstr;
uint32_t hash = 5381;
uint32_t c;
while ((c = *chr++)) {
hash = ((hash << 5) + hash) ^ c; /* hash * 33 ^ c */
}
return hash;
}
static _FORCE_INLINE_ uint32_t hash_djb2_buffer(const uint8_t *p_buff, int p_len, uint32_t p_prev = 5381) {
uint32_t hash = p_prev;
for (int i = 0; i < p_len; i++) {
hash = ((hash << 5) + hash) ^ p_buff[i]; /* hash * 33 + c */
}
return hash;
}
static _FORCE_INLINE_ uint32_t hash_djb2_one_32(uint32_t p_in, uint32_t p_prev = 5381) {
return ((p_prev << 5) + p_prev) ^ p_in;
}
/**
* Thomas Wang's 64-bit to 32-bit Hash function:
* https://web.archive.org/web/20071223173210/https:/www.concentric.net/~Ttwang/tech/inthash.htm
*
* @param p_int - 64-bit unsigned integer key to be hashed
* @return unsigned 32-bit value representing hashcode
*/
static _FORCE_INLINE_ uint32_t hash_one_uint64(const uint64_t p_int) {
uint64_t v = p_int;
v = (~v) + (v << 18); // v = (v << 18) - v - 1;
v = v ^ (v >> 31);
v = v * 21; // v = (v + (v << 2)) + (v << 4);
v = v ^ (v >> 11);
v = v + (v << 6);
v = v ^ (v >> 22);
return uint32_t(v);
}
#define HASH_MURMUR3_SEED 0x7F07C65
// Murmurhash3 32-bit version.
// All MurmurHash versions are public domain software, and the author disclaims all copyright to their code.
static _FORCE_INLINE_ uint32_t hash_murmur3_one_32(uint32_t p_in, uint32_t p_seed = HASH_MURMUR3_SEED) {
p_in *= 0xcc9e2d51;
p_in = (p_in << 15) | (p_in >> 17);
p_in *= 0x1b873593;
p_seed ^= p_in;
p_seed = (p_seed << 13) | (p_seed >> 19);
p_seed = p_seed * 5 + 0xe6546b64;
return p_seed;
}
static _FORCE_INLINE_ uint32_t hash_murmur3_one_float(float p_in, uint32_t p_seed = HASH_MURMUR3_SEED) {
union {
float f;
uint32_t i;
} u;
// Normalize +/- 0.0 and NaN values so they hash the same.
if (p_in == 0.0f) {
u.f = 0.0;
} else if (Math::is_nan(p_in)) {
u.f = NAN;
} else {
u.f = p_in;
}
return hash_murmur3_one_32(u.i, p_seed);
}
static _FORCE_INLINE_ uint32_t hash_murmur3_one_64(uint64_t p_in, uint32_t p_seed = HASH_MURMUR3_SEED) {
p_seed = hash_murmur3_one_32(p_in & 0xFFFFFFFF, p_seed);
return hash_murmur3_one_32(p_in >> 32, p_seed);
}
static _FORCE_INLINE_ uint32_t hash_murmur3_one_double(double p_in, uint32_t p_seed = HASH_MURMUR3_SEED) {
union {
double d;
uint64_t i;
} u;
// Normalize +/- 0.0 and NaN values so they hash the same.
if (p_in == 0.0f) {
u.d = 0.0;
} else if (Math::is_nan(p_in)) {
u.d = NAN;
} else {
u.d = p_in;
}
return hash_murmur3_one_64(u.i, p_seed);
}
static _FORCE_INLINE_ uint32_t hash_murmur3_one_real(real_t p_in, uint32_t p_seed = HASH_MURMUR3_SEED) {
#ifdef REAL_T_IS_DOUBLE
return hash_murmur3_one_double(p_in, p_seed);
#else
return hash_murmur3_one_float(p_in, p_seed);
#endif
}
static _FORCE_INLINE_ uint32_t hash_rotl32(uint32_t x, int8_t r) {
return (x << r) | (x >> (32 - r));
}
static _FORCE_INLINE_ uint32_t hash_fmix32(uint32_t h) {
h ^= h >> 16;
h *= 0x85ebca6b;
h ^= h >> 13;
h *= 0xc2b2ae35;
h ^= h >> 16;
return h;
}
static _FORCE_INLINE_ uint32_t hash_murmur3_buffer(const void *key, int length, const uint32_t seed = HASH_MURMUR3_SEED) {
// Although not required, this is a random prime number.
const uint8_t *data = (const uint8_t *)key;
const int nblocks = length / 4;
uint32_t h1 = seed;
const uint32_t c1 = 0xcc9e2d51;
const uint32_t c2 = 0x1b873593;
const uint32_t *blocks = (const uint32_t *)(data + nblocks * 4);
for (int i = -nblocks; i; i++) {
uint32_t k1 = blocks[i];
k1 *= c1;
k1 = hash_rotl32(k1, 15);
k1 *= c2;
h1 ^= k1;
h1 = hash_rotl32(h1, 13);
h1 = h1 * 5 + 0xe6546b64;
}
const uint8_t *tail = (const uint8_t *)(data + nblocks * 4);
uint32_t k1 = 0;
switch (length & 3) {
case 3:
k1 ^= tail[2] << 16;
[[fallthrough]];
case 2:
k1 ^= tail[1] << 8;
[[fallthrough]];
case 1:
k1 ^= tail[0];
k1 *= c1;
k1 = hash_rotl32(k1, 15);
k1 *= c2;
h1 ^= k1;
}
// Finalize with additional bit mixing.
h1 ^= length;
return hash_fmix32(h1);
}
static _FORCE_INLINE_ uint32_t hash_djb2_one_float(double p_in, uint32_t p_prev = 5381) {
union {
double d;
uint64_t i;
} u;
// Normalize +/- 0.0 and NaN values so they hash the same.
if (p_in == 0.0f) {
u.d = 0.0;
} else if (Math::is_nan(p_in)) {
u.d = NAN;
} else {
u.d = p_in;
}
return ((p_prev << 5) + p_prev) + hash_one_uint64(u.i);
}
template <class T>
static _FORCE_INLINE_ uint32_t hash_make_uint32_t(T p_in) {
union {
T t;
uint32_t _u32;
} _u;
_u._u32 = 0;
_u.t = p_in;
return _u._u32;
}
static _FORCE_INLINE_ uint64_t hash_djb2_one_float_64(double p_in, uint64_t p_prev = 5381) {
union {
double d;
uint64_t i;
} u;
// Normalize +/- 0.0 and NaN values so they hash the same.
if (p_in == 0.0f) {
u.d = 0.0;
} else if (Math::is_nan(p_in)) {
u.d = NAN;
} else {
u.d = p_in;
}
return ((p_prev << 5) + p_prev) + u.i;
}
static _FORCE_INLINE_ uint64_t hash_djb2_one_64(uint64_t p_in, uint64_t p_prev = 5381) {
return ((p_prev << 5) + p_prev) ^ p_in;
}
template <class T>
static _FORCE_INLINE_ uint64_t hash_make_uint64_t(T p_in) {
union {
T t;
uint64_t _u64;
} _u;
_u._u64 = 0; // in case p_in is smaller
_u.t = p_in;
return _u._u64;
}
template <class T>
class Ref;
struct HashMapHasherDefault {
// Generic hash function for any type.
template <class T>
static _FORCE_INLINE_ uint32_t hash(const T *p_pointer) { return hash_one_uint64((uint64_t)p_pointer); }
template <class T>
static _FORCE_INLINE_ uint32_t hash(const Ref<T> &p_ref) { return hash_one_uint64((uint64_t)p_ref.operator->()); }
static _FORCE_INLINE_ uint32_t hash(const String &p_string) { return p_string.hash(); }
static _FORCE_INLINE_ uint32_t hash(const char *p_cstr) { return hash_djb2(p_cstr); }
static _FORCE_INLINE_ uint32_t hash(const wchar_t p_wchar) { return hash_fmix32(p_wchar); }
static _FORCE_INLINE_ uint32_t hash(const char16_t p_uchar) { return hash_fmix32(p_uchar); }
static _FORCE_INLINE_ uint32_t hash(const char32_t p_uchar) { return hash_fmix32(p_uchar); }
static _FORCE_INLINE_ uint32_t hash(const RID &p_rid) { return hash_one_uint64(p_rid.get_id()); }
static _FORCE_INLINE_ uint32_t hash(const StringName &p_string_name) { return p_string_name.hash(); }
static _FORCE_INLINE_ uint32_t hash(const NodePath &p_path) { return p_path.hash(); }
static _FORCE_INLINE_ uint32_t hash(const ObjectID &p_id) { return hash_one_uint64(p_id); }
static _FORCE_INLINE_ uint32_t hash(const uint64_t p_int) { return hash_one_uint64(p_int); }
static _FORCE_INLINE_ uint32_t hash(const int64_t p_int) { return hash_one_uint64(p_int); }
static _FORCE_INLINE_ uint32_t hash(const float p_float) { return hash_murmur3_one_float(p_float); }
static _FORCE_INLINE_ uint32_t hash(const double p_double) { return hash_murmur3_one_double(p_double); }
static _FORCE_INLINE_ uint32_t hash(const uint32_t p_int) { return hash_fmix32(p_int); }
static _FORCE_INLINE_ uint32_t hash(const int32_t p_int) { return hash_fmix32(p_int); }
static _FORCE_INLINE_ uint32_t hash(const uint16_t p_int) { return hash_fmix32(p_int); }
static _FORCE_INLINE_ uint32_t hash(const int16_t p_int) { return hash_fmix32(p_int); }
static _FORCE_INLINE_ uint32_t hash(const uint8_t p_int) { return hash_fmix32(p_int); }
static _FORCE_INLINE_ uint32_t hash(const int8_t p_int) { return hash_fmix32(p_int); }
static _FORCE_INLINE_ uint32_t hash(const Vector2i &p_vec) {
uint32_t h = hash_murmur3_one_32(p_vec.x);
h = hash_murmur3_one_32(p_vec.y, h);
return hash_fmix32(h);
}
static _FORCE_INLINE_ uint32_t hash(const Vector3i &p_vec) {
uint32_t h = hash_murmur3_one_32(p_vec.x);
h = hash_murmur3_one_32(p_vec.y, h);
h = hash_murmur3_one_32(p_vec.z, h);
return hash_fmix32(h);
}
static _FORCE_INLINE_ uint32_t hash(const Vector4i &p_vec) {
uint32_t h = hash_murmur3_one_32(p_vec.x);
h = hash_murmur3_one_32(p_vec.y, h);
h = hash_murmur3_one_32(p_vec.z, h);
h = hash_murmur3_one_32(p_vec.w, h);
return hash_fmix32(h);
}
static _FORCE_INLINE_ uint32_t hash(const Vector2 &p_vec) {
uint32_t h = hash_murmur3_one_real(p_vec.x);
h = hash_murmur3_one_real(p_vec.y, h);
return hash_fmix32(h);
}
static _FORCE_INLINE_ uint32_t hash(const Vector3 &p_vec) {
uint32_t h = hash_murmur3_one_real(p_vec.x);
h = hash_murmur3_one_real(p_vec.y, h);
h = hash_murmur3_one_real(p_vec.z, h);
return hash_fmix32(h);
}
static _FORCE_INLINE_ uint32_t hash(const Vector4 &p_vec) {
uint32_t h = hash_murmur3_one_real(p_vec.x);
h = hash_murmur3_one_real(p_vec.y, h);
h = hash_murmur3_one_real(p_vec.z, h);
h = hash_murmur3_one_real(p_vec.w, h);
return hash_fmix32(h);
}
static _FORCE_INLINE_ uint32_t hash(const Rect2i &p_rect) {
uint32_t h = hash_murmur3_one_32(p_rect.position.x);
h = hash_murmur3_one_32(p_rect.position.y, h);
h = hash_murmur3_one_32(p_rect.size.x, h);
h = hash_murmur3_one_32(p_rect.size.y, h);
return hash_fmix32(h);
}
static _FORCE_INLINE_ uint32_t hash(const Rect2 &p_rect) {
uint32_t h = hash_murmur3_one_real(p_rect.position.x);
h = hash_murmur3_one_real(p_rect.position.y, h);
h = hash_murmur3_one_real(p_rect.size.x, h);
h = hash_murmur3_one_real(p_rect.size.y, h);
return hash_fmix32(h);
}
static _FORCE_INLINE_ uint32_t hash(const AABB &p_aabb) {
uint32_t h = hash_murmur3_one_real(p_aabb.position.x);
h = hash_murmur3_one_real(p_aabb.position.y, h);
h = hash_murmur3_one_real(p_aabb.position.z, h);
h = hash_murmur3_one_real(p_aabb.size.x, h);
h = hash_murmur3_one_real(p_aabb.size.y, h);
h = hash_murmur3_one_real(p_aabb.size.z, h);
return hash_fmix32(h);
}
};
template <typename T>
struct HashMapComparatorDefault {
static bool compare(const T &p_lhs, const T &p_rhs) {
return p_lhs == p_rhs;
}
};
template <>
struct HashMapComparatorDefault<float> {
static bool compare(const float &p_lhs, const float &p_rhs) {
return (p_lhs == p_rhs) || (Math::is_nan(p_lhs) && Math::is_nan(p_rhs));
}
};
template <>
struct HashMapComparatorDefault<double> {
static bool compare(const double &p_lhs, const double &p_rhs) {
return (p_lhs == p_rhs) || (Math::is_nan(p_lhs) && Math::is_nan(p_rhs));
}
};
template <>
struct HashMapComparatorDefault<Vector2> {
static bool compare(const Vector2 &p_lhs, const Vector2 &p_rhs) {
return ((p_lhs.x == p_rhs.x) || (Math::is_nan(p_lhs.x) && Math::is_nan(p_rhs.x))) && ((p_lhs.y == p_rhs.y) || (Math::is_nan(p_lhs.y) && Math::is_nan(p_rhs.y)));
}
};
template <>
struct HashMapComparatorDefault<Vector3> {
static bool compare(const Vector3 &p_lhs, const Vector3 &p_rhs) {
return ((p_lhs.x == p_rhs.x) || (Math::is_nan(p_lhs.x) && Math::is_nan(p_rhs.x))) && ((p_lhs.y == p_rhs.y) || (Math::is_nan(p_lhs.y) && Math::is_nan(p_rhs.y))) && ((p_lhs.z == p_rhs.z) || (Math::is_nan(p_lhs.z) && Math::is_nan(p_rhs.z)));
}
};
constexpr uint32_t HASH_TABLE_SIZE_MAX = 29;
const uint32_t hash_table_size_primes[HASH_TABLE_SIZE_MAX] = {
5,
13,
23,
47,
97,
193,
389,
769,
1543,
3079,
6151,
12289,
24593,
49157,
98317,
196613,
393241,
786433,
1572869,
3145739,
6291469,
12582917,
25165843,
50331653,
100663319,
201326611,
402653189,
805306457,
1610612741,
};
// Computed with elem_i = UINT64_C (0 x FFFFFFFF FFFFFFFF ) / d_i + 1, where d_i is the i-th element of the above array.
const uint64_t hash_table_size_primes_inv[HASH_TABLE_SIZE_MAX] = {
3689348814741910324,
1418980313362273202,
802032351030850071,
392483916461905354,
190172619316593316,
95578984837873325,
47420935922132524,
23987963684927896,
11955116055547344,
5991147799191151,
2998982941588287,
1501077717772769,
750081082979285,
375261795343686,
187625172388393,
93822606204624,
46909513691883,
23456218233098,
11728086747027,
5864041509391,
2932024948977,
1466014921160,
733007198436,
366503839517,
183251896093,
91625960335,
45812983922,
22906489714,
11453246088
};
/**
* Fastmod computes ( n mod d ) given the precomputed c much faster than n % d.
* The implementation of fastmod is based on the following paper by Daniel Lemire et al.
* Faster Remainder by Direct Computation: Applications to Compilers and Software Libraries
* https://arxiv.org/abs/1902.01961
*/
static _FORCE_INLINE_ uint32_t fastmod(const uint32_t n, const uint64_t c, const uint32_t d) {
#if defined(_MSC_VER)
// Returns the upper 64 bits of the product of two 64-bit unsigned integers.
// This intrinsic function is required since MSVC does not support unsigned 128-bit integers.
#if defined(_M_X64) || defined(_M_ARM64)
return __umulh(c * n, d);
#else
// Fallback to the slower method for 32-bit platforms.
return n % d;
#endif // _M_X64 || _M_ARM64
#else
#ifdef __SIZEOF_INT128__
// Prevent compiler warning, because we know what we are doing.
uint64_t lowbits = c * n;
__extension__ typedef unsigned __int128 uint128;
return static_cast<uint64_t>(((uint128)lowbits * d) >> 64);
#else
// Fallback to the slower method if no 128-bit unsigned integer type is available.
return n % d;
#endif // __SIZEOF_INT128__
#endif // _MSC_VER
}
} // namespace godot
#endif // GODOT_HASHFUNCS_HPP

View File

@@ -0,0 +1,769 @@
/**************************************************************************/
/* list.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_LIST_HPP
#define GODOT_LIST_HPP
#include <godot_cpp/core/error_macros.hpp>
#include <godot_cpp/core/memory.hpp>
#include <godot_cpp/templates/sort_array.hpp>
/**
* Generic Templatized Linked List Implementation.
* The implementation differs from the STL one because
* a compatible preallocated linked list can be written
* using the same API, or features such as erasing an element
* from the iterator.
*/
namespace godot {
template <class T, class A = DefaultAllocator>
class List {
struct _Data;
public:
class Element {
private:
friend class List<T, A>;
T value;
Element *next_ptr = nullptr;
Element *prev_ptr = nullptr;
_Data *data = nullptr;
public:
/**
* Get NEXT Element iterator, for constant lists.
*/
_FORCE_INLINE_ const Element *next() const {
return next_ptr;
}
/**
* Get NEXT Element iterator,
*/
_FORCE_INLINE_ Element *next() {
return next_ptr;
}
/**
* Get PREV Element iterator, for constant lists.
*/
_FORCE_INLINE_ const Element *prev() const {
return prev_ptr;
}
/**
* Get PREV Element iterator,
*/
_FORCE_INLINE_ Element *prev() {
return prev_ptr;
}
/**
* * operator, for using as *iterator, when iterators are defined on stack.
*/
_FORCE_INLINE_ const T &operator*() const {
return value;
}
/**
* operator->, for using as iterator->, when iterators are defined on stack, for constant lists.
*/
_FORCE_INLINE_ const T *operator->() const {
return &value;
}
/**
* * operator, for using as *iterator, when iterators are defined on stack,
*/
_FORCE_INLINE_ T &operator*() {
return value;
}
/**
* operator->, for using as iterator->, when iterators are defined on stack, for constant lists.
*/
_FORCE_INLINE_ T *operator->() {
return &value;
}
/**
* get the value stored in this element.
*/
_FORCE_INLINE_ T &get() {
return value;
}
/**
* get the value stored in this element, for constant lists
*/
_FORCE_INLINE_ const T &get() const {
return value;
}
/**
* set the value stored in this element.
*/
_FORCE_INLINE_ void set(const T &p_value) {
value = (T &)p_value;
}
void erase() {
data->erase(this);
}
_FORCE_INLINE_ Element() {}
};
typedef T ValueType;
struct Iterator {
_FORCE_INLINE_ T &operator*() const {
return E->get();
}
_FORCE_INLINE_ T *operator->() const { return &E->get(); }
_FORCE_INLINE_ Iterator &operator++() {
E = E->next();
return *this;
}
_FORCE_INLINE_ Iterator &operator--() {
E = E->prev();
return *this;
}
_FORCE_INLINE_ bool operator==(const Iterator &b) const { return E == b.E; }
_FORCE_INLINE_ bool operator!=(const Iterator &b) const { return E != b.E; }
Iterator(Element *p_E) { E = p_E; }
Iterator() {}
Iterator(const Iterator &p_it) { E = p_it.E; }
private:
Element *E = nullptr;
};
struct ConstIterator {
_FORCE_INLINE_ const T &operator*() const {
return E->get();
}
_FORCE_INLINE_ const T *operator->() const { return &E->get(); }
_FORCE_INLINE_ ConstIterator &operator++() {
E = E->next();
return *this;
}
_FORCE_INLINE_ ConstIterator &operator--() {
E = E->prev();
return *this;
}
_FORCE_INLINE_ bool operator==(const ConstIterator &b) const { return E == b.E; }
_FORCE_INLINE_ bool operator!=(const ConstIterator &b) const { return E != b.E; }
_FORCE_INLINE_ ConstIterator(const Element *p_E) { E = p_E; }
_FORCE_INLINE_ ConstIterator() {}
_FORCE_INLINE_ ConstIterator(const ConstIterator &p_it) { E = p_it.E; }
private:
const Element *E = nullptr;
};
_FORCE_INLINE_ Iterator begin() {
return Iterator(front());
}
_FORCE_INLINE_ Iterator end() {
return Iterator(nullptr);
}
#if 0
//to use when replacing find()
_FORCE_INLINE_ Iterator find(const K &p_key) {
return Iterator(find(p_key));
}
#endif
_FORCE_INLINE_ ConstIterator begin() const {
return ConstIterator(front());
}
_FORCE_INLINE_ ConstIterator end() const {
return ConstIterator(nullptr);
}
#if 0
//to use when replacing find()
_FORCE_INLINE_ ConstIterator find(const K &p_key) const {
return ConstIterator(find(p_key));
}
#endif
private:
struct _Data {
Element *first = nullptr;
Element *last = nullptr;
int size_cache = 0;
bool erase(const Element *p_I) {
ERR_FAIL_NULL_V(p_I, false);
ERR_FAIL_COND_V(p_I->data != this, false);
if (first == p_I) {
first = p_I->next_ptr;
}
if (last == p_I) {
last = p_I->prev_ptr;
}
if (p_I->prev_ptr) {
p_I->prev_ptr->next_ptr = p_I->next_ptr;
}
if (p_I->next_ptr) {
p_I->next_ptr->prev_ptr = p_I->prev_ptr;
}
memdelete_allocator<Element, A>(const_cast<Element *>(p_I));
size_cache--;
return true;
}
};
_Data *_data = nullptr;
public:
/**
* return a const iterator to the beginning of the list.
*/
_FORCE_INLINE_ const Element *front() const {
return _data ? _data->first : nullptr;
}
/**
* return an iterator to the beginning of the list.
*/
_FORCE_INLINE_ Element *front() {
return _data ? _data->first : nullptr;
}
/**
* return a const iterator to the last member of the list.
*/
_FORCE_INLINE_ const Element *back() const {
return _data ? _data->last : nullptr;
}
/**
* return an iterator to the last member of the list.
*/
_FORCE_INLINE_ Element *back() {
return _data ? _data->last : nullptr;
}
/**
* store a new element at the end of the list
*/
Element *push_back(const T &value) {
if (!_data) {
_data = memnew_allocator(_Data, A);
_data->first = nullptr;
_data->last = nullptr;
_data->size_cache = 0;
}
Element *n = memnew_allocator(Element, A);
n->value = (T &)value;
n->prev_ptr = _data->last;
n->next_ptr = nullptr;
n->data = _data;
if (_data->last) {
_data->last->next_ptr = n;
}
_data->last = n;
if (!_data->first) {
_data->first = n;
}
_data->size_cache++;
return n;
}
void pop_back() {
if (_data && _data->last) {
erase(_data->last);
}
}
/**
* store a new element at the beginning of the list
*/
Element *push_front(const T &value) {
if (!_data) {
_data = memnew_allocator(_Data, A);
_data->first = nullptr;
_data->last = nullptr;
_data->size_cache = 0;
}
Element *n = memnew_allocator(Element, A);
n->value = (T &)value;
n->prev_ptr = nullptr;
n->next_ptr = _data->first;
n->data = _data;
if (_data->first) {
_data->first->prev_ptr = n;
}
_data->first = n;
if (!_data->last) {
_data->last = n;
}
_data->size_cache++;
return n;
}
void pop_front() {
if (_data && _data->first) {
erase(_data->first);
}
}
Element *insert_after(Element *p_element, const T &p_value) {
CRASH_COND(p_element && (!_data || p_element->data != _data));
if (!p_element) {
return push_back(p_value);
}
Element *n = memnew_allocator(Element, A);
n->value = (T &)p_value;
n->prev_ptr = p_element;
n->next_ptr = p_element->next_ptr;
n->data = _data;
if (!p_element->next_ptr) {
_data->last = n;
} else {
p_element->next_ptr->prev_ptr = n;
}
p_element->next_ptr = n;
_data->size_cache++;
return n;
}
Element *insert_before(Element *p_element, const T &p_value) {
CRASH_COND(p_element && (!_data || p_element->data != _data));
if (!p_element) {
return push_back(p_value);
}
Element *n = memnew_allocator(Element, A);
n->value = (T &)p_value;
n->prev_ptr = p_element->prev_ptr;
n->next_ptr = p_element;
n->data = _data;
if (!p_element->prev_ptr) {
_data->first = n;
} else {
p_element->prev_ptr->next_ptr = n;
}
p_element->prev_ptr = n;
_data->size_cache++;
return n;
}
/**
* find an element in the list,
*/
template <class T_v>
Element *find(const T_v &p_val) {
Element *it = front();
while (it) {
if (it->value == p_val) {
return it;
}
it = it->next();
}
return nullptr;
}
/**
* erase an element in the list, by iterator pointing to it. Return true if it was found/erased.
*/
bool erase(const Element *p_I) {
if (_data && p_I) {
bool ret = _data->erase(p_I);
if (_data->size_cache == 0) {
memdelete_allocator<_Data, A>(_data);
_data = nullptr;
}
return ret;
}
return false;
}
/**
* erase the first element in the list, that contains value
*/
bool erase(const T &value) {
Element *I = find(value);
return erase(I);
}
/**
* return whether the list is empty
*/
_FORCE_INLINE_ bool is_empty() const {
return (!_data || !_data->size_cache);
}
/**
* clear the list
*/
void clear() {
while (front()) {
erase(front());
}
}
_FORCE_INLINE_ int size() const {
return _data ? _data->size_cache : 0;
}
void swap(Element *p_A, Element *p_B) {
ERR_FAIL_COND(!p_A || !p_B);
ERR_FAIL_COND(p_A->data != _data);
ERR_FAIL_COND(p_B->data != _data);
if (p_A == p_B) {
return;
}
Element *A_prev = p_A->prev_ptr;
Element *A_next = p_A->next_ptr;
Element *B_prev = p_B->prev_ptr;
Element *B_next = p_B->next_ptr;
if (A_prev) {
A_prev->next_ptr = p_B;
} else {
_data->first = p_B;
}
if (B_prev) {
B_prev->next_ptr = p_A;
} else {
_data->first = p_A;
}
if (A_next) {
A_next->prev_ptr = p_B;
} else {
_data->last = p_B;
}
if (B_next) {
B_next->prev_ptr = p_A;
} else {
_data->last = p_A;
}
p_A->prev_ptr = A_next == p_B ? p_B : B_prev;
p_A->next_ptr = B_next == p_A ? p_B : B_next;
p_B->prev_ptr = B_next == p_A ? p_A : A_prev;
p_B->next_ptr = A_next == p_B ? p_A : A_next;
}
/**
* copy the list
*/
void operator=(const List &p_list) {
clear();
const Element *it = p_list.front();
while (it) {
push_back(it->get());
it = it->next();
}
}
T &operator[](int p_index) {
CRASH_BAD_INDEX(p_index, size());
Element *I = front();
int c = 0;
while (c < p_index) {
I = I->next();
c++;
}
return I->get();
}
const T &operator[](int p_index) const {
CRASH_BAD_INDEX(p_index, size());
const Element *I = front();
int c = 0;
while (c < p_index) {
I = I->next();
c++;
}
return I->get();
}
void move_to_back(Element *p_I) {
ERR_FAIL_COND(p_I->data != _data);
if (!p_I->next_ptr) {
return;
}
if (_data->first == p_I) {
_data->first = p_I->next_ptr;
}
if (_data->last == p_I) {
_data->last = p_I->prev_ptr;
}
if (p_I->prev_ptr) {
p_I->prev_ptr->next_ptr = p_I->next_ptr;
}
p_I->next_ptr->prev_ptr = p_I->prev_ptr;
_data->last->next_ptr = p_I;
p_I->prev_ptr = _data->last;
p_I->next_ptr = nullptr;
_data->last = p_I;
}
void reverse() {
int s = size() / 2;
Element *F = front();
Element *B = back();
for (int i = 0; i < s; i++) {
SWAP(F->value, B->value);
F = F->next();
B = B->prev();
}
}
void move_to_front(Element *p_I) {
ERR_FAIL_COND(p_I->data != _data);
if (!p_I->prev_ptr) {
return;
}
if (_data->first == p_I) {
_data->first = p_I->next_ptr;
}
if (_data->last == p_I) {
_data->last = p_I->prev_ptr;
}
p_I->prev_ptr->next_ptr = p_I->next_ptr;
if (p_I->next_ptr) {
p_I->next_ptr->prev_ptr = p_I->prev_ptr;
}
_data->first->prev_ptr = p_I;
p_I->next_ptr = _data->first;
p_I->prev_ptr = nullptr;
_data->first = p_I;
}
void move_before(Element *value, Element *where) {
if (value->prev_ptr) {
value->prev_ptr->next_ptr = value->next_ptr;
} else {
_data->first = value->next_ptr;
}
if (value->next_ptr) {
value->next_ptr->prev_ptr = value->prev_ptr;
} else {
_data->last = value->prev_ptr;
}
value->next_ptr = where;
if (!where) {
value->prev_ptr = _data->last;
_data->last = value;
return;
}
value->prev_ptr = where->prev_ptr;
if (where->prev_ptr) {
where->prev_ptr->next_ptr = value;
} else {
_data->first = value;
}
where->prev_ptr = value;
}
/**
* simple insertion sort
*/
void sort() {
sort_custom<Comparator<T>>();
}
template <class C>
void sort_custom_inplace() {
if (size() < 2) {
return;
}
Element *from = front();
Element *current = from;
Element *to = from;
while (current) {
Element *next = current->next_ptr;
if (from != current) {
current->prev_ptr = nullptr;
current->next_ptr = from;
Element *find = from;
C less;
while (find && less(find->value, current->value)) {
current->prev_ptr = find;
current->next_ptr = find->next_ptr;
find = find->next_ptr;
}
if (current->prev_ptr) {
current->prev_ptr->next_ptr = current;
} else {
from = current;
}
if (current->next_ptr) {
current->next_ptr->prev_ptr = current;
} else {
to = current;
}
} else {
current->prev_ptr = nullptr;
current->next_ptr = nullptr;
}
current = next;
}
_data->first = from;
_data->last = to;
}
template <class C>
struct AuxiliaryComparator {
C compare;
_FORCE_INLINE_ bool operator()(const Element *a, const Element *b) const {
return compare(a->value, b->value);
}
};
template <class C>
void sort_custom() {
// this version uses auxiliary memory for speed.
// if you don't want to use auxiliary memory, use the in_place version
int s = size();
if (s < 2) {
return;
}
Element **aux_buffer = memnew_arr(Element *, s);
int idx = 0;
for (Element *E = front(); E; E = E->next_ptr) {
aux_buffer[idx] = E;
idx++;
}
SortArray<Element *, AuxiliaryComparator<C>> sort;
sort.sort(aux_buffer, s);
_data->first = aux_buffer[0];
aux_buffer[0]->prev_ptr = nullptr;
aux_buffer[0]->next_ptr = aux_buffer[1];
_data->last = aux_buffer[s - 1];
aux_buffer[s - 1]->prev_ptr = aux_buffer[s - 2];
aux_buffer[s - 1]->next_ptr = nullptr;
for (int i = 1; i < s - 1; i++) {
aux_buffer[i]->prev_ptr = aux_buffer[i - 1];
aux_buffer[i]->next_ptr = aux_buffer[i + 1];
}
memdelete_arr(aux_buffer);
}
const void *id() const {
return (void *)_data;
}
/**
* copy constructor for the list
*/
List(const List &p_list) {
const Element *it = p_list.front();
while (it) {
push_back(it->get());
it = it->next();
}
}
List() {}
~List() {
clear();
if (_data) {
ERR_FAIL_COND(_data->size_cache);
memdelete_allocator<_Data, A>(_data);
}
}
};
} // namespace godot
#endif // GODOT_LIST_HPP

View File

@@ -0,0 +1,339 @@
/**************************************************************************/
/* local_vector.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_LOCAL_VECTOR_HPP
#define GODOT_LOCAL_VECTOR_HPP
#include "godot_cpp/core/error_macros.hpp"
#include "godot_cpp/core/memory.hpp"
#include "godot_cpp/templates/sort_array.hpp"
#include "godot_cpp/templates/vector.hpp"
#include <initializer_list>
#include <type_traits>
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>
class LocalVector {
private:
U count = 0;
U capacity = 0;
T *data = nullptr;
public:
T *ptr() {
return data;
}
const T *ptr() const {
return data;
}
_FORCE_INLINE_ void push_back(T p_elem) {
if (unlikely(count == capacity)) {
if (capacity == 0) {
capacity = 1;
} else {
capacity <<= 1;
}
data = (T *)memrealloc(data, capacity * sizeof(T));
CRASH_COND_MSG(!data, "Out of memory");
}
if constexpr (!std::is_trivially_constructible<T>::value && !force_trivial) {
memnew_placement(&data[count++], T(p_elem));
} else {
data[count++] = p_elem;
}
}
void remove_at(U p_index) {
ERR_FAIL_UNSIGNED_INDEX(p_index, count);
count--;
for (U i = p_index; i < count; i++) {
data[i] = data[i + 1];
}
if constexpr (!std::is_trivially_destructible<T>::value && !force_trivial) {
data[count].~T();
}
}
/// Removes the item copying the last value into the position of the one to
/// remove. It's generally faster than `remove`.
void remove_at_unordered(U p_index) {
ERR_FAIL_INDEX(p_index, count);
count--;
if (count > p_index) {
data[p_index] = data[count];
}
if constexpr (!std::is_trivially_destructible<T>::value && !force_trivial) {
data[count].~T();
}
}
void erase(const T &p_val) {
int64_t idx = find(p_val);
if (idx >= 0) {
remove_at(idx);
}
}
void invert() {
for (U i = 0; i < count / 2; i++) {
SWAP(data[i], data[count - i - 1]);
}
}
_FORCE_INLINE_ void clear() { resize(0); }
_FORCE_INLINE_ void reset() {
clear();
if (data) {
memfree(data);
data = nullptr;
capacity = 0;
}
}
_FORCE_INLINE_ bool is_empty() const { return count == 0; }
_FORCE_INLINE_ U get_capacity() const { return capacity; }
_FORCE_INLINE_ void reserve(U p_size) {
p_size = tight ? p_size : nearest_power_of_2_templated(p_size);
if (p_size > capacity) {
capacity = p_size;
data = (T *)memrealloc(data, capacity * sizeof(T));
CRASH_COND_MSG(!data, "Out of memory");
}
}
_FORCE_INLINE_ U size() const { return count; }
void resize(U p_size) {
if (p_size < count) {
if constexpr (!std::is_trivially_destructible<T>::value && !force_trivial) {
for (U i = p_size; i < count; i++) {
data[i].~T();
}
}
count = p_size;
} else if (p_size > count) {
if (unlikely(p_size > capacity)) {
if (capacity == 0) {
capacity = 1;
}
while (capacity < p_size) {
capacity <<= 1;
}
data = (T *)memrealloc(data, capacity * sizeof(T));
CRASH_COND_MSG(!data, "Out of memory");
}
if constexpr (!std::is_trivially_constructible<T>::value && !force_trivial) {
for (U i = count; i < p_size; i++) {
memnew_placement(&data[i], T);
}
}
count = p_size;
}
}
_FORCE_INLINE_ const T &operator[](U p_index) const {
CRASH_BAD_UNSIGNED_INDEX(p_index, count);
return data[p_index];
}
_FORCE_INLINE_ T &operator[](U p_index) {
CRASH_BAD_UNSIGNED_INDEX(p_index, count);
return data[p_index];
}
struct Iterator {
_FORCE_INLINE_ T &operator*() const {
return *elem_ptr;
}
_FORCE_INLINE_ T *operator->() const { return elem_ptr; }
_FORCE_INLINE_ Iterator &operator++() {
elem_ptr++;
return *this;
}
_FORCE_INLINE_ Iterator &operator--() {
elem_ptr--;
return *this;
}
_FORCE_INLINE_ bool operator==(const Iterator &b) const { return elem_ptr == b.elem_ptr; }
_FORCE_INLINE_ bool operator!=(const Iterator &b) const { return elem_ptr != b.elem_ptr; }
Iterator(T *p_ptr) { elem_ptr = p_ptr; }
Iterator() {}
Iterator(const Iterator &p_it) { elem_ptr = p_it.elem_ptr; }
private:
T *elem_ptr = nullptr;
};
struct ConstIterator {
_FORCE_INLINE_ const T &operator*() const {
return *elem_ptr;
}
_FORCE_INLINE_ const T *operator->() const { return elem_ptr; }
_FORCE_INLINE_ ConstIterator &operator++() {
elem_ptr++;
return *this;
}
_FORCE_INLINE_ ConstIterator &operator--() {
elem_ptr--;
return *this;
}
_FORCE_INLINE_ bool operator==(const ConstIterator &b) const { return elem_ptr == b.elem_ptr; }
_FORCE_INLINE_ bool operator!=(const ConstIterator &b) const { return elem_ptr != b.elem_ptr; }
ConstIterator(const T *p_ptr) { elem_ptr = p_ptr; }
ConstIterator() {}
ConstIterator(const ConstIterator &p_it) { elem_ptr = p_it.elem_ptr; }
private:
const T *elem_ptr = nullptr;
};
_FORCE_INLINE_ Iterator begin() {
return Iterator(data);
}
_FORCE_INLINE_ Iterator end() {
return Iterator(data + size());
}
_FORCE_INLINE_ ConstIterator begin() const {
return ConstIterator(ptr());
}
_FORCE_INLINE_ ConstIterator end() const {
return ConstIterator(ptr() + size());
}
void insert(U p_pos, T p_val) {
ERR_FAIL_UNSIGNED_INDEX(p_pos, count + 1);
if (p_pos == count) {
push_back(p_val);
} else {
resize(count + 1);
for (U i = count - 1; i > p_pos; i--) {
data[i] = data[i - 1];
}
data[p_pos] = p_val;
}
}
int64_t find(const T &p_val, U p_from = 0) const {
for (U i = p_from; i < count; i++) {
if (data[i] == p_val) {
return int64_t(i);
}
}
return -1;
}
template <class C>
void sort_custom() {
U len = count;
if (len == 0) {
return;
}
SortArray<T, C> sorter;
sorter.sort(data, len);
}
void sort() {
sort_custom<_DefaultComparator<T>>();
}
void ordered_insert(T p_val) {
U i;
for (i = 0; i < count; i++) {
if (p_val < data[i]) {
break;
}
}
insert(i, p_val);
}
operator Vector<T>() const {
Vector<T> ret;
ret.resize(size());
T *w = ret.ptrw();
memcpy(w, data, sizeof(T) * count);
return ret;
}
Vector<uint8_t> to_byte_array() const { //useful to pass stuff to gpu or variant
Vector<uint8_t> ret;
ret.resize(count * sizeof(T));
uint8_t *w = ret.ptrw();
memcpy(w, data, sizeof(T) * count);
return ret;
}
_FORCE_INLINE_ LocalVector() {}
_FORCE_INLINE_ LocalVector(std::initializer_list<T> p_init) {
reserve(p_init.size());
for (const T &element : p_init) {
push_back(element);
}
}
_FORCE_INLINE_ LocalVector(const LocalVector &p_from) {
resize(p_from.size());
for (U i = 0; i < p_from.count; i++) {
data[i] = p_from.data[i];
}
}
inline void operator=(const LocalVector &p_from) {
resize(p_from.size());
for (U i = 0; i < p_from.count; i++) {
data[i] = p_from.data[i];
}
}
inline void operator=(const Vector<T> &p_from) {
resize(p_from.size());
for (U i = 0; i < count; i++) {
data[i] = p_from[i];
}
}
_FORCE_INLINE_ ~LocalVector() {
if (data) {
reset();
}
}
};
template <class T, class U = uint32_t, bool force_trivial = false>
using TightLocalVector = LocalVector<T, U, force_trivial, true>;
} // namespace godot
#endif // GODOT_LOCAL_VECTOR_HPP

View File

@@ -0,0 +1,107 @@
/**************************************************************************/
/* pair.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_PAIR_HPP
#define GODOT_PAIR_HPP
namespace godot {
template <class F, class S>
struct Pair {
F first;
S second;
Pair() :
first(),
second() {
}
Pair(F p_first, const S &p_second) :
first(p_first),
second(p_second) {
}
};
template <class F, class S>
bool operator==(const Pair<F, S> &pair, const Pair<F, S> &other) {
return (pair.first == other.first) && (pair.second == other.second);
}
template <class F, class S>
bool operator!=(const Pair<F, S> &pair, const Pair<F, S> &other) {
return (pair.first != other.first) || (pair.second != other.second);
}
template <class F, class S>
struct PairSort {
bool operator()(const Pair<F, S> &A, const Pair<F, S> &B) const {
if (A.first != B.first) {
return A.first < B.first;
}
return A.second < B.second;
}
};
template <class K, class V>
struct KeyValue {
const K key;
V value;
void operator=(const KeyValue &p_kv) = delete;
_FORCE_INLINE_ KeyValue(const KeyValue &p_kv) :
key(p_kv.key),
value(p_kv.value) {
}
_FORCE_INLINE_ KeyValue(const K &p_key, const V &p_value) :
key(p_key),
value(p_value) {
}
};
template <class K, class V>
bool operator==(const KeyValue<K, V> &pair, const KeyValue<K, V> &other) {
return (pair.key == other.key) && (pair.value == other.value);
}
template <class K, class V>
bool operator!=(const KeyValue<K, V> &pair, const KeyValue<K, V> &other) {
return (pair.key != other.key) || (pair.value != other.value);
}
template <class K, class V>
struct KeyValueSort {
bool operator()(const KeyValue<K, V> &A, const KeyValue<K, V> &B) const {
return A.key < B.key;
}
};
} // namespace godot
#endif // GODOT_PAIR_HPP

View File

@@ -0,0 +1,765 @@
/**************************************************************************/
/* rb_map.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_RB_MAP_HPP
#define GODOT_RB_MAP_HPP
#include <godot_cpp/core/error_macros.hpp>
#include <godot_cpp/core/memory.hpp>
#include <godot_cpp/templates/pair.hpp>
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>
class RBMap {
enum Color {
RED,
BLACK
};
struct _Data;
public:
class Element {
private:
friend class RBMap<K, V, C, A>;
int color = RED;
Element *right = nullptr;
Element *left = nullptr;
Element *parent = nullptr;
Element *_next = nullptr;
Element *_prev = nullptr;
KeyValue<K, V> _data;
public:
KeyValue<K, V> &key_value() { return _data; }
const KeyValue<K, V> &key_value() const { return _data; }
const Element *next() const {
return _next;
}
Element *next() {
return _next;
}
const Element *prev() const {
return _prev;
}
Element *prev() {
return _prev;
}
const K &key() const {
return _data.key;
}
V &value() {
return _data.value;
}
const V &value() const {
return _data.value;
}
V &get() {
return _data.value;
}
const V &get() const {
return _data.value;
}
Element(const KeyValue<K, V> &p_data) :
_data(p_data) {}
};
typedef KeyValue<K, V> ValueType;
struct Iterator {
_FORCE_INLINE_ KeyValue<K, V> &operator*() const {
return E->key_value();
}
_FORCE_INLINE_ KeyValue<K, V> *operator->() const { return &E->key_value(); }
_FORCE_INLINE_ Iterator &operator++() {
E = E->next();
return *this;
}
_FORCE_INLINE_ Iterator &operator--() {
E = E->prev();
return *this;
}
_FORCE_INLINE_ bool operator==(const Iterator &b) const { return E == b.E; }
_FORCE_INLINE_ bool operator!=(const Iterator &b) const { return E != b.E; }
explicit operator bool() const {
return E != nullptr;
}
Iterator(Element *p_E) { E = p_E; }
Iterator() {}
Iterator(const Iterator &p_it) { E = p_it.E; }
private:
Element *E = nullptr;
};
struct ConstIterator {
_FORCE_INLINE_ const KeyValue<K, V> &operator*() const {
return E->key_value();
}
_FORCE_INLINE_ const KeyValue<K, V> *operator->() const { return &E->key_value(); }
_FORCE_INLINE_ ConstIterator &operator++() {
E = E->next();
return *this;
}
_FORCE_INLINE_ ConstIterator &operator--() {
E = E->prev();
return *this;
}
_FORCE_INLINE_ bool operator==(const ConstIterator &b) const { return E == b.E; }
_FORCE_INLINE_ bool operator!=(const ConstIterator &b) const { return E != b.E; }
explicit operator bool() const {
return E != nullptr;
}
ConstIterator(const Element *p_E) { E = p_E; }
ConstIterator() {}
ConstIterator(const ConstIterator &p_it) { E = p_it.E; }
private:
const Element *E = nullptr;
};
_FORCE_INLINE_ Iterator begin() {
return Iterator(front());
}
_FORCE_INLINE_ Iterator end() {
return Iterator(nullptr);
}
#if 0
//to use when replacing find()
_FORCE_INLINE_ Iterator find(const K &p_key) {
return Iterator(find(p_key));
}
#endif
_FORCE_INLINE_ void remove(const Iterator &p_iter) {
return erase(p_iter.E);
}
_FORCE_INLINE_ ConstIterator begin() const {
return ConstIterator(front());
}
_FORCE_INLINE_ ConstIterator end() const {
return ConstIterator(nullptr);
}
#if 0
//to use when replacing find()
_FORCE_INLINE_ ConstIterator find(const K &p_key) const {
return ConstIterator(find(p_key));
}
#endif
private:
struct _Data {
Element *_root = nullptr;
Element *_nil = nullptr;
int size_cache = 0;
_FORCE_INLINE_ _Data() {
#ifdef GLOBALNIL_DISABLED
_nil = memnew_allocator(Element, A);
_nil->parent = _nil->left = _nil->right = _nil;
_nil->color = BLACK;
#else
_nil = (Element *)&_GlobalNilClass::_nil;
#endif
}
void _create_root() {
_root = memnew_allocator(Element(KeyValue<K, V>(K(), V())), A);
_root->parent = _root->left = _root->right = _nil;
_root->color = BLACK;
}
void _free_root() {
if (_root) {
memdelete_allocator<Element, A>(_root);
_root = nullptr;
}
}
~_Data() {
_free_root();
#ifdef GLOBALNIL_DISABLED
memdelete_allocator<Element, A>(_nil);
#endif
}
};
_Data _data;
inline void _set_color(Element *p_node, int p_color) {
ERR_FAIL_COND(p_node == _data._nil && p_color == RED);
p_node->color = p_color;
}
inline void _rotate_left(Element *p_node) {
Element *r = p_node->right;
p_node->right = r->left;
if (r->left != _data._nil) {
r->left->parent = p_node;
}
r->parent = p_node->parent;
if (p_node == p_node->parent->left) {
p_node->parent->left = r;
} else {
p_node->parent->right = r;
}
r->left = p_node;
p_node->parent = r;
}
inline void _rotate_right(Element *p_node) {
Element *l = p_node->left;
p_node->left = l->right;
if (l->right != _data._nil) {
l->right->parent = p_node;
}
l->parent = p_node->parent;
if (p_node == p_node->parent->right) {
p_node->parent->right = l;
} else {
p_node->parent->left = l;
}
l->right = p_node;
p_node->parent = l;
}
inline Element *_successor(Element *p_node) const {
Element *node = p_node;
if (node->right != _data._nil) {
node = node->right;
while (node->left != _data._nil) { /* returns the minimum of the right subtree of node */
node = node->left;
}
return node;
} else {
while (node == node->parent->right) {
node = node->parent;
}
if (node->parent == _data._root) {
return nullptr; // No successor, as p_node = last node
}
return node->parent;
}
}
inline Element *_predecessor(Element *p_node) const {
Element *node = p_node;
if (node->left != _data._nil) {
node = node->left;
while (node->right != _data._nil) { /* returns the minimum of the left subtree of node */
node = node->right;
}
return node;
} else {
while (node == node->parent->left) {
node = node->parent;
}
if (node == _data._root) {
return nullptr; // No predecessor, as p_node = first node
}
return node->parent;
}
}
Element *_find(const K &p_key) const {
Element *node = _data._root->left;
C less;
while (node != _data._nil) {
if (less(p_key, node->_data.key)) {
node = node->left;
} else if (less(node->_data.key, p_key)) {
node = node->right;
} else {
return node; // found
}
}
return nullptr;
}
Element *_find_closest(const K &p_key) const {
Element *node = _data._root->left;
Element *prev = nullptr;
C less;
while (node != _data._nil) {
prev = node;
if (less(p_key, node->_data.key)) {
node = node->left;
} else if (less(node->_data.key, p_key)) {
node = node->right;
} else {
return node; // found
}
}
if (prev == nullptr) {
return nullptr; // tree empty
}
if (less(p_key, prev->_data.key)) {
prev = prev->_prev;
}
return prev;
}
void _insert_rb_fix(Element *p_new_node) {
Element *node = p_new_node;
Element *nparent = node->parent;
Element *ngrand_parent = nullptr;
while (nparent->color == RED) {
ngrand_parent = nparent->parent;
if (nparent == ngrand_parent->left) {
if (ngrand_parent->right->color == RED) {
_set_color(nparent, BLACK);
_set_color(ngrand_parent->right, BLACK);
_set_color(ngrand_parent, RED);
node = ngrand_parent;
nparent = node->parent;
} else {
if (node == nparent->right) {
_rotate_left(nparent);
node = nparent;
nparent = node->parent;
}
_set_color(nparent, BLACK);
_set_color(ngrand_parent, RED);
_rotate_right(ngrand_parent);
}
} else {
if (ngrand_parent->left->color == RED) {
_set_color(nparent, BLACK);
_set_color(ngrand_parent->left, BLACK);
_set_color(ngrand_parent, RED);
node = ngrand_parent;
nparent = node->parent;
} else {
if (node == nparent->left) {
_rotate_right(nparent);
node = nparent;
nparent = node->parent;
}
_set_color(nparent, BLACK);
_set_color(ngrand_parent, RED);
_rotate_left(ngrand_parent);
}
}
}
_set_color(_data._root->left, BLACK);
}
Element *_insert(const K &p_key, const V &p_value) {
Element *new_parent = _data._root;
Element *node = _data._root->left;
C less;
while (node != _data._nil) {
new_parent = node;
if (less(p_key, node->_data.key)) {
node = node->left;
} else if (less(node->_data.key, p_key)) {
node = node->right;
} else {
node->_data.value = p_value;
return node; // Return existing node with new value
}
}
typedef KeyValue<K, V> KV;
Element *new_node = memnew_allocator(Element(KV(p_key, p_value)), A);
new_node->parent = new_parent;
new_node->right = _data._nil;
new_node->left = _data._nil;
// new_node->data=_data;
if (new_parent == _data._root || less(p_key, new_parent->_data.key)) {
new_parent->left = new_node;
} else {
new_parent->right = new_node;
}
new_node->_next = _successor(new_node);
new_node->_prev = _predecessor(new_node);
if (new_node->_next) {
new_node->_next->_prev = new_node;
}
if (new_node->_prev) {
new_node->_prev->_next = new_node;
}
_data.size_cache++;
_insert_rb_fix(new_node);
return new_node;
}
void _erase_fix_rb(Element *p_node) {
Element *root = _data._root->left;
Element *node = _data._nil;
Element *sibling = p_node;
Element *parent = sibling->parent;
while (node != root) { // If red node found, will exit at a break
if (sibling->color == RED) {
_set_color(sibling, BLACK);
_set_color(parent, RED);
if (sibling == parent->right) {
sibling = sibling->left;
_rotate_left(parent);
} else {
sibling = sibling->right;
_rotate_right(parent);
}
}
if ((sibling->left->color == BLACK) && (sibling->right->color == BLACK)) {
_set_color(sibling, RED);
if (parent->color == RED) {
_set_color(parent, BLACK);
break;
} else { // loop: haven't found any red nodes yet
node = parent;
parent = node->parent;
sibling = (node == parent->left) ? parent->right : parent->left;
}
} else {
if (sibling == parent->right) {
if (sibling->right->color == BLACK) {
_set_color(sibling->left, BLACK);
_set_color(sibling, RED);
_rotate_right(sibling);
sibling = sibling->parent;
}
_set_color(sibling, parent->color);
_set_color(parent, BLACK);
_set_color(sibling->right, BLACK);
_rotate_left(parent);
break;
} else {
if (sibling->left->color == BLACK) {
_set_color(sibling->right, BLACK);
_set_color(sibling, RED);
_rotate_left(sibling);
sibling = sibling->parent;
}
_set_color(sibling, parent->color);
_set_color(parent, BLACK);
_set_color(sibling->left, BLACK);
_rotate_right(parent);
break;
}
}
}
ERR_FAIL_COND(_data._nil->color != BLACK);
}
void _erase(Element *p_node) {
Element *rp = ((p_node->left == _data._nil) || (p_node->right == _data._nil)) ? p_node : p_node->_next;
Element *node = (rp->left == _data._nil) ? rp->right : rp->left;
Element *sibling = nullptr;
if (rp == rp->parent->left) {
rp->parent->left = node;
sibling = rp->parent->right;
} else {
rp->parent->right = node;
sibling = rp->parent->left;
}
if (node->color == RED) {
node->parent = rp->parent;
_set_color(node, BLACK);
} else if (rp->color == BLACK && rp->parent != _data._root) {
_erase_fix_rb(sibling);
}
if (rp != p_node) {
ERR_FAIL_COND(rp == _data._nil);
rp->left = p_node->left;
rp->right = p_node->right;
rp->parent = p_node->parent;
rp->color = p_node->color;
if (p_node->left != _data._nil) {
p_node->left->parent = rp;
}
if (p_node->right != _data._nil) {
p_node->right->parent = rp;
}
if (p_node == p_node->parent->left) {
p_node->parent->left = rp;
} else {
p_node->parent->right = rp;
}
}
if (p_node->_next) {
p_node->_next->_prev = p_node->_prev;
}
if (p_node->_prev) {
p_node->_prev->_next = p_node->_next;
}
memdelete_allocator<Element, A>(p_node);
_data.size_cache--;
ERR_FAIL_COND(_data._nil->color == RED);
}
void _calculate_depth(Element *p_element, int &max_d, int d) const {
if (p_element == _data._nil) {
return;
}
_calculate_depth(p_element->left, max_d, d + 1);
_calculate_depth(p_element->right, max_d, d + 1);
if (d > max_d) {
max_d = d;
}
}
void _cleanup_tree(Element *p_element) {
if (p_element == _data._nil) {
return;
}
_cleanup_tree(p_element->left);
_cleanup_tree(p_element->right);
memdelete_allocator<Element, A>(p_element);
}
void _copy_from(const RBMap &p_map) {
clear();
// not the fastest way, but safeset to write.
for (Element *I = p_map.front(); I; I = I->next()) {
insert(I->key(), I->value());
}
}
public:
const Element *find(const K &p_key) const {
if (!_data._root) {
return nullptr;
}
const Element *res = _find(p_key);
return res;
}
Element *find(const K &p_key) {
if (!_data._root) {
return nullptr;
}
Element *res = _find(p_key);
return res;
}
const Element *find_closest(const K &p_key) const {
if (!_data._root) {
return nullptr;
}
const Element *res = _find_closest(p_key);
return res;
}
Element *find_closest(const K &p_key) {
if (!_data._root) {
return nullptr;
}
Element *res = _find_closest(p_key);
return res;
}
bool has(const K &p_key) const {
return find(p_key) != nullptr;
}
Element *insert(const K &p_key, const V &p_value) {
if (!_data._root) {
_data._create_root();
}
return _insert(p_key, p_value);
}
void erase(Element *p_element) {
if (!_data._root || !p_element) {
return;
}
_erase(p_element);
if (_data.size_cache == 0 && _data._root) {
_data._free_root();
}
}
bool erase(const K &p_key) {
if (!_data._root) {
return false;
}
Element *e = find(p_key);
if (!e) {
return false;
}
_erase(e);
if (_data.size_cache == 0 && _data._root) {
_data._free_root();
}
return true;
}
const V &operator[](const K &p_key) const {
CRASH_COND(!_data._root);
const Element *e = find(p_key);
CRASH_COND(!e);
return e->_data.value;
}
V &operator[](const K &p_key) {
if (!_data._root) {
_data._create_root();
}
Element *e = find(p_key);
if (!e) {
e = insert(p_key, V());
}
return e->_data.value;
}
Element *front() const {
if (!_data._root) {
return nullptr;
}
Element *e = _data._root->left;
if (e == _data._nil) {
return nullptr;
}
while (e->left != _data._nil) {
e = e->left;
}
return e;
}
Element *back() const {
if (!_data._root) {
return nullptr;
}
Element *e = _data._root->left;
if (e == _data._nil) {
return nullptr;
}
while (e->right != _data._nil) {
e = e->right;
}
return e;
}
inline bool is_empty() const {
return _data.size_cache == 0;
}
inline int size() const {
return _data.size_cache;
}
int calculate_depth() const {
// used for debug mostly
if (!_data._root) {
return 0;
}
int max_d = 0;
_calculate_depth(_data._root->left, max_d, 0);
return max_d;
}
void clear() {
if (!_data._root) {
return;
}
_cleanup_tree(_data._root->left);
_data._root->left = _data._nil;
_data.size_cache = 0;
_data._free_root();
}
void operator=(const RBMap &p_map) {
_copy_from(p_map);
}
RBMap(const RBMap &p_map) {
_copy_from(p_map);
}
_FORCE_INLINE_ RBMap() {}
~RBMap() {
clear();
}
};
} // namespace godot
#endif // GODOT_RB_MAP_HPP

View File

@@ -0,0 +1,714 @@
/**************************************************************************/
/* rb_set.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_RB_SET_HPP
#define GODOT_RB_SET_HPP
#include <godot_cpp/core/memory.hpp>
// 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
namespace godot {
template <class T, class C = Comparator<T>, class A = DefaultAllocator>
class RBSet {
enum Color {
RED,
BLACK
};
struct _Data;
public:
class Element {
private:
friend class RBSet<T, C, A>;
int color = RED;
Element *right = nullptr;
Element *left = nullptr;
Element *parent = nullptr;
Element *_next = nullptr;
Element *_prev = nullptr;
T value;
//_Data *data;
public:
const Element *next() const {
return _next;
}
Element *next() {
return _next;
}
const Element *prev() const {
return _prev;
}
Element *prev() {
return _prev;
}
T &get() {
return value;
}
const T &get() const {
return value;
}
Element() {}
};
typedef T ValueType;
struct Iterator {
_FORCE_INLINE_ T &operator*() const {
return E->get();
}
_FORCE_INLINE_ T *operator->() const { return &E->get(); }
_FORCE_INLINE_ Iterator &operator++() {
E = E->next();
return *this;
}
_FORCE_INLINE_ Iterator &operator--() {
E = E->prev();
return *this;
}
_FORCE_INLINE_ bool operator==(const Iterator &b) const { return E == b.E; }
_FORCE_INLINE_ bool operator!=(const Iterator &b) const { return E != b.E; }
explicit operator bool() const { return E != nullptr; }
Iterator(Element *p_E) { E = p_E; }
Iterator() {}
Iterator(const Iterator &p_it) { E = p_it.E; }
private:
Element *E = nullptr;
};
struct ConstIterator {
_FORCE_INLINE_ const T &operator*() const {
return E->get();
}
_FORCE_INLINE_ const T *operator->() const { return &E->get(); }
_FORCE_INLINE_ ConstIterator &operator++() {
E = E->next();
return *this;
}
_FORCE_INLINE_ ConstIterator &operator--() {
E = E->prev();
return *this;
}
_FORCE_INLINE_ bool operator==(const ConstIterator &b) const { return E == b.E; }
_FORCE_INLINE_ bool operator!=(const ConstIterator &b) const { return E != b.E; }
_FORCE_INLINE_ ConstIterator(const Element *p_E) { E = p_E; }
_FORCE_INLINE_ ConstIterator() {}
_FORCE_INLINE_ ConstIterator(const ConstIterator &p_it) { E = p_it.E; }
explicit operator bool() const { return E != nullptr; }
private:
const Element *E = nullptr;
};
_FORCE_INLINE_ Iterator begin() {
return Iterator(front());
}
_FORCE_INLINE_ Iterator end() {
return Iterator(nullptr);
}
#if 0
//to use when replacing find()
_FORCE_INLINE_ Iterator find(const K &p_key) {
return Iterator(find(p_key));
}
#endif
_FORCE_INLINE_ ConstIterator begin() const {
return ConstIterator(front());
}
_FORCE_INLINE_ ConstIterator end() const {
return ConstIterator(nullptr);
}
#if 0
//to use when replacing find()
_FORCE_INLINE_ ConstIterator find(const K &p_key) const {
return ConstIterator(find(p_key));
}
#endif
private:
struct _Data {
Element *_root = nullptr;
Element *_nil = nullptr;
int size_cache = 0;
_FORCE_INLINE_ _Data() {
#ifdef GLOBALNIL_DISABLED
_nil = memnew_allocator(Element, A);
_nil->parent = _nil->left = _nil->right = _nil;
_nil->color = BLACK;
#else
_nil = (Element *)&_GlobalNilClass::_nil;
#endif
}
void _create_root() {
_root = memnew_allocator(Element, A);
_root->parent = _root->left = _root->right = _nil;
_root->color = BLACK;
}
void _free_root() {
if (_root) {
memdelete_allocator<Element, A>(_root);
_root = nullptr;
}
}
~_Data() {
_free_root();
#ifdef GLOBALNIL_DISABLED
memdelete_allocator<Element, A>(_nil);
#endif
}
};
_Data _data;
inline void _set_color(Element *p_node, int p_color) {
ERR_FAIL_COND(p_node == _data._nil && p_color == RED);
p_node->color = p_color;
}
inline void _rotate_left(Element *p_node) {
Element *r = p_node->right;
p_node->right = r->left;
if (r->left != _data._nil) {
r->left->parent = p_node;
}
r->parent = p_node->parent;
if (p_node == p_node->parent->left) {
p_node->parent->left = r;
} else {
p_node->parent->right = r;
}
r->left = p_node;
p_node->parent = r;
}
inline void _rotate_right(Element *p_node) {
Element *l = p_node->left;
p_node->left = l->right;
if (l->right != _data._nil) {
l->right->parent = p_node;
}
l->parent = p_node->parent;
if (p_node == p_node->parent->right) {
p_node->parent->right = l;
} else {
p_node->parent->left = l;
}
l->right = p_node;
p_node->parent = l;
}
inline Element *_successor(Element *p_node) const {
Element *node = p_node;
if (node->right != _data._nil) {
node = node->right;
while (node->left != _data._nil) { /* returns the minimum of the right subtree of node */
node = node->left;
}
return node;
} else {
while (node == node->parent->right) {
node = node->parent;
}
if (node->parent == _data._root) {
return nullptr; // No successor, as p_node = last node
}
return node->parent;
}
}
inline Element *_predecessor(Element *p_node) const {
Element *node = p_node;
if (node->left != _data._nil) {
node = node->left;
while (node->right != _data._nil) { /* returns the minimum of the left subtree of node */
node = node->right;
}
return node;
} else {
while (node == node->parent->left) {
node = node->parent;
}
if (node == _data._root) {
return nullptr; // No predecessor, as p_node = first node.
}
return node->parent;
}
}
Element *_find(const T &p_value) const {
Element *node = _data._root->left;
C less;
while (node != _data._nil) {
if (less(p_value, node->value)) {
node = node->left;
} else if (less(node->value, p_value)) {
node = node->right;
} else {
return node; // found
}
}
return nullptr;
}
Element *_lower_bound(const T &p_value) const {
Element *node = _data._root->left;
Element *prev = nullptr;
C less;
while (node != _data._nil) {
prev = node;
if (less(p_value, node->value)) {
node = node->left;
} else if (less(node->value, p_value)) {
node = node->right;
} else {
return node; // found
}
}
if (prev == nullptr) {
return nullptr; // tree empty
}
if (less(prev->value, p_value)) {
prev = prev->_next;
}
return prev;
}
void _insert_rb_fix(Element *p_new_node) {
Element *node = p_new_node;
Element *nparent = node->parent;
Element *ngrand_parent = nullptr;
while (nparent->color == RED) {
ngrand_parent = nparent->parent;
if (nparent == ngrand_parent->left) {
if (ngrand_parent->right->color == RED) {
_set_color(nparent, BLACK);
_set_color(ngrand_parent->right, BLACK);
_set_color(ngrand_parent, RED);
node = ngrand_parent;
nparent = node->parent;
} else {
if (node == nparent->right) {
_rotate_left(nparent);
node = nparent;
nparent = node->parent;
}
_set_color(nparent, BLACK);
_set_color(ngrand_parent, RED);
_rotate_right(ngrand_parent);
}
} else {
if (ngrand_parent->left->color == RED) {
_set_color(nparent, BLACK);
_set_color(ngrand_parent->left, BLACK);
_set_color(ngrand_parent, RED);
node = ngrand_parent;
nparent = node->parent;
} else {
if (node == nparent->left) {
_rotate_right(nparent);
node = nparent;
nparent = node->parent;
}
_set_color(nparent, BLACK);
_set_color(ngrand_parent, RED);
_rotate_left(ngrand_parent);
}
}
}
_set_color(_data._root->left, BLACK);
}
Element *_insert(const T &p_value) {
Element *new_parent = _data._root;
Element *node = _data._root->left;
C less;
while (node != _data._nil) {
new_parent = node;
if (less(p_value, node->value)) {
node = node->left;
} else if (less(node->value, p_value)) {
node = node->right;
} else {
return node; // Return existing node
}
}
Element *new_node = memnew_allocator(Element, A);
new_node->parent = new_parent;
new_node->right = _data._nil;
new_node->left = _data._nil;
new_node->value = p_value;
// new_node->data=_data;
if (new_parent == _data._root || less(p_value, new_parent->value)) {
new_parent->left = new_node;
} else {
new_parent->right = new_node;
}
new_node->_next = _successor(new_node);
new_node->_prev = _predecessor(new_node);
if (new_node->_next) {
new_node->_next->_prev = new_node;
}
if (new_node->_prev) {
new_node->_prev->_next = new_node;
}
_data.size_cache++;
_insert_rb_fix(new_node);
return new_node;
}
void _erase_fix_rb(Element *p_node) {
Element *root = _data._root->left;
Element *node = _data._nil;
Element *sibling = p_node;
Element *parent = sibling->parent;
while (node != root) { // If red node found, will exit at a break
if (sibling->color == RED) {
_set_color(sibling, BLACK);
_set_color(parent, RED);
if (sibling == parent->right) {
sibling = sibling->left;
_rotate_left(parent);
} else {
sibling = sibling->right;
_rotate_right(parent);
}
}
if ((sibling->left->color == BLACK) && (sibling->right->color == BLACK)) {
_set_color(sibling, RED);
if (parent->color == RED) {
_set_color(parent, BLACK);
break;
} else { // loop: haven't found any red nodes yet
node = parent;
parent = node->parent;
sibling = (node == parent->left) ? parent->right : parent->left;
}
} else {
if (sibling == parent->right) {
if (sibling->right->color == BLACK) {
_set_color(sibling->left, BLACK);
_set_color(sibling, RED);
_rotate_right(sibling);
sibling = sibling->parent;
}
_set_color(sibling, parent->color);
_set_color(parent, BLACK);
_set_color(sibling->right, BLACK);
_rotate_left(parent);
break;
} else {
if (sibling->left->color == BLACK) {
_set_color(sibling->right, BLACK);
_set_color(sibling, RED);
_rotate_left(sibling);
sibling = sibling->parent;
}
_set_color(sibling, parent->color);
_set_color(parent, BLACK);
_set_color(sibling->left, BLACK);
_rotate_right(parent);
break;
}
}
}
ERR_FAIL_COND(_data._nil->color != BLACK);
}
void _erase(Element *p_node) {
Element *rp = ((p_node->left == _data._nil) || (p_node->right == _data._nil)) ? p_node : p_node->_next;
Element *node = (rp->left == _data._nil) ? rp->right : rp->left;
Element *sibling = nullptr;
if (rp == rp->parent->left) {
rp->parent->left = node;
sibling = rp->parent->right;
} else {
rp->parent->right = node;
sibling = rp->parent->left;
}
if (node->color == RED) {
node->parent = rp->parent;
_set_color(node, BLACK);
} else if (rp->color == BLACK && rp->parent != _data._root) {
_erase_fix_rb(sibling);
}
if (rp != p_node) {
ERR_FAIL_COND(rp == _data._nil);
rp->left = p_node->left;
rp->right = p_node->right;
rp->parent = p_node->parent;
rp->color = p_node->color;
if (p_node->left != _data._nil) {
p_node->left->parent = rp;
}
if (p_node->right != _data._nil) {
p_node->right->parent = rp;
}
if (p_node == p_node->parent->left) {
p_node->parent->left = rp;
} else {
p_node->parent->right = rp;
}
}
if (p_node->_next) {
p_node->_next->_prev = p_node->_prev;
}
if (p_node->_prev) {
p_node->_prev->_next = p_node->_next;
}
memdelete_allocator<Element, A>(p_node);
_data.size_cache--;
ERR_FAIL_COND(_data._nil->color == RED);
}
void _calculate_depth(Element *p_element, int &max_d, int d) const {
if (p_element == _data._nil) {
return;
}
_calculate_depth(p_element->left, max_d, d + 1);
_calculate_depth(p_element->right, max_d, d + 1);
if (d > max_d) {
max_d = d;
}
}
void _cleanup_tree(Element *p_element) {
if (p_element == _data._nil) {
return;
}
_cleanup_tree(p_element->left);
_cleanup_tree(p_element->right);
memdelete_allocator<Element, A>(p_element);
}
void _copy_from(const RBSet &p_set) {
clear();
// not the fastest way, but safeset to write.
for (Element *I = p_set.front(); I; I = I->next()) {
insert(I->get());
}
}
public:
const Element *find(const T &p_value) const {
if (!_data._root) {
return nullptr;
}
const Element *res = _find(p_value);
return res;
}
Element *find(const T &p_value) {
if (!_data._root) {
return nullptr;
}
Element *res = _find(p_value);
return res;
}
Element *lower_bound(const T &p_value) const {
if (!_data._root) {
return nullptr;
}
return _lower_bound(p_value);
}
bool has(const T &p_value) const {
return find(p_value) != nullptr;
}
Element *insert(const T &p_value) {
if (!_data._root) {
_data._create_root();
}
return _insert(p_value);
}
void erase(Element *p_element) {
if (!_data._root || !p_element) {
return;
}
_erase(p_element);
if (_data.size_cache == 0 && _data._root) {
_data._free_root();
}
}
bool erase(const T &p_value) {
if (!_data._root) {
return false;
}
Element *e = find(p_value);
if (!e) {
return false;
}
_erase(e);
if (_data.size_cache == 0 && _data._root) {
_data._free_root();
}
return true;
}
Element *front() const {
if (!_data._root) {
return nullptr;
}
Element *e = _data._root->left;
if (e == _data._nil) {
return nullptr;
}
while (e->left != _data._nil) {
e = e->left;
}
return e;
}
Element *back() const {
if (!_data._root) {
return nullptr;
}
Element *e = _data._root->left;
if (e == _data._nil) {
return nullptr;
}
while (e->right != _data._nil) {
e = e->right;
}
return e;
}
inline bool is_empty() const {
return _data.size_cache == 0;
}
inline int size() const {
return _data.size_cache;
}
int calculate_depth() const {
// used for debug mostly
if (!_data._root) {
return 0;
}
int max_d = 0;
_calculate_depth(_data._root->left, max_d, 0);
return max_d;
}
void clear() {
if (!_data._root) {
return;
}
_cleanup_tree(_data._root->left);
_data._root->left = _data._nil;
_data.size_cache = 0;
_data._free_root();
}
void operator=(const RBSet &p_set) {
_copy_from(p_set);
}
RBSet(const RBSet &p_set) {
_copy_from(p_set);
}
_FORCE_INLINE_ RBSet() {}
~RBSet() {
clear();
}
};
} // namespace godot
#endif // GODOT_RB_SET_HPP

View File

@@ -0,0 +1,465 @@
/**************************************************************************/
/* rid_owner.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_RID_OWNER_HPP
#define GODOT_RID_OWNER_HPP
#include <godot_cpp/core/memory.hpp>
#include <godot_cpp/godot.hpp>
#include <godot_cpp/templates/list.hpp>
#include <godot_cpp/templates/spin_lock.hpp>
#include <godot_cpp/variant/utility_functions.hpp>
#include <cstdio>
#include <typeinfo>
namespace godot {
template <class T, bool THREAD_SAFE = false>
class RID_Alloc {
T **chunks = nullptr;
uint32_t **free_list_chunks = nullptr;
uint32_t **validator_chunks = nullptr;
uint32_t elements_in_chunk;
uint32_t max_alloc = 0;
uint32_t alloc_count = 0;
const char *description = nullptr;
SpinLock spin_lock;
_FORCE_INLINE_ RID _allocate_rid() {
if (THREAD_SAFE) {
spin_lock.lock();
}
if (alloc_count == max_alloc) {
// allocate a new chunk
uint32_t chunk_count = alloc_count == 0 ? 0 : (max_alloc / elements_in_chunk);
// grow chunks
chunks = (T **)memrealloc(chunks, sizeof(T *) * (chunk_count + 1));
chunks[chunk_count] = (T *)memalloc(sizeof(T) * elements_in_chunk); // but don't initialize
// grow validators
validator_chunks = (uint32_t **)memrealloc(validator_chunks, sizeof(uint32_t *) * (chunk_count + 1));
validator_chunks[chunk_count] = (uint32_t *)memalloc(sizeof(uint32_t) * elements_in_chunk);
// grow free lists
free_list_chunks = (uint32_t **)memrealloc(free_list_chunks, sizeof(uint32_t *) * (chunk_count + 1));
free_list_chunks[chunk_count] = (uint32_t *)memalloc(sizeof(uint32_t) * elements_in_chunk);
// initialize
for (uint32_t i = 0; i < elements_in_chunk; i++) {
// Don't initialize chunk.
validator_chunks[chunk_count][i] = 0xFFFFFFFF;
free_list_chunks[chunk_count][i] = alloc_count + i;
}
max_alloc += elements_in_chunk;
}
uint32_t free_index = free_list_chunks[alloc_count / elements_in_chunk][alloc_count % elements_in_chunk];
uint32_t free_chunk = free_index / elements_in_chunk;
uint32_t free_element = free_index % elements_in_chunk;
uint32_t validator = (uint32_t)(UtilityFunctions::rid_allocate_id() & 0x7FFFFFFF);
uint64_t id = validator;
id <<= 32;
id |= free_index;
validator_chunks[free_chunk][free_element] = validator;
validator_chunks[free_chunk][free_element] |= 0x80000000; // mark uninitialized bit
alloc_count++;
if (THREAD_SAFE) {
spin_lock.unlock();
}
return UtilityFunctions::rid_from_int64(id);
}
public:
RID make_rid() {
RID rid = _allocate_rid();
initialize_rid(rid);
return rid;
}
RID make_rid(const T &p_value) {
RID rid = _allocate_rid();
initialize_rid(rid, p_value);
return rid;
}
// allocate but don't initialize, use initialize_rid afterwards
RID allocate_rid() {
return _allocate_rid();
}
_FORCE_INLINE_ T *get_or_null(const RID &p_rid, bool p_initialize = false) {
if (p_rid == RID()) {
return nullptr;
}
if (THREAD_SAFE) {
spin_lock.lock();
}
uint64_t id = p_rid.get_id();
uint32_t idx = uint32_t(id & 0xFFFFFFFF);
if (unlikely(idx >= max_alloc)) {
if (THREAD_SAFE) {
spin_lock.unlock();
}
return nullptr;
}
uint32_t idx_chunk = idx / elements_in_chunk;
uint32_t idx_element = idx % elements_in_chunk;
uint32_t validator = uint32_t(id >> 32);
if (unlikely(p_initialize)) {
if (unlikely(!(validator_chunks[idx_chunk][idx_element] & 0x80000000))) {
if (THREAD_SAFE) {
spin_lock.unlock();
}
ERR_FAIL_V_MSG(nullptr, "Initializing already initialized RID");
}
if (unlikely((validator_chunks[idx_chunk][idx_element] & 0x7FFFFFFF) != validator)) {
if (THREAD_SAFE) {
spin_lock.unlock();
}
ERR_FAIL_V_MSG(nullptr, "Attempting to initialize the wrong RID");
return nullptr;
}
validator_chunks[idx_chunk][idx_element] &= 0x7FFFFFFF; // initialized
} else if (unlikely(validator_chunks[idx_chunk][idx_element] != validator)) {
if (THREAD_SAFE) {
spin_lock.unlock();
}
if ((validator_chunks[idx_chunk][idx_element] & 0x80000000) && validator_chunks[idx_chunk][idx_element] != 0xFFFFFFFF) {
ERR_FAIL_V_MSG(nullptr, "Attempting to use an uninitialized RID");
}
return nullptr;
}
T *ptr = &chunks[idx_chunk][idx_element];
if (THREAD_SAFE) {
spin_lock.unlock();
}
return ptr;
}
void initialize_rid(RID p_rid) {
T *mem = get_or_null(p_rid, true);
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_NULL(mem);
memnew_placement(mem, T(p_value));
}
_FORCE_INLINE_ bool owns(const RID &p_rid) {
if (THREAD_SAFE) {
spin_lock.lock();
}
uint64_t id = p_rid.get_id();
uint32_t idx = uint32_t(id & 0xFFFFFFFF);
if (unlikely(idx >= max_alloc)) {
if (THREAD_SAFE) {
spin_lock.unlock();
}
return false;
}
uint32_t idx_chunk = idx / elements_in_chunk;
uint32_t idx_element = idx % elements_in_chunk;
uint32_t validator = uint32_t(id >> 32);
bool owned = (validator_chunks[idx_chunk][idx_element] & 0x7FFFFFFF) == validator;
if (THREAD_SAFE) {
spin_lock.unlock();
}
return owned;
}
_FORCE_INLINE_ void free(const RID &p_rid) {
if (THREAD_SAFE) {
spin_lock.lock();
}
uint64_t id = p_rid.get_id();
uint32_t idx = uint32_t(id & 0xFFFFFFFF);
if (unlikely(idx >= max_alloc)) {
if (THREAD_SAFE) {
spin_lock.unlock();
}
ERR_FAIL();
}
uint32_t idx_chunk = idx / elements_in_chunk;
uint32_t idx_element = idx % elements_in_chunk;
uint32_t validator = uint32_t(id >> 32);
if (unlikely(validator_chunks[idx_chunk][idx_element] & 0x80000000)) {
if (THREAD_SAFE) {
spin_lock.unlock();
}
ERR_FAIL_MSG("Attempted to free an uninitialized or invalid RID");
} else if (unlikely(validator_chunks[idx_chunk][idx_element] != validator)) {
if (THREAD_SAFE) {
spin_lock.unlock();
}
ERR_FAIL();
}
chunks[idx_chunk][idx_element].~T();
validator_chunks[idx_chunk][idx_element] = 0xFFFFFFFF; // go invalid
alloc_count--;
free_list_chunks[alloc_count / elements_in_chunk][alloc_count % elements_in_chunk] = idx;
if (THREAD_SAFE) {
spin_lock.unlock();
}
}
_FORCE_INLINE_ uint32_t get_rid_count() const {
return alloc_count;
}
void get_owned_list(List<RID> *p_owned) {
if (THREAD_SAFE) {
spin_lock.lock();
}
for (size_t i = 0; i < max_alloc; i++) {
uint64_t validator = validator_chunks[i / elements_in_chunk][i % elements_in_chunk];
if (validator != 0xFFFFFFFF) {
p_owned->push_back(UtilityFunctions::rid_from_int64((validator << 32) | i));
}
}
if (THREAD_SAFE) {
spin_lock.unlock();
}
}
// used for fast iteration in the elements or RIDs
void fill_owned_buffer(RID *p_rid_buffer) {
if (THREAD_SAFE) {
spin_lock.lock();
}
uint32_t idx = 0;
for (size_t i = 0; i < max_alloc; i++) {
uint64_t validator = validator_chunks[i / elements_in_chunk][i % elements_in_chunk];
if (validator != 0xFFFFFFFF) {
p_rid_buffer[idx] = UtilityFunctions::rid_from_int64((validator << 32) | i);
idx++;
}
}
if (THREAD_SAFE) {
spin_lock.unlock();
}
}
void set_description(const char *p_descrption) {
description = p_descrption;
}
RID_Alloc(uint32_t p_target_chunk_byte_size = 65536) {
elements_in_chunk = sizeof(T) > p_target_chunk_byte_size ? 1 : (p_target_chunk_byte_size / sizeof(T));
}
~RID_Alloc() {
if (alloc_count) {
if (description) {
printf("ERROR: %d RID allocations of type '%s' were leaked at exit.", alloc_count, description);
} else {
#ifdef NO_SAFE_CAST
printf("ERROR: %d RID allocations of type 'unknown' were leaked at exit.", alloc_count);
#else
printf("ERROR: %d RID allocations of type '%s' were leaked at exit.", alloc_count, typeid(T).name());
#endif
}
for (size_t i = 0; i < max_alloc; i++) {
uint64_t validator = validator_chunks[i / elements_in_chunk][i % elements_in_chunk];
if (validator & 0x80000000) {
continue; // uninitialized
}
if (validator != 0xFFFFFFFF) {
chunks[i / elements_in_chunk][i % elements_in_chunk].~T();
}
}
}
uint32_t chunk_count = max_alloc / elements_in_chunk;
for (uint32_t i = 0; i < chunk_count; i++) {
memfree(chunks[i]);
memfree(validator_chunks[i]);
memfree(free_list_chunks[i]);
}
if (chunks) {
memfree(chunks);
memfree(free_list_chunks);
memfree(validator_chunks);
}
}
};
template <class T, bool THREAD_SAFE = false>
class RID_PtrOwner {
RID_Alloc<T *, THREAD_SAFE> alloc;
public:
_FORCE_INLINE_ RID make_rid(T *p_ptr) {
return alloc.make_rid(p_ptr);
}
_FORCE_INLINE_ RID allocate_rid() {
return alloc.allocate_rid();
}
_FORCE_INLINE_ void initialize_rid(RID p_rid, T *p_ptr) {
alloc.initialize_rid(p_rid, p_ptr);
}
_FORCE_INLINE_ T *get_or_null(const RID &p_rid) {
T **ptr = alloc.get_or_null(p_rid);
if (unlikely(!ptr)) {
return nullptr;
}
return *ptr;
}
_FORCE_INLINE_ void replace(const RID &p_rid, T *p_new_ptr) {
T **ptr = alloc.get_or_null(p_rid);
ERR_FAIL_NULL(ptr);
*ptr = p_new_ptr;
}
_FORCE_INLINE_ bool owns(const RID &p_rid) {
return alloc.owns(p_rid);
}
_FORCE_INLINE_ void free(const RID &p_rid) {
alloc.free(p_rid);
}
_FORCE_INLINE_ uint32_t get_rid_count() const {
return alloc.get_rid_count();
}
_FORCE_INLINE_ void get_owned_list(List<RID> *p_owned) {
return alloc.get_owned_list(p_owned);
}
void fill_owned_buffer(RID *p_rid_buffer) {
alloc.fill_owned_buffer(p_rid_buffer);
}
void set_description(const char *p_descrption) {
alloc.set_description(p_descrption);
}
RID_PtrOwner(uint32_t p_target_chunk_byte_size = 65536) :
alloc(p_target_chunk_byte_size) {}
};
template <class T, bool THREAD_SAFE = false>
class RID_Owner {
RID_Alloc<T, THREAD_SAFE> alloc;
public:
_FORCE_INLINE_ RID make_rid() {
return alloc.make_rid();
}
_FORCE_INLINE_ RID make_rid(const T &p_ptr) {
return alloc.make_rid(p_ptr);
}
_FORCE_INLINE_ RID allocate_rid() {
return alloc.allocate_rid();
}
_FORCE_INLINE_ void initialize_rid(RID p_rid) {
alloc.initialize_rid(p_rid);
}
_FORCE_INLINE_ void initialize_rid(RID p_rid, const T &p_ptr) {
alloc.initialize_rid(p_rid, p_ptr);
}
_FORCE_INLINE_ T *get_or_null(const RID &p_rid) {
return alloc.get_or_null(p_rid);
}
_FORCE_INLINE_ bool owns(const RID &p_rid) {
return alloc.owns(p_rid);
}
_FORCE_INLINE_ void free(const RID &p_rid) {
alloc.free(p_rid);
}
_FORCE_INLINE_ uint32_t get_rid_count() const {
return alloc.get_rid_count();
}
_FORCE_INLINE_ void get_owned_list(List<RID> *p_owned) {
return alloc.get_owned_list(p_owned);
}
void fill_owned_buffer(RID *p_rid_buffer) {
alloc.fill_owned_buffer(p_rid_buffer);
}
void set_description(const char *p_descrption) {
alloc.set_description(p_descrption);
}
RID_Owner(uint32_t p_target_chunk_byte_size = 65536) :
alloc(p_target_chunk_byte_size) {}
};
} // namespace godot
#endif // GODOT_RID_OWNER_HPP

View File

@@ -0,0 +1,326 @@
/**************************************************************************/
/* safe_refcount.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_SAFE_REFCOUNT_HPP
#define GODOT_SAFE_REFCOUNT_HPP
#if !defined(NO_THREADS)
#include <atomic>
#include <type_traits>
namespace godot {
// Design goals for these classes:
// - No automatic conversions or arithmetic operators,
// to keep explicit the use of atomics everywhere.
// - Using acquire-release semantics, even to set the first value.
// The first value may be set relaxedly in many cases, but adding the distinction
// between relaxed and unrelaxed operation to the interface would make it needlessly
// flexible. There's negligible waste in having release semantics for the initial
// 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>
class SafeNumeric {
std::atomic<T> value;
static_assert(std::atomic<T>::is_always_lock_free);
public:
_ALWAYS_INLINE_ void set(T p_value) {
value.store(p_value, std::memory_order_release);
}
_ALWAYS_INLINE_ T get() const {
return value.load(std::memory_order_acquire);
}
_ALWAYS_INLINE_ T increment() {
return value.fetch_add(1, std::memory_order_acq_rel) + 1;
}
// Returns the original value instead of the new one
_ALWAYS_INLINE_ T postincrement() {
return value.fetch_add(1, std::memory_order_acq_rel);
}
_ALWAYS_INLINE_ T decrement() {
return value.fetch_sub(1, std::memory_order_acq_rel) - 1;
}
// Returns the original value instead of the new one
_ALWAYS_INLINE_ T postdecrement() {
return value.fetch_sub(1, std::memory_order_acq_rel);
}
_ALWAYS_INLINE_ T add(T p_value) {
return value.fetch_add(p_value, std::memory_order_acq_rel) + p_value;
}
// Returns the original value instead of the new one
_ALWAYS_INLINE_ T postadd(T p_value) {
return value.fetch_add(p_value, std::memory_order_acq_rel);
}
_ALWAYS_INLINE_ T sub(T p_value) {
return value.fetch_sub(p_value, std::memory_order_acq_rel) - p_value;
}
// Returns the original value instead of the new one
_ALWAYS_INLINE_ T postsub(T p_value) {
return value.fetch_sub(p_value, std::memory_order_acq_rel);
}
_ALWAYS_INLINE_ T exchange_if_greater(T p_value) {
while (true) {
T tmp = value.load(std::memory_order_acquire);
if (tmp >= p_value) {
return tmp; // already greater, or equal
}
if (value.compare_exchange_weak(tmp, p_value, std::memory_order_release)) {
return p_value;
}
}
}
_ALWAYS_INLINE_ T conditional_increment() {
while (true) {
T c = value.load(std::memory_order_acquire);
if (c == 0) {
return 0;
}
if (value.compare_exchange_weak(c, c + 1, std::memory_order_release)) {
return c + 1;
}
}
}
_ALWAYS_INLINE_ explicit SafeNumeric<T>(T p_value = static_cast<T>(0)) {
set(p_value);
}
};
class SafeFlag {
std::atomic_bool flag;
static_assert(std::atomic_bool::is_always_lock_free);
public:
_ALWAYS_INLINE_ bool is_set() const {
return flag.load(std::memory_order_acquire);
}
_ALWAYS_INLINE_ void set() {
flag.store(true, std::memory_order_release);
}
_ALWAYS_INLINE_ void clear() {
flag.store(false, std::memory_order_release);
}
_ALWAYS_INLINE_ void set_to(bool p_value) {
flag.store(p_value, std::memory_order_release);
}
_ALWAYS_INLINE_ explicit SafeFlag(bool p_value = false) {
set_to(p_value);
}
};
class SafeRefCount {
SafeNumeric<uint32_t> count;
public:
_ALWAYS_INLINE_ bool ref() { // true on success
return count.conditional_increment() != 0;
}
_ALWAYS_INLINE_ uint32_t refval() { // none-zero on success
return count.conditional_increment();
}
_ALWAYS_INLINE_ bool unref() { // true if must be disposed of
return count.decrement() == 0;
}
_ALWAYS_INLINE_ uint32_t unrefval() { // 0 if must be disposed of
return count.decrement();
}
_ALWAYS_INLINE_ uint32_t get() const {
return count.get();
}
_ALWAYS_INLINE_ void init(uint32_t p_value = 1) {
count.set(p_value);
}
};
#else
template <class T>
class SafeNumeric {
protected:
T value;
public:
_ALWAYS_INLINE_ void set(T p_value) {
value = p_value;
}
_ALWAYS_INLINE_ T get() const {
return value;
}
_ALWAYS_INLINE_ T increment() {
return ++value;
}
_ALWAYS_INLINE_ T postincrement() {
return value++;
}
_ALWAYS_INLINE_ T decrement() {
return --value;
}
_ALWAYS_INLINE_ T postdecrement() {
return value--;
}
_ALWAYS_INLINE_ T add(T p_value) {
return value += p_value;
}
_ALWAYS_INLINE_ T postadd(T p_value) {
T old = value;
value += p_value;
return old;
}
_ALWAYS_INLINE_ T sub(T p_value) {
return value -= p_value;
}
_ALWAYS_INLINE_ T postsub(T p_value) {
T old = value;
value -= p_value;
return old;
}
_ALWAYS_INLINE_ T exchange_if_greater(T p_value) {
if (value < p_value) {
value = p_value;
}
return value;
}
_ALWAYS_INLINE_ T conditional_increment() {
if (value == 0) {
return 0;
} else {
return ++value;
}
}
_ALWAYS_INLINE_ explicit SafeNumeric<T>(T p_value = static_cast<T>(0)) :
value(p_value) {
}
};
class SafeFlag {
protected:
bool flag;
public:
_ALWAYS_INLINE_ bool is_set() const {
return flag;
}
_ALWAYS_INLINE_ void set() {
flag = true;
}
_ALWAYS_INLINE_ void clear() {
flag = false;
}
_ALWAYS_INLINE_ void set_to(bool p_value) {
flag = p_value;
}
_ALWAYS_INLINE_ explicit SafeFlag(bool p_value = false) :
flag(p_value) {}
};
class SafeRefCount {
uint32_t count = 0;
public:
_ALWAYS_INLINE_ bool ref() { // true on success
if (count != 0) {
++count;
return true;
} else {
return false;
}
}
_ALWAYS_INLINE_ uint32_t refval() { // none-zero on success
if (count != 0) {
return ++count;
} else {
return 0;
}
}
_ALWAYS_INLINE_ bool unref() { // true if must be disposed of
return --count == 0;
}
_ALWAYS_INLINE_ uint32_t unrefval() { // 0 if must be disposed of
return --count;
}
_ALWAYS_INLINE_ uint32_t get() const {
return count;
}
_ALWAYS_INLINE_ void init(uint32_t p_value = 1) {
count = p_value;
}
};
#endif
} // namespace godot
#endif // GODOT_SAFE_REFCOUNT_HPP

View File

@@ -0,0 +1,71 @@
/**************************************************************************/
/* search_array.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_SEARCH_ARRAY_HPP
#define GODOT_SEARCH_ARRAY_HPP
#include <godot_cpp/templates/sort_array.hpp>
namespace godot {
template <class T, class Comparator = _DefaultComparator<T>>
class SearchArray {
public:
Comparator compare;
inline int bisect(const T *p_array, int p_len, const T &p_value, bool p_before) const {
int lo = 0;
int hi = p_len;
if (p_before) {
while (lo < hi) {
const int mid = (lo + hi) / 2;
if (compare(p_array[mid], p_value)) {
lo = mid + 1;
} else {
hi = mid;
}
}
} else {
while (lo < hi) {
const int mid = (lo + hi) / 2;
if (compare(p_value, p_array[mid])) {
hi = mid;
} else {
lo = mid + 1;
}
}
}
return lo;
}
};
} // namespace godot
#endif // GODOT_SEARCH_ARRAY_HPP

View File

@@ -0,0 +1,143 @@
/**************************************************************************/
/* self_list.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_SELF_LIST_HPP
#define GODOT_SELF_LIST_HPP
#include <godot_cpp/core/defs.hpp>
#include <godot_cpp/core/error_macros.hpp>
namespace godot {
template <class T>
class SelfList {
public:
class List {
SelfList<T> *_first = nullptr;
SelfList<T> *_last = nullptr;
public:
void add(SelfList<T> *p_elem) {
ERR_FAIL_COND(p_elem->_root);
p_elem->_root = this;
p_elem->_next = _first;
p_elem->_prev = nullptr;
if (_first) {
_first->_prev = p_elem;
} else {
_last = p_elem;
}
_first = p_elem;
}
void add_last(SelfList<T> *p_elem) {
ERR_FAIL_COND(p_elem->_root);
p_elem->_root = this;
p_elem->_next = nullptr;
p_elem->_prev = _last;
if (_last) {
_last->_next = p_elem;
} else {
_first = p_elem;
}
_last = p_elem;
}
void remove(SelfList<T> *p_elem) {
ERR_FAIL_COND(p_elem->_root != this);
if (p_elem->_next) {
p_elem->_next->_prev = p_elem->_prev;
}
if (p_elem->_prev) {
p_elem->_prev->_next = p_elem->_next;
}
if (_first == p_elem) {
_first = p_elem->_next;
}
if (_last == p_elem) {
_last = p_elem->_prev;
}
p_elem->_next = nullptr;
p_elem->_prev = nullptr;
p_elem->_root = nullptr;
}
_FORCE_INLINE_ SelfList<T> *first() { return _first; }
_FORCE_INLINE_ const SelfList<T> *first() const { return _first; }
_FORCE_INLINE_ List() {}
_FORCE_INLINE_ ~List() { ERR_FAIL_COND(_first != nullptr); }
};
private:
List *_root = nullptr;
T *_self = nullptr;
SelfList<T> *_next = nullptr;
SelfList<T> *_prev = nullptr;
public:
_FORCE_INLINE_ bool in_list() const { return _root; }
_FORCE_INLINE_ void remove_from_list() {
if (_root) {
_root->remove(this);
}
}
_FORCE_INLINE_ SelfList<T> *next() { return _next; }
_FORCE_INLINE_ SelfList<T> *prev() { return _prev; }
_FORCE_INLINE_ const SelfList<T> *next() const { return _next; }
_FORCE_INLINE_ const SelfList<T> *prev() const { return _prev; }
_FORCE_INLINE_ T *self() const { return _self; }
_FORCE_INLINE_ SelfList(T *p_self) {
_self = p_self;
}
_FORCE_INLINE_ ~SelfList() {
if (_root) {
_root->remove(this);
}
}
};
} // namespace godot
#endif // GODOT_SELF_LIST_HPP

View File

@@ -0,0 +1,323 @@
/**************************************************************************/
/* sort_array.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_SORT_ARRAY_HPP
#define GODOT_SORT_ARRAY_HPP
#include <godot_cpp/core/error_macros.hpp>
namespace godot {
#define ERR_BAD_COMPARE(cond) \
if (unlikely(cond)) { \
ERR_PRINT("bad comparison function; sorting will be broken"); \
break; \
}
template <class T>
struct _DefaultComparator {
_FORCE_INLINE_ bool operator()(const T &a, const T &b) const { return (a < b); }
};
#ifdef DEBUG_ENABLED
#define SORT_ARRAY_VALIDATE_ENABLED true
#else
#define SORT_ARRAY_VALIDATE_ENABLED false
#endif
template <class T, class Comparator = _DefaultComparator<T>, bool Validate = SORT_ARRAY_VALIDATE_ENABLED>
class SortArray {
enum {
INTROSORT_THRESHOLD = 16
};
public:
Comparator compare;
inline const T &median_of_3(const T &a, const T &b, const T &c) const {
if (compare(a, b)) {
if (compare(b, c)) {
return b;
} else if (compare(a, c)) {
return c;
} else {
return a;
}
} else if (compare(a, c)) {
return a;
} else if (compare(b, c)) {
return c;
} else {
return b;
}
}
inline int bitlog(int n) const {
int k;
for (k = 0; n != 1; n >>= 1) {
++k;
}
return k;
}
/* Heap / Heapsort functions */
inline void push_heap(int p_first, int p_hole_idx, int p_top_index, T p_value, T *p_array) const {
int parent = (p_hole_idx - 1) / 2;
while (p_hole_idx > p_top_index && compare(p_array[p_first + parent], p_value)) {
p_array[p_first + p_hole_idx] = p_array[p_first + parent];
p_hole_idx = parent;
parent = (p_hole_idx - 1) / 2;
}
p_array[p_first + p_hole_idx] = p_value;
}
inline void pop_heap(int p_first, int p_last, int p_result, T p_value, T *p_array) const {
p_array[p_result] = p_array[p_first];
adjust_heap(p_first, 0, p_last - p_first, p_value, p_array);
}
inline void pop_heap(int p_first, int p_last, T *p_array) const {
pop_heap(p_first, p_last - 1, p_last - 1, p_array[p_last - 1], p_array);
}
inline void adjust_heap(int p_first, int p_hole_idx, int p_len, T p_value, T *p_array) const {
int top_index = p_hole_idx;
int second_child = 2 * p_hole_idx + 2;
while (second_child < p_len) {
if (compare(p_array[p_first + second_child], p_array[p_first + (second_child - 1)])) {
second_child--;
}
p_array[p_first + p_hole_idx] = p_array[p_first + second_child];
p_hole_idx = second_child;
second_child = 2 * (second_child + 1);
}
if (second_child == p_len) {
p_array[p_first + p_hole_idx] = p_array[p_first + (second_child - 1)];
p_hole_idx = second_child - 1;
}
push_heap(p_first, p_hole_idx, top_index, p_value, p_array);
}
inline void sort_heap(int p_first, int p_last, T *p_array) const {
while (p_last - p_first > 1) {
pop_heap(p_first, p_last--, p_array);
}
}
inline void make_heap(int p_first, int p_last, T *p_array) const {
if (p_last - p_first < 2) {
return;
}
int len = p_last - p_first;
int parent = (len - 2) / 2;
while (true) {
adjust_heap(p_first, parent, len, p_array[p_first + parent], p_array);
if (parent == 0) {
return;
}
parent--;
}
}
inline void partial_sort(int p_first, int p_last, int p_middle, T *p_array) const {
make_heap(p_first, p_middle, p_array);
for (int i = p_middle; i < p_last; i++) {
if (compare(p_array[i], p_array[p_first])) {
pop_heap(p_first, p_middle, i, p_array[i], p_array);
}
}
sort_heap(p_first, p_middle, p_array);
}
inline void partial_select(int p_first, int p_last, int p_middle, T *p_array) const {
make_heap(p_first, p_middle, p_array);
for (int i = p_middle; i < p_last; i++) {
if (compare(p_array[i], p_array[p_first])) {
pop_heap(p_first, p_middle, i, p_array[i], p_array);
}
}
}
inline int partitioner(int p_first, int p_last, T p_pivot, T *p_array) const {
const int unmodified_first = p_first;
const int unmodified_last = p_last;
while (true) {
while (compare(p_array[p_first], p_pivot)) {
if (Validate) {
ERR_BAD_COMPARE(p_first == unmodified_last - 1);
}
p_first++;
}
p_last--;
while (compare(p_pivot, p_array[p_last])) {
if (Validate) {
ERR_BAD_COMPARE(p_last == unmodified_first);
}
p_last--;
}
if (!(p_first < p_last)) {
return p_first;
}
SWAP(p_array[p_first], p_array[p_last]);
p_first++;
}
}
inline void introsort(int p_first, int p_last, T *p_array, int p_max_depth) const {
while (p_last - p_first > INTROSORT_THRESHOLD) {
if (p_max_depth == 0) {
partial_sort(p_first, p_last, p_last, p_array);
return;
}
p_max_depth--;
int cut = partitioner(
p_first,
p_last,
median_of_3(
p_array[p_first],
p_array[p_first + (p_last - p_first) / 2],
p_array[p_last - 1]),
p_array);
introsort(cut, p_last, p_array, p_max_depth);
p_last = cut;
}
}
inline void introselect(int p_first, int p_nth, int p_last, T *p_array, int p_max_depth) const {
while (p_last - p_first > 3) {
if (p_max_depth == 0) {
partial_select(p_first, p_nth + 1, p_last, p_array);
SWAP(p_first, p_nth);
return;
}
p_max_depth--;
int cut = partitioner(
p_first,
p_last,
median_of_3(
p_array[p_first],
p_array[p_first + (p_last - p_first) / 2],
p_array[p_last - 1]),
p_array);
if (cut <= p_nth) {
p_first = cut;
} else {
p_last = cut;
}
}
insertion_sort(p_first, p_last, p_array);
}
inline void unguarded_linear_insert(int p_last, T p_value, T *p_array) const {
int next = p_last - 1;
while (compare(p_value, p_array[next])) {
if (Validate) {
ERR_BAD_COMPARE(next == 0);
}
p_array[p_last] = p_array[next];
p_last = next;
next--;
}
p_array[p_last] = p_value;
}
inline void linear_insert(int p_first, int p_last, T *p_array) const {
T val = p_array[p_last];
if (compare(val, p_array[p_first])) {
for (int i = p_last; i > p_first; i--) {
p_array[i] = p_array[i - 1];
}
p_array[p_first] = val;
} else {
unguarded_linear_insert(p_last, val, p_array);
}
}
inline void insertion_sort(int p_first, int p_last, T *p_array) const {
if (p_first == p_last) {
return;
}
for (int i = p_first + 1; i != p_last; i++) {
linear_insert(p_first, i, p_array);
}
}
inline void unguarded_insertion_sort(int p_first, int p_last, T *p_array) const {
for (int i = p_first; i != p_last; i++) {
unguarded_linear_insert(i, p_array[i], p_array);
}
}
inline void final_insertion_sort(int p_first, int p_last, T *p_array) const {
if (p_last - p_first > INTROSORT_THRESHOLD) {
insertion_sort(p_first, p_first + INTROSORT_THRESHOLD, p_array);
unguarded_insertion_sort(p_first + INTROSORT_THRESHOLD, p_last, p_array);
} else {
insertion_sort(p_first, p_last, p_array);
}
}
inline void sort_range(int p_first, int p_last, T *p_array) const {
if (p_first != p_last) {
introsort(p_first, p_last, p_array, bitlog(p_last - p_first) * 2);
final_insertion_sort(p_first, p_last, p_array);
}
}
inline void sort(T *p_array, int p_len) const {
sort_range(0, p_len, p_array);
}
inline void nth_element(int p_first, int p_last, int p_nth, T *p_array) const {
if (p_first == p_last || p_nth == p_last) {
return;
}
introselect(p_first, p_nth, p_last, p_array, bitlog(p_last - p_first) * 2);
}
};
} // namespace godot
#endif // GODOT_SORT_ARRAY_HPP

View File

@@ -0,0 +1,54 @@
/**************************************************************************/
/* spin_lock.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_SPIN_LOCK_HPP
#define GODOT_SPIN_LOCK_HPP
#include <atomic>
namespace godot {
class SpinLock {
std::atomic_flag locked = ATOMIC_FLAG_INIT;
public:
_ALWAYS_INLINE_ void lock() {
while (locked.test_and_set(std::memory_order_acquire)) {
;
}
}
_ALWAYS_INLINE_ void unlock() {
locked.clear(std::memory_order_release);
}
};
} // namespace godot
#endif // GODOT_SPIN_LOCK_HPP

View File

@@ -0,0 +1,205 @@
/**************************************************************************/
/* thread_work_pool.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_THREAD_WORK_POOL_HPP
#define GODOT_THREAD_WORK_POOL_HPP
#include <godot_cpp/classes/os.hpp>
#include <godot_cpp/classes/semaphore.hpp>
#include <godot_cpp/core/error_macros.hpp>
#include <godot_cpp/core/memory.hpp>
#include <thread>
#include <atomic>
namespace godot {
class ThreadWorkPool {
std::atomic<uint32_t> index;
struct BaseWork {
std::atomic<uint32_t> *index = nullptr;
uint32_t max_elements = 0;
virtual void work() = 0;
virtual ~BaseWork() = default;
};
template <class C, class M, class U>
struct Work : public BaseWork {
C *instance;
M method;
U userdata;
virtual void work() {
while (true) {
uint32_t work_index = index->fetch_add(1, std::memory_order_relaxed);
if (work_index >= max_elements) {
break;
}
(instance->*method)(work_index, userdata);
}
}
};
struct ThreadData {
std::thread thread;
Semaphore start;
Semaphore completed;
std::atomic<bool> exit;
BaseWork *work;
};
ThreadData *threads = nullptr;
uint32_t thread_count = 0;
uint32_t threads_working = 0;
BaseWork *current_work = nullptr;
static void _thread_function(void *p_user) {
ThreadData *thread = static_cast<ThreadData *>(p_user);
while (true) {
thread->start.wait();
if (thread->exit.load()) {
break;
}
thread->work->work();
thread->completed.post();
}
}
public:
template <class C, class M, class U>
void begin_work(uint32_t p_elements, C *p_instance, M p_method, U p_userdata) {
ERR_FAIL_NULL(threads); // Never initialized.
ERR_FAIL_COND(current_work != nullptr);
index.store(0, std::memory_order_release);
Work<C, M, U> *w = new (Work<C, M, U>);
w->instance = p_instance;
w->userdata = p_userdata;
w->method = p_method;
w->index = &index;
w->max_elements = p_elements;
current_work = w;
threads_working = Math::min(p_elements, thread_count);
for (uint32_t i = 0; i < threads_working; i++) {
threads[i].work = w;
threads[i].start.post();
}
}
bool is_working() const {
return current_work != nullptr;
}
bool is_done_dispatching() const {
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_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_NULL(current_work);
for (uint32_t i = 0; i < threads_working; i++) {
threads[i].completed.wait();
threads[i].work = nullptr;
}
threads_working = 0;
delete current_work;
current_work = nullptr;
}
template <class C, class M, class U>
void do_work(uint32_t p_elements, C *p_instance, M p_method, U p_userdata) {
switch (p_elements) {
case 0:
// Nothing to do, so do nothing.
break;
case 1:
// No value in pushing the work to another thread if it's a single job
// and we're going to wait for it to finish. Just run it right here.
(p_instance->*p_method)(0, p_userdata);
break;
default:
// Multiple jobs to do; commence threaded business.
begin_work(p_elements, p_instance, p_method, p_userdata);
end_work();
}
}
_FORCE_INLINE_ int get_thread_count() const { return thread_count; }
void init(int p_thread_count = -1) {
ERR_FAIL_COND(threads != nullptr);
if (p_thread_count < 0) {
p_thread_count = OS::get_singleton()->get_processor_count();
}
thread_count = p_thread_count;
threads = new ThreadData[thread_count];
for (uint32_t i = 0; i < thread_count; i++) {
threads[i].exit.store(false);
threads[i].thread = std::thread(&ThreadWorkPool::_thread_function, &threads[i]);
}
}
void finish() {
if (threads == nullptr) {
return;
}
for (uint32_t i = 0; i < thread_count; i++) {
threads[i].exit.store(true);
threads[i].start.post();
}
for (uint32_t i = 0; i < thread_count; i++) {
threads[i].thread.join();
}
delete[] (threads);
threads = nullptr;
}
~ThreadWorkPool() {
finish();
}
};
} // namespace godot
#endif // GODOT_THREAD_WORK_POOL_HPP

View File

@@ -0,0 +1,321 @@
/**************************************************************************/
/* vector.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_VECTOR_HPP
#define GODOT_VECTOR_HPP
/**
* @class Vector
* Vector container. Regular Vector Container. Use with care and for smaller arrays when possible. Use Vector for large arrays.
*/
#include <godot_cpp/core/error_macros.hpp>
#include <godot_cpp/core/memory.hpp>
#include <godot_cpp/templates/cowdata.hpp>
#include <godot_cpp/templates/search_array.hpp>
#include <godot_cpp/templates/sort_array.hpp>
#include <climits>
#include <initializer_list>
namespace godot {
template <class T>
class VectorWriteProxy {
public:
_FORCE_INLINE_ T &operator[](int p_index) {
CRASH_BAD_INDEX(p_index, ((Vector<T> *)(this))->_cowdata.size());
return ((Vector<T> *)(this))->_cowdata.ptrw()[p_index];
}
};
template <class T>
class Vector {
friend class VectorWriteProxy<T>;
public:
VectorWriteProxy<T> write;
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
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);
if (idx >= 0) {
remove_at(idx);
}
}
void reverse();
_FORCE_INLINE_ T *ptrw() { return _cowdata.ptrw(); }
_FORCE_INLINE_ const T *ptr() const { return _cowdata.ptr(); }
_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); }
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();
if (len == 0) {
return;
}
T *data = ptrw();
SortArray<T, C> sorter;
sorter.sort(data, len);
}
void sort() {
sort_custom<_DefaultComparator<T>>();
}
int bsearch(const T &p_value, bool p_before) {
SearchArray<T> search;
return search.bisect(ptrw(), size(), p_value, p_before);
}
Vector<T> duplicate() {
return *this;
}
void ordered_insert(const T &p_val) {
int i;
for (i = 0; i < _cowdata.size(); i++) {
if (p_val < operator[](i)) {
break;
}
}
insert(i, p_val);
}
inline void operator=(const Vector &p_from) {
_cowdata._ref(p_from._cowdata);
}
Vector<uint8_t> to_byte_array() const {
Vector<uint8_t> 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> result;
const int s = size();
int begin = Math::clamp(p_begin, -s, s);
if (begin < 0) {
begin += s;
}
int end = Math::clamp(p_end, -s, s);
if (end < 0) {
end += s;
}
ERR_FAIL_COND_V(begin > end, result);
int 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) {
w[i] = r[begin + i];
}
return result;
}
bool operator==(const Vector<T> &p_arr) const {
int s = size();
if (s != p_arr.size()) {
return false;
}
for (int i = 0; i < s; i++) {
if (operator[](i) != p_arr[i]) {
return false;
}
}
return true;
}
bool operator!=(const Vector<T> &p_arr) const {
int s = size();
if (s != p_arr.size()) {
return true;
}
for (int i = 0; i < s; i++) {
if (operator[](i) != p_arr[i]) {
return true;
}
}
return false;
}
struct Iterator {
_FORCE_INLINE_ T &operator*() const {
return *elem_ptr;
}
_FORCE_INLINE_ T *operator->() const { return elem_ptr; }
_FORCE_INLINE_ Iterator &operator++() {
elem_ptr++;
return *this;
}
_FORCE_INLINE_ Iterator &operator--() {
elem_ptr--;
return *this;
}
_FORCE_INLINE_ bool operator==(const Iterator &b) const { return elem_ptr == b.elem_ptr; }
_FORCE_INLINE_ bool operator!=(const Iterator &b) const { return elem_ptr != b.elem_ptr; }
Iterator(T *p_ptr) { elem_ptr = p_ptr; }
Iterator() {}
Iterator(const Iterator &p_it) { elem_ptr = p_it.elem_ptr; }
private:
T *elem_ptr = nullptr;
};
struct ConstIterator {
_FORCE_INLINE_ const T &operator*() const {
return *elem_ptr;
}
_FORCE_INLINE_ const T *operator->() const { return elem_ptr; }
_FORCE_INLINE_ ConstIterator &operator++() {
elem_ptr++;
return *this;
}
_FORCE_INLINE_ ConstIterator &operator--() {
elem_ptr--;
return *this;
}
_FORCE_INLINE_ bool operator==(const ConstIterator &b) const { return elem_ptr == b.elem_ptr; }
_FORCE_INLINE_ bool operator!=(const ConstIterator &b) const { return elem_ptr != b.elem_ptr; }
ConstIterator(const T *p_ptr) { elem_ptr = p_ptr; }
ConstIterator() {}
ConstIterator(const ConstIterator &p_it) { elem_ptr = p_it.elem_ptr; }
private:
const T *elem_ptr = nullptr;
};
_FORCE_INLINE_ Iterator begin() {
return Iterator(ptrw());
}
_FORCE_INLINE_ Iterator end() {
return Iterator(ptrw() + size());
}
_FORCE_INLINE_ ConstIterator begin() const {
return ConstIterator(ptr());
}
_FORCE_INLINE_ ConstIterator end() const {
return ConstIterator(ptr() + size());
}
_FORCE_INLINE_ Vector() {}
_FORCE_INLINE_ Vector(std::initializer_list<T> p_init) {
Error err = _cowdata.resize(p_init.size());
ERR_FAIL_COND(err);
int i = 0;
for (const T &element : p_init) {
_cowdata.set(i++, element);
}
}
_FORCE_INLINE_ Vector(const Vector &p_from) { _cowdata._ref(p_from._cowdata); }
_FORCE_INLINE_ ~Vector() {}
};
template <class T>
void Vector<T>::reverse() {
for (int i = 0; i < size() / 2; i++) {
T *p = ptrw();
SWAP(p[i], p[size() - i - 1]);
}
}
template <class T>
void Vector<T>::append_array(Vector<T> p_other) {
const int ds = p_other.size();
if (ds == 0) {
return;
}
const int bs = size();
resize(bs + ds);
for (int i = 0; i < ds; ++i) {
ptrw()[bs + i] = p_other[i];
}
}
template <class T>
bool Vector<T>::push_back(T p_elem) {
Error err = resize(size() + 1);
ERR_FAIL_COND_V(err, true);
set(size() - 1, p_elem);
return false;
}
template <class T>
void Vector<T>::fill(T p_elem) {
T *p = ptrw();
for (int i = 0; i < size(); i++) {
p[i] = p_elem;
}
}
} // namespace godot
#endif // GODOT_VECTOR_HPP

View File

@@ -0,0 +1,204 @@
/**************************************************************************/
/* vmap.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_VMAP_HPP
#define GODOT_VMAP_HPP
#include <godot_cpp/templates/cowdata.hpp>
namespace godot {
template <class T, class V>
class VMap {
public:
struct Pair {
T key;
V value;
_FORCE_INLINE_ Pair() {}
_FORCE_INLINE_ Pair(const T &p_key, const V &p_value) {
key = p_key;
value = p_value;
}
};
private:
CowData<Pair> _cowdata;
_FORCE_INLINE_ int _find(const T &p_val, bool &r_exact) const {
r_exact = false;
if (_cowdata.is_empty()) {
return 0;
}
int low = 0;
int high = _cowdata.size() - 1;
const Pair *a = _cowdata.ptr();
int middle = 0;
#ifdef DEBUG_ENABLED
if (low > high) {
ERR_PRINT("low > high, this may be a bug");
}
#endif
while (low <= high) {
middle = (low + high) / 2;
if (p_val < a[middle].key) {
high = middle - 1; // search low end of array
} else if (a[middle].key < p_val) {
low = middle + 1; // search high end of array
} else {
r_exact = true;
return middle;
}
}
// return the position where this would be inserted
if (a[middle].key < p_val) {
middle++;
}
return middle;
}
_FORCE_INLINE_ int _find_exact(const T &p_val) const {
if (_cowdata.is_empty()) {
return -1;
}
int low = 0;
int high = _cowdata.size() - 1;
int middle;
const Pair *a = _cowdata.ptr();
while (low <= high) {
middle = (low + high) / 2;
if (p_val < a[middle].key) {
high = middle - 1; // search low end of array
} else if (a[middle].key < p_val) {
low = middle + 1; // search high end of array
} else {
return middle;
}
}
return -1;
}
public:
int insert(const T &p_key, const V &p_val) {
bool exact;
int pos = _find(p_key, exact);
if (exact) {
_cowdata.get_m(pos).value = p_val;
return pos;
}
_cowdata.insert(pos, Pair(p_key, p_val));
return pos;
}
bool has(const T &p_val) const {
return _find_exact(p_val) != -1;
}
void erase(const T &p_val) {
int pos = _find_exact(p_val);
if (pos < 0) {
return;
}
_cowdata.remove_at(pos);
}
int find(const T &p_val) const {
return _find_exact(p_val);
}
int find_nearest(const T &p_val) const {
bool exact;
return _find(p_val, exact);
}
_FORCE_INLINE_ int size() const { return _cowdata.size(); }
_FORCE_INLINE_ bool is_empty() const { return _cowdata.is_empty(); }
const Pair *get_array() const {
return _cowdata.ptr();
}
Pair *get_array() {
return _cowdata.ptrw();
}
const V &getv(int p_index) const {
return _cowdata.get(p_index).value;
}
V &getv(int p_index) {
return _cowdata.get_m(p_index).value;
}
const T &getk(int p_index) const {
return _cowdata.get(p_index).key;
}
T &getk(int p_index) {
return _cowdata.get_m(p_index).key;
}
inline const V &operator[](const T &p_key) const {
int pos = _find_exact(p_key);
CRASH_COND(pos < 0);
return _cowdata.get(pos).value;
}
inline V &operator[](const T &p_key) {
int pos = _find_exact(p_key);
if (pos < 0) {
pos = insert(p_key, V());
}
return _cowdata.get_m(pos).value;
}
_FORCE_INLINE_ VMap() {}
_FORCE_INLINE_ VMap(const VMap &p_from) { _cowdata._ref(p_from._cowdata); }
inline void operator=(const VMap &p_from) {
_cowdata._ref(p_from._cowdata);
}
};
} // namespace godot
#endif // GODOT_VMAP_HPP

View File

@@ -0,0 +1,145 @@
/**************************************************************************/
/* vset.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_VSET_HPP
#define GODOT_VSET_HPP
#include <godot_cpp/templates/vector.hpp>
namespace godot {
template <class T>
class VSet {
Vector<T> _data;
_FORCE_INLINE_ int _find(const T &p_val, bool &r_exact) const {
r_exact = false;
if (_data.is_empty()) {
return 0;
}
int low = 0;
int high = _data.size() - 1;
const T *a = &_data[0];
int middle = 0;
#ifdef DEBUG_ENABLED
if (low > high) {
ERR_PRINT("low > high, this may be a bug");
}
#endif
while (low <= high) {
middle = (low + high) / 2;
if (p_val < a[middle]) {
high = middle - 1; // search low end of array
} else if (a[middle] < p_val) {
low = middle + 1; // search high end of array
} else {
r_exact = true;
return middle;
}
}
// return the position where this would be inserted
if (a[middle] < p_val) {
middle++;
}
return middle;
}
_FORCE_INLINE_ int _find_exact(const T &p_val) const {
if (_data.is_empty()) {
return -1;
}
int low = 0;
int high = _data.size() - 1;
int middle;
const T *a = &_data[0];
while (low <= high) {
middle = (low + high) / 2;
if (p_val < a[middle]) {
high = middle - 1; // search low end of array
} else if (a[middle] < p_val) {
low = middle + 1; // search high end of array
} else {
return middle;
}
}
return -1;
}
public:
void insert(const T &p_val) {
bool exact;
int pos = _find(p_val, exact);
if (exact) {
return;
}
_data.insert(pos, p_val);
}
bool has(const T &p_val) const {
return _find_exact(p_val) != -1;
}
void erase(const T &p_val) {
int pos = _find_exact(p_val);
if (pos < 0) {
return;
}
_data.remove_at(pos);
}
int find(const T &p_val) const {
return _find_exact(p_val);
}
_FORCE_INLINE_ bool is_empty() const { return _data.is_empty(); }
_FORCE_INLINE_ int size() const { return _data.size(); }
inline T &operator[](int p_index) {
return _data.write[p_index];
}
inline const T &operator[](int p_index) const {
return _data[p_index];
}
};
} // namespace godot
#endif // GODOT_VSET_HPP

View File

@@ -0,0 +1,494 @@
/**************************************************************************/
/* aabb.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_AABB_HPP
#define GODOT_AABB_HPP
#include <godot_cpp/variant/plane.hpp>
#include <godot_cpp/variant/vector3.hpp>
/**
* AABB (Axis Aligned Bounding Box)
* This is implemented by a point (position) and the box size.
*/
namespace godot {
class Variant;
struct _NO_DISCARD_ AABB {
Vector3 position;
Vector3 size;
real_t get_volume() const;
_FORCE_INLINE_ bool has_volume() const {
return size.x > 0.0f && size.y > 0.0f && size.z > 0.0f;
}
_FORCE_INLINE_ bool has_surface() const {
return size.x > 0.0f || size.y > 0.0f || size.z > 0.0f;
}
const Vector3 &get_position() const { return position; }
void set_position(const Vector3 &p_pos) { position = p_pos; }
const Vector3 &get_size() const { return size; }
void set_size(const Vector3 &p_size) { size = p_size; }
bool operator==(const AABB &p_rval) const;
bool operator!=(const AABB &p_rval) const;
bool is_equal_approx(const AABB &p_aabb) const;
_FORCE_INLINE_ bool intersects(const AABB &p_aabb) const; /// Both AABBs overlap
_FORCE_INLINE_ bool intersects_inclusive(const AABB &p_aabb) const; /// Both AABBs (or their faces) overlap
_FORCE_INLINE_ bool encloses(const AABB &p_aabb) const; /// p_aabb is completely inside this
AABB merge(const AABB &p_with) const;
void merge_with(const AABB &p_aabb); ///merge with another AABB
AABB intersection(const AABB &p_aabb) const; ///get box where two intersect, empty if no intersection occurs
bool intersects_segment(const Vector3 &p_from, const Vector3 &p_to, Vector3 *r_clip = nullptr, Vector3 *r_normal = nullptr) const;
bool intersects_ray(const Vector3 &p_from, const Vector3 &p_dir, Vector3 *r_clip = nullptr, Vector3 *r_normal = nullptr) const;
_FORCE_INLINE_ bool smits_intersect_ray(const Vector3 &p_from, const Vector3 &p_dir, real_t t0, real_t t1) const;
_FORCE_INLINE_ bool intersects_convex_shape(const Plane *p_planes, int p_plane_count, const Vector3 *p_points, int p_point_count) const;
_FORCE_INLINE_ bool inside_convex_shape(const Plane *p_planes, int p_plane_count) const;
bool intersects_plane(const Plane &p_plane) const;
_FORCE_INLINE_ bool has_point(const Vector3 &p_point) const;
_FORCE_INLINE_ Vector3 get_support(const Vector3 &p_normal) const;
Vector3 get_longest_axis() const;
int get_longest_axis_index() const;
_FORCE_INLINE_ real_t get_longest_axis_size() const;
Vector3 get_shortest_axis() const;
int get_shortest_axis_index() const;
_FORCE_INLINE_ real_t get_shortest_axis_size() const;
AABB grow(real_t p_by) const;
_FORCE_INLINE_ void grow_by(real_t p_amount);
void get_edge(int p_edge, Vector3 &r_from, Vector3 &r_to) const;
_FORCE_INLINE_ Vector3 get_endpoint(int p_point) const;
AABB expand(const Vector3 &p_vector) const;
_FORCE_INLINE_ void project_range_in_plane(const Plane &p_plane, real_t &r_min, real_t &r_max) const;
_FORCE_INLINE_ void expand_to(const Vector3 &p_vector); /** expand to contain a point if necessary */
_FORCE_INLINE_ AABB abs() const {
return AABB(Vector3(position.x + MIN(size.x, (real_t)0), position.y + MIN(size.y, (real_t)0), position.z + MIN(size.z, (real_t)0)), size.abs());
}
Variant intersects_segment_bind(const Vector3 &p_from, const Vector3 &p_to) const;
Variant intersects_ray_bind(const Vector3 &p_from, const Vector3 &p_dir) const;
_FORCE_INLINE_ void quantize(real_t p_unit);
_FORCE_INLINE_ AABB quantized(real_t p_unit) const;
_FORCE_INLINE_ void set_end(const Vector3 &p_end) {
size = p_end - position;
}
_FORCE_INLINE_ Vector3 get_end() const {
return position + size;
}
_FORCE_INLINE_ Vector3 get_center() const {
return position + (size * 0.5f);
}
operator String() const;
_FORCE_INLINE_ AABB() {}
inline AABB(const Vector3 &p_pos, const Vector3 &p_size) :
position(p_pos),
size(p_size) {
}
};
inline bool AABB::intersects(const AABB &p_aabb) const {
#ifdef MATH_CHECKS
if (unlikely(size.x < 0 || size.y < 0 || size.z < 0 || p_aabb.size.x < 0 || p_aabb.size.y < 0 || p_aabb.size.z < 0)) {
ERR_PRINT("AABB size is negative, this is not supported. Use AABB.abs() to get an AABB with a positive size.");
}
#endif
if (position.x >= (p_aabb.position.x + p_aabb.size.x)) {
return false;
}
if ((position.x + size.x) <= p_aabb.position.x) {
return false;
}
if (position.y >= (p_aabb.position.y + p_aabb.size.y)) {
return false;
}
if ((position.y + size.y) <= p_aabb.position.y) {
return false;
}
if (position.z >= (p_aabb.position.z + p_aabb.size.z)) {
return false;
}
if ((position.z + size.z) <= p_aabb.position.z) {
return false;
}
return true;
}
inline bool AABB::intersects_inclusive(const AABB &p_aabb) const {
#ifdef MATH_CHECKS
if (unlikely(size.x < 0 || size.y < 0 || size.z < 0 || p_aabb.size.x < 0 || p_aabb.size.y < 0 || p_aabb.size.z < 0)) {
ERR_PRINT("AABB size is negative, this is not supported. Use AABB.abs() to get an AABB with a positive size.");
}
#endif
if (position.x > (p_aabb.position.x + p_aabb.size.x)) {
return false;
}
if ((position.x + size.x) < p_aabb.position.x) {
return false;
}
if (position.y > (p_aabb.position.y + p_aabb.size.y)) {
return false;
}
if ((position.y + size.y) < p_aabb.position.y) {
return false;
}
if (position.z > (p_aabb.position.z + p_aabb.size.z)) {
return false;
}
if ((position.z + size.z) < p_aabb.position.z) {
return false;
}
return true;
}
inline bool AABB::encloses(const AABB &p_aabb) const {
#ifdef MATH_CHECKS
if (unlikely(size.x < 0 || size.y < 0 || size.z < 0 || p_aabb.size.x < 0 || p_aabb.size.y < 0 || p_aabb.size.z < 0)) {
ERR_PRINT("AABB size is negative, this is not supported. Use AABB.abs() to get an AABB with a positive size.");
}
#endif
Vector3 src_min = position;
Vector3 src_max = position + size;
Vector3 dst_min = p_aabb.position;
Vector3 dst_max = p_aabb.position + p_aabb.size;
return (
(src_min.x <= dst_min.x) &&
(src_max.x > dst_max.x) &&
(src_min.y <= dst_min.y) &&
(src_max.y > dst_max.y) &&
(src_min.z <= dst_min.z) &&
(src_max.z > dst_max.z));
}
Vector3 AABB::get_support(const Vector3 &p_normal) const {
Vector3 half_extents = size * 0.5f;
Vector3 ofs = position + half_extents;
return Vector3(
(p_normal.x > 0) ? half_extents.x : -half_extents.x,
(p_normal.y > 0) ? half_extents.y : -half_extents.y,
(p_normal.z > 0) ? half_extents.z : -half_extents.z) +
ofs;
}
Vector3 AABB::get_endpoint(int p_point) const {
switch (p_point) {
case 0:
return Vector3(position.x, position.y, position.z);
case 1:
return Vector3(position.x, position.y, position.z + size.z);
case 2:
return Vector3(position.x, position.y + size.y, position.z);
case 3:
return Vector3(position.x, position.y + size.y, position.z + size.z);
case 4:
return Vector3(position.x + size.x, position.y, position.z);
case 5:
return Vector3(position.x + size.x, position.y, position.z + size.z);
case 6:
return Vector3(position.x + size.x, position.y + size.y, position.z);
case 7:
return Vector3(position.x + size.x, position.y + size.y, position.z + size.z);
}
ERR_FAIL_V(Vector3());
}
bool AABB::intersects_convex_shape(const Plane *p_planes, int p_plane_count, const Vector3 *p_points, int p_point_count) const {
Vector3 half_extents = size * 0.5f;
Vector3 ofs = position + half_extents;
for (int i = 0; i < p_plane_count; i++) {
const Plane &p = p_planes[i];
Vector3 point(
(p.normal.x > 0) ? -half_extents.x : half_extents.x,
(p.normal.y > 0) ? -half_extents.y : half_extents.y,
(p.normal.z > 0) ? -half_extents.z : half_extents.z);
point += ofs;
if (p.is_point_over(point)) {
return false;
}
}
// Make sure all points in the shape aren't fully separated from the AABB on
// each axis.
int bad_point_counts_positive[3] = { 0 };
int bad_point_counts_negative[3] = { 0 };
for (int k = 0; k < 3; k++) {
for (int i = 0; i < p_point_count; i++) {
if (p_points[i].coord[k] > ofs.coord[k] + half_extents.coord[k]) {
bad_point_counts_positive[k]++;
}
if (p_points[i].coord[k] < ofs.coord[k] - half_extents.coord[k]) {
bad_point_counts_negative[k]++;
}
}
if (bad_point_counts_negative[k] == p_point_count) {
return false;
}
if (bad_point_counts_positive[k] == p_point_count) {
return false;
}
}
return true;
}
bool AABB::inside_convex_shape(const Plane *p_planes, int p_plane_count) const {
Vector3 half_extents = size * 0.5f;
Vector3 ofs = position + half_extents;
for (int i = 0; i < p_plane_count; i++) {
const Plane &p = p_planes[i];
Vector3 point(
(p.normal.x < 0) ? -half_extents.x : half_extents.x,
(p.normal.y < 0) ? -half_extents.y : half_extents.y,
(p.normal.z < 0) ? -half_extents.z : half_extents.z);
point += ofs;
if (p.is_point_over(point)) {
return false;
}
}
return true;
}
bool AABB::has_point(const Vector3 &p_point) const {
#ifdef MATH_CHECKS
if (unlikely(size.x < 0 || size.y < 0 || size.z < 0)) {
ERR_PRINT("AABB size is negative, this is not supported. Use AABB.abs() to get an AABB with a positive size.");
}
#endif
if (p_point.x < position.x) {
return false;
}
if (p_point.y < position.y) {
return false;
}
if (p_point.z < position.z) {
return false;
}
if (p_point.x > position.x + size.x) {
return false;
}
if (p_point.y > position.y + size.y) {
return false;
}
if (p_point.z > position.z + size.z) {
return false;
}
return true;
}
inline void AABB::expand_to(const Vector3 &p_vector) {
#ifdef MATH_CHECKS
if (unlikely(size.x < 0 || size.y < 0 || size.z < 0)) {
ERR_PRINT("AABB size is negative, this is not supported. Use AABB.abs() to get an AABB with a positive size.");
}
#endif
Vector3 begin = position;
Vector3 end = position + size;
if (p_vector.x < begin.x) {
begin.x = p_vector.x;
}
if (p_vector.y < begin.y) {
begin.y = p_vector.y;
}
if (p_vector.z < begin.z) {
begin.z = p_vector.z;
}
if (p_vector.x > end.x) {
end.x = p_vector.x;
}
if (p_vector.y > end.y) {
end.y = p_vector.y;
}
if (p_vector.z > end.z) {
end.z = p_vector.z;
}
position = begin;
size = end - begin;
}
void AABB::project_range_in_plane(const Plane &p_plane, real_t &r_min, real_t &r_max) const {
Vector3 half_extents(size.x * 0.5f, size.y * 0.5f, size.z * 0.5f);
Vector3 center(position.x + half_extents.x, position.y + half_extents.y, position.z + half_extents.z);
real_t length = p_plane.normal.abs().dot(half_extents);
real_t distance = p_plane.distance_to(center);
r_min = distance - length;
r_max = distance + length;
}
inline real_t AABB::get_longest_axis_size() const {
real_t max_size = size.x;
if (size.y > max_size) {
max_size = size.y;
}
if (size.z > max_size) {
max_size = size.z;
}
return max_size;
}
inline real_t AABB::get_shortest_axis_size() const {
real_t max_size = size.x;
if (size.y < max_size) {
max_size = size.y;
}
if (size.z < max_size) {
max_size = size.z;
}
return max_size;
}
bool AABB::smits_intersect_ray(const Vector3 &p_from, const Vector3 &p_dir, real_t t0, real_t t1) const {
#ifdef MATH_CHECKS
if (unlikely(size.x < 0 || size.y < 0 || size.z < 0)) {
ERR_PRINT("AABB size is negative, this is not supported. Use AABB.abs() to get an AABB with a positive size.");
}
#endif
real_t divx = 1.0f / p_dir.x;
real_t divy = 1.0f / p_dir.y;
real_t divz = 1.0f / p_dir.z;
Vector3 upbound = position + size;
real_t tmin, tmax, tymin, tymax, tzmin, tzmax;
if (p_dir.x >= 0) {
tmin = (position.x - p_from.x) * divx;
tmax = (upbound.x - p_from.x) * divx;
} else {
tmin = (upbound.x - p_from.x) * divx;
tmax = (position.x - p_from.x) * divx;
}
if (p_dir.y >= 0) {
tymin = (position.y - p_from.y) * divy;
tymax = (upbound.y - p_from.y) * divy;
} else {
tymin = (upbound.y - p_from.y) * divy;
tymax = (position.y - p_from.y) * divy;
}
if ((tmin > tymax) || (tymin > tmax)) {
return false;
}
if (tymin > tmin) {
tmin = tymin;
}
if (tymax < tmax) {
tmax = tymax;
}
if (p_dir.z >= 0) {
tzmin = (position.z - p_from.z) * divz;
tzmax = (upbound.z - p_from.z) * divz;
} else {
tzmin = (upbound.z - p_from.z) * divz;
tzmax = (position.z - p_from.z) * divz;
}
if ((tmin > tzmax) || (tzmin > tmax)) {
return false;
}
if (tzmin > tmin) {
tmin = tzmin;
}
if (tzmax < tmax) {
tmax = tzmax;
}
return ((tmin < t1) && (tmax > t0));
}
void AABB::grow_by(real_t p_amount) {
position.x -= p_amount;
position.y -= p_amount;
position.z -= p_amount;
size.x += 2.0f * p_amount;
size.y += 2.0f * p_amount;
size.z += 2.0f * p_amount;
}
void AABB::quantize(real_t p_unit) {
size += position;
position.x -= Math::fposmodp(position.x, p_unit);
position.y -= Math::fposmodp(position.y, p_unit);
position.z -= Math::fposmodp(position.z, p_unit);
size.x -= Math::fposmodp(size.x, p_unit);
size.y -= Math::fposmodp(size.y, p_unit);
size.z -= Math::fposmodp(size.z, p_unit);
size.x += p_unit;
size.y += p_unit;
size.z += p_unit;
size -= position;
}
AABB AABB::quantized(real_t p_unit) const {
AABB ret = *this;
ret.quantize(p_unit);
return ret;
}
} // namespace godot
#endif // GODOT_AABB_HPP

View File

@@ -0,0 +1,50 @@
/**************************************************************************/
/* array_helpers.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. */
/**************************************************************************/
namespace godot {
namespace helpers {
template <typename T, typename ValueT>
T append_all(T appendable, ValueT value) {
appendable.append(value);
return appendable;
}
template <typename T, typename ValueT, typename... Args>
T append_all(T appendable, ValueT value, Args... args) {
appendable.append(value);
return append_all(appendable, args...);
}
template <typename T>
T append_all(T appendable) {
return appendable;
}
} // namespace helpers
} // namespace godot

View File

@@ -0,0 +1,318 @@
/**************************************************************************/
/* basis.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_BASIS_HPP
#define GODOT_BASIS_HPP
#include <godot_cpp/classes/global_constants.hpp>
#include <godot_cpp/variant/quaternion.hpp>
#include <godot_cpp/variant/vector3.hpp>
namespace godot {
struct _NO_DISCARD_ Basis {
Vector3 rows[3] = {
Vector3(1, 0, 0),
Vector3(0, 1, 0),
Vector3(0, 0, 1)
};
_FORCE_INLINE_ const Vector3 &operator[](int axis) const {
return rows[axis];
}
_FORCE_INLINE_ Vector3 &operator[](int axis) {
return rows[axis];
}
void invert();
void transpose();
Basis inverse() const;
Basis transposed() const;
_FORCE_INLINE_ real_t determinant() const;
void from_z(const Vector3 &p_z);
void rotate(const Vector3 &p_axis, real_t p_angle);
Basis rotated(const Vector3 &p_axis, real_t p_angle) const;
void rotate_local(const Vector3 &p_axis, real_t p_angle);
Basis rotated_local(const Vector3 &p_axis, real_t p_angle) const;
void rotate(const Vector3 &p_euler, EulerOrder p_order = EULER_ORDER_YXZ);
Basis rotated(const Vector3 &p_euler, EulerOrder p_order = EULER_ORDER_YXZ) const;
void rotate(const Quaternion &p_quaternion);
Basis rotated(const Quaternion &p_quaternion) const;
Vector3 get_euler_normalized(EulerOrder p_order = EULER_ORDER_YXZ) const;
void get_rotation_axis_angle(Vector3 &p_axis, real_t &p_angle) const;
void get_rotation_axis_angle_local(Vector3 &p_axis, real_t &p_angle) const;
Quaternion get_rotation_quaternion() const;
void rotate_to_align(Vector3 p_start_direction, Vector3 p_end_direction);
Vector3 rotref_posscale_decomposition(Basis &rotref) const;
Vector3 get_euler(EulerOrder p_order = EULER_ORDER_YXZ) const;
void set_euler(const Vector3 &p_euler, EulerOrder p_order = EULER_ORDER_YXZ);
static Basis from_euler(const Vector3 &p_euler, EulerOrder p_order = EULER_ORDER_YXZ) {
Basis b;
b.set_euler(p_euler, p_order);
return b;
}
Quaternion get_quaternion() const;
void set_quaternion(const Quaternion &p_quaternion);
void get_axis_angle(Vector3 &r_axis, real_t &r_angle) const;
void set_axis_angle(const Vector3 &p_axis, real_t p_angle);
void scale(const Vector3 &p_scale);
Basis scaled(const Vector3 &p_scale) const;
void scale_local(const Vector3 &p_scale);
Basis scaled_local(const Vector3 &p_scale) const;
void scale_orthogonal(const Vector3 &p_scale);
Basis scaled_orthogonal(const Vector3 &p_scale) const;
void make_scale_uniform();
float get_uniform_scale() const;
Vector3 get_scale() const;
Vector3 get_scale_abs() const;
Vector3 get_scale_local() const;
void set_axis_angle_scale(const Vector3 &p_axis, real_t p_angle, const Vector3 &p_scale);
void set_euler_scale(const Vector3 &p_euler, const Vector3 &p_scale, EulerOrder p_order = EULER_ORDER_YXZ);
void set_quaternion_scale(const Quaternion &p_quaternion, const Vector3 &p_scale);
// transposed dot products
_FORCE_INLINE_ real_t tdotx(const Vector3 &v) const {
return rows[0][0] * v[0] + rows[1][0] * v[1] + rows[2][0] * v[2];
}
_FORCE_INLINE_ real_t tdoty(const Vector3 &v) const {
return rows[0][1] * v[0] + rows[1][1] * v[1] + rows[2][1] * v[2];
}
_FORCE_INLINE_ real_t tdotz(const Vector3 &v) const {
return rows[0][2] * v[0] + rows[1][2] * v[1] + rows[2][2] * v[2];
}
bool is_equal_approx(const Basis &p_basis) const;
bool operator==(const Basis &p_matrix) const;
bool operator!=(const Basis &p_matrix) const;
_FORCE_INLINE_ Vector3 xform(const Vector3 &p_vector) const;
_FORCE_INLINE_ Vector3 xform_inv(const Vector3 &p_vector) const;
_FORCE_INLINE_ void operator*=(const Basis &p_matrix);
_FORCE_INLINE_ Basis operator*(const Basis &p_matrix) const;
_FORCE_INLINE_ void operator+=(const Basis &p_matrix);
_FORCE_INLINE_ Basis operator+(const Basis &p_matrix) const;
_FORCE_INLINE_ void operator-=(const Basis &p_matrix);
_FORCE_INLINE_ Basis operator-(const Basis &p_matrix) const;
_FORCE_INLINE_ void operator*=(const real_t p_val);
_FORCE_INLINE_ Basis operator*(const real_t p_val) const;
bool is_orthogonal() const;
bool is_diagonal() const;
bool is_rotation() const;
Basis lerp(const Basis &p_to, const real_t &p_weight) const;
Basis slerp(const Basis &p_to, const real_t &p_weight) const;
void rotate_sh(real_t *p_values);
operator String() const;
/* create / set */
_FORCE_INLINE_ void set(real_t xx, real_t xy, real_t xz, real_t yx, real_t yy, real_t yz, real_t zx, real_t zy, real_t zz) {
rows[0][0] = xx;
rows[0][1] = xy;
rows[0][2] = xz;
rows[1][0] = yx;
rows[1][1] = yy;
rows[1][2] = yz;
rows[2][0] = zx;
rows[2][1] = zy;
rows[2][2] = zz;
}
_FORCE_INLINE_ void set_columns(const Vector3 &p_x, const Vector3 &p_y, const Vector3 &p_z) {
set_column(0, p_x);
set_column(1, p_y);
set_column(2, p_z);
}
_FORCE_INLINE_ Vector3 get_column(int p_index) const {
// Get actual basis axis column (we store transposed as rows for performance).
return Vector3(rows[0][p_index], rows[1][p_index], rows[2][p_index]);
}
_FORCE_INLINE_ void set_column(int p_index, const Vector3 &p_value) {
// Set actual basis axis column (we store transposed as rows for performance).
rows[0][p_index] = p_value.x;
rows[1][p_index] = p_value.y;
rows[2][p_index] = p_value.z;
}
_FORCE_INLINE_ Vector3 get_main_diagonal() const {
return Vector3(rows[0][0], rows[1][1], rows[2][2]);
}
_FORCE_INLINE_ void set_zero() {
rows[0].zero();
rows[1].zero();
rows[2].zero();
}
_FORCE_INLINE_ Basis transpose_xform(const Basis &m) const {
return Basis(
rows[0].x * m[0].x + rows[1].x * m[1].x + rows[2].x * m[2].x,
rows[0].x * m[0].y + rows[1].x * m[1].y + rows[2].x * m[2].y,
rows[0].x * m[0].z + rows[1].x * m[1].z + rows[2].x * m[2].z,
rows[0].y * m[0].x + rows[1].y * m[1].x + rows[2].y * m[2].x,
rows[0].y * m[0].y + rows[1].y * m[1].y + rows[2].y * m[2].y,
rows[0].y * m[0].z + rows[1].y * m[1].z + rows[2].y * m[2].z,
rows[0].z * m[0].x + rows[1].z * m[1].x + rows[2].z * m[2].x,
rows[0].z * m[0].y + rows[1].z * m[1].y + rows[2].z * m[2].y,
rows[0].z * m[0].z + rows[1].z * m[1].z + rows[2].z * m[2].z);
}
Basis(real_t xx, real_t xy, real_t xz, real_t yx, real_t yy, real_t yz, real_t zx, real_t zy, real_t zz) {
set(xx, xy, xz, yx, yy, yz, zx, zy, zz);
}
void orthonormalize();
Basis orthonormalized() const;
void orthogonalize();
Basis orthogonalized() const;
#ifdef MATH_CHECKS
bool is_symmetric() const;
#endif
Basis diagonalize();
operator Quaternion() const { return get_quaternion(); }
static Basis looking_at(const Vector3 &p_target, const Vector3 &p_up = Vector3(0, 1, 0));
Basis(const Quaternion &p_quaternion) { set_quaternion(p_quaternion); }
Basis(const Quaternion &p_quaternion, const Vector3 &p_scale) { set_quaternion_scale(p_quaternion, p_scale); }
Basis(const Vector3 &p_axis, real_t p_angle) { set_axis_angle(p_axis, p_angle); }
Basis(const Vector3 &p_axis, real_t p_angle, const Vector3 &p_scale) { set_axis_angle_scale(p_axis, p_angle, p_scale); }
static Basis from_scale(const Vector3 &p_scale);
_FORCE_INLINE_ Basis(const Vector3 &p_x_axis, const Vector3 &p_y_axis, const Vector3 &p_z_axis) {
set_columns(p_x_axis, p_y_axis, p_z_axis);
}
_FORCE_INLINE_ Basis() {}
private:
// Helper method.
void _set_diagonal(const Vector3 &p_diag);
};
_FORCE_INLINE_ void Basis::operator*=(const Basis &p_matrix) {
set(
p_matrix.tdotx(rows[0]), p_matrix.tdoty(rows[0]), p_matrix.tdotz(rows[0]),
p_matrix.tdotx(rows[1]), p_matrix.tdoty(rows[1]), p_matrix.tdotz(rows[1]),
p_matrix.tdotx(rows[2]), p_matrix.tdoty(rows[2]), p_matrix.tdotz(rows[2]));
}
_FORCE_INLINE_ Basis Basis::operator*(const Basis &p_matrix) const {
return Basis(
p_matrix.tdotx(rows[0]), p_matrix.tdoty(rows[0]), p_matrix.tdotz(rows[0]),
p_matrix.tdotx(rows[1]), p_matrix.tdoty(rows[1]), p_matrix.tdotz(rows[1]),
p_matrix.tdotx(rows[2]), p_matrix.tdoty(rows[2]), p_matrix.tdotz(rows[2]));
}
_FORCE_INLINE_ void Basis::operator+=(const Basis &p_matrix) {
rows[0] += p_matrix.rows[0];
rows[1] += p_matrix.rows[1];
rows[2] += p_matrix.rows[2];
}
_FORCE_INLINE_ Basis Basis::operator+(const Basis &p_matrix) const {
Basis ret(*this);
ret += p_matrix;
return ret;
}
_FORCE_INLINE_ void Basis::operator-=(const Basis &p_matrix) {
rows[0] -= p_matrix.rows[0];
rows[1] -= p_matrix.rows[1];
rows[2] -= p_matrix.rows[2];
}
_FORCE_INLINE_ Basis Basis::operator-(const Basis &p_matrix) const {
Basis ret(*this);
ret -= p_matrix;
return ret;
}
_FORCE_INLINE_ void Basis::operator*=(const real_t p_val) {
rows[0] *= p_val;
rows[1] *= p_val;
rows[2] *= p_val;
}
_FORCE_INLINE_ Basis Basis::operator*(const real_t p_val) const {
Basis ret(*this);
ret *= p_val;
return ret;
}
Vector3 Basis::xform(const Vector3 &p_vector) const {
return Vector3(
rows[0].dot(p_vector),
rows[1].dot(p_vector),
rows[2].dot(p_vector));
}
Vector3 Basis::xform_inv(const Vector3 &p_vector) const {
return Vector3(
(rows[0][0] * p_vector.x) + (rows[1][0] * p_vector.y) + (rows[2][0] * p_vector.z),
(rows[0][1] * p_vector.x) + (rows[1][1] * p_vector.y) + (rows[2][1] * p_vector.z),
(rows[0][2] * p_vector.x) + (rows[1][2] * p_vector.y) + (rows[2][2] * p_vector.z));
}
real_t Basis::determinant() const {
return rows[0][0] * (rows[1][1] * rows[2][2] - rows[2][1] * rows[1][2]) -
rows[1][0] * (rows[0][1] * rows[2][2] - rows[2][1] * rows[0][2]) +
rows[2][0] * (rows[0][1] * rows[1][2] - rows[1][1] * rows[0][2]);
}
} // namespace godot
#endif // GODOT_BASIS_HPP

View File

@@ -0,0 +1,64 @@
/**************************************************************************/
/* callable_custom.hpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#ifndef GODOT_CALLABLE_CUSTOM_HPP
#define GODOT_CALLABLE_CUSTOM_HPP
#include <godot_cpp/core/object_id.hpp>
#include <godot_cpp/variant/string_name.hpp>
namespace godot {
class Object;
class CallableCustomBase {
public:
virtual ObjectID get_object() const = 0;
virtual void call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, GDExtensionCallError &r_call_error) const = 0;
virtual ~CallableCustomBase() {}
};
class CallableCustom : public CallableCustomBase {
public:
typedef bool (*CompareEqualFunc)(const CallableCustom *p_a, const CallableCustom *p_b);
typedef bool (*CompareLessFunc)(const CallableCustom *p_a, const CallableCustom *p_b);
virtual uint32_t hash() const = 0;
virtual String get_as_text() const = 0;
virtual CompareEqualFunc get_compare_equal_func() const = 0;
virtual CompareLessFunc get_compare_less_func() const = 0;
virtual bool is_valid() const;
virtual ObjectID get_object() const = 0;
virtual void call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, GDExtensionCallError &r_call_error) const = 0;
};
} // namespace godot
#endif // GODOT_CALLABLE_CUSTOM_HPP

View File

@@ -0,0 +1,248 @@
/**************************************************************************/
/* callable_method_pointer.hpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#ifndef GODOT_CALLABLE_METHOD_POINTER_HPP
#define GODOT_CALLABLE_METHOD_POINTER_HPP
#include <godot_cpp/core/binder_common.hpp>
#include <godot_cpp/variant/variant.hpp>
namespace godot {
class CallableCustomMethodPointerBase : public CallableCustomBase {
uint32_t *comp_ptr = nullptr;
uint32_t comp_size;
uint32_t h;
protected:
void _setup(uint32_t *p_base_ptr, uint32_t p_ptr_size);
public:
_FORCE_INLINE_ const uint32_t *get_comp_ptr() const { return comp_ptr; }
_FORCE_INLINE_ uint32_t get_comp_size() const { return comp_size; }
_FORCE_INLINE_ uint32_t get_hash() const { return h; }
};
namespace internal {
Callable create_callable_from_ccmp(CallableCustomMethodPointerBase *p_callable_method_pointer);
} // namespace internal
//
// No return value.
//
template <class T, class... P>
class CallableCustomMethodPointer : public CallableCustomMethodPointerBase {
struct Data {
T *instance;
void (T::*method)(P...);
} data;
static_assert(sizeof(Data) % 4 == 0);
public:
virtual ObjectID get_object() const override {
return ObjectID(data.instance->get_instance_id());
}
virtual void call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, GDExtensionCallError &r_call_error) const override {
call_with_variant_args(data.instance, data.method, p_arguments, p_argcount, r_call_error);
}
CallableCustomMethodPointer(T *p_instance, void (T::*p_method)(P...)) {
memset(&data, 0, sizeof(Data));
data.instance = p_instance;
data.method = p_method;
_setup((uint32_t *)&data, sizeof(Data));
}
};
template <class T, class... P>
Callable create_custom_callable_function_pointer(T *p_instance, void (T::*p_method)(P...)) {
typedef CallableCustomMethodPointer<T, P...> CCMP;
CCMP *ccmp = memnew(CCMP(p_instance, p_method));
return ::godot::internal::create_callable_from_ccmp(ccmp);
}
//
// With return value.
//
template <class T, class R, class... P>
class CallableCustomMethodPointerRet : public CallableCustomMethodPointerBase {
struct Data {
T *instance;
R(T::*method)
(P...);
} data;
static_assert(sizeof(Data) % 4 == 0);
public:
virtual ObjectID get_object() const override {
return ObjectID(data.instance->get_instance_id());
}
virtual void call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, GDExtensionCallError &r_call_error) const override {
call_with_variant_args_ret(data.instance, data.method, p_arguments, p_argcount, r_return_value, r_call_error);
}
CallableCustomMethodPointerRet(T *p_instance, R (T::*p_method)(P...)) {
memset(&data, 0, sizeof(Data));
data.instance = p_instance;
data.method = p_method;
_setup((uint32_t *)&data, sizeof(Data));
}
};
template <class T, class R, class... P>
Callable create_custom_callable_function_pointer(T *p_instance, R (T::*p_method)(P...)) {
typedef CallableCustomMethodPointerRet<T, R, P...> CCMP; // Messes with memnew otherwise.
CCMP *ccmp = memnew(CCMP(p_instance, p_method));
return ::godot::internal::create_callable_from_ccmp(ccmp);
}
//
// Const with return value.
//
template <class T, class R, class... P>
class CallableCustomMethodPointerRetC : public CallableCustomMethodPointerBase {
struct Data {
T *instance;
R(T::*method)
(P...) const;
} data;
static_assert(sizeof(Data) % 4 == 0);
public:
virtual ObjectID get_object() const override {
return ObjectID(data.instance->get_instance_id());
}
virtual void call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, GDExtensionCallError &r_call_error) const override {
call_with_variant_args_retc(data.instance, data.method, p_arguments, p_argcount, r_return_value, r_call_error);
}
CallableCustomMethodPointerRetC(const T *p_instance, R (T::*p_method)(P...) const) {
memset(&data, 0, sizeof(Data));
data.instance = const_cast<T *>(p_instance);
data.method = p_method;
_setup((uint32_t *)&data, sizeof(Data));
}
};
template <class T, class R, class... P>
Callable create_custom_callable_function_pointer(const T *p_instance, R (T::*p_method)(P...) const) {
typedef CallableCustomMethodPointerRetC<T, R, P...> CCMP; // Messes with memnew otherwise.
CCMP *ccmp = memnew(CCMP(p_instance, p_method));
return ::godot::internal::create_callable_from_ccmp(ccmp);
}
//
// Static method with no return value.
//
template <class... P>
class CallableCustomStaticMethodPointer : public CallableCustomMethodPointerBase {
struct Data {
void (*method)(P...);
} data;
static_assert(sizeof(Data) % 4 == 0);
public:
virtual ObjectID get_object() const override {
return ObjectID();
}
virtual void call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, GDExtensionCallError &r_call_error) const override {
call_with_variant_args_static_ret(data.method, p_arguments, p_argcount, r_return_value, r_call_error);
r_return_value = Variant();
}
CallableCustomStaticMethodPointer(void (*p_method)(P...)) {
memset(&data, 0, sizeof(Data));
data.method = p_method;
_setup((uint32_t *)&data, sizeof(Data));
}
};
template <class... P>
Callable create_custom_callable_static_function_pointer(void (*p_method)(P...)) {
typedef CallableCustomStaticMethodPointer<P...> CCMP;
CCMP *ccmp = memnew(CCMP(p_method));
return ::godot::internal::create_callable_from_ccmp(ccmp);
}
//
// Static method with return value.
//
template <class R, class... P>
class CallableCustomStaticMethodPointerRet : public CallableCustomMethodPointerBase {
struct Data {
R(*method)
(P...);
} data;
static_assert(sizeof(Data) % 4 == 0);
public:
virtual ObjectID get_object() const override {
return ObjectID();
}
virtual void call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, GDExtensionCallError &r_call_error) const override {
call_with_variant_args_static_ret(data.method, p_arguments, p_argcount, r_return_value, r_call_error);
}
CallableCustomStaticMethodPointerRet(R (*p_method)(P...)) {
memset(&data, 0, sizeof(Data));
data.method = p_method;
_setup((uint32_t *)&data, sizeof(Data));
}
};
template <class R, class... P>
Callable create_custom_callable_static_function_pointer(R (*p_method)(P...)) {
typedef CallableCustomStaticMethodPointerRet<R, P...> CCMP;
CCMP *ccmp = memnew(CCMP(p_method));
return ::godot::internal::create_callable_from_ccmp(ccmp);
}
//
// The API:
//
#define callable_mp(I, M) ::godot::create_custom_callable_function_pointer(I, M)
#define callable_mp_static(M) ::godot::create_custom_callable_static_function_pointer(M)
} // namespace godot
#endif // GODOT_CALLABLE_METHOD_POINTER_HPP

View File

@@ -0,0 +1,142 @@
/**************************************************************************/
/* char_string.hpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#ifndef GODOT_CHAR_STRING_HPP
#define GODOT_CHAR_STRING_HPP
#include <godot_cpp/templates/cowdata.hpp>
#include <cstddef>
#include <cstdint>
namespace godot {
template <class T>
class CharStringT;
template <class T>
class CharProxy {
template <class TS>
friend class CharStringT;
const int _index;
CowData<T> &_cowdata;
static inline const T _null = 0;
_FORCE_INLINE_ CharProxy(const int &p_index, CowData<T> &p_cowdata) :
_index(p_index),
_cowdata(p_cowdata) {}
public:
_FORCE_INLINE_ CharProxy(const CharProxy<T> &p_other) :
_index(p_other._index),
_cowdata(p_other._cowdata) {}
_FORCE_INLINE_ operator T() const {
if (unlikely(_index == _cowdata.size())) {
return _null;
}
return _cowdata.get(_index);
}
_FORCE_INLINE_ const T *operator&() const {
return _cowdata.ptr() + _index;
}
_FORCE_INLINE_ void operator=(const T &p_other) const {
_cowdata.set(_index, p_other);
}
_FORCE_INLINE_ void operator=(const CharProxy<T> &p_other) const {
_cowdata.set(_index, p_other.operator T());
}
};
template <class T>
class CharStringT {
friend class String;
CowData<T> _cowdata;
static inline const T _null = 0;
public:
_FORCE_INLINE_ T *ptrw() { return _cowdata.ptrw(); }
_FORCE_INLINE_ const T *ptr() const { return _cowdata.ptr(); }
_FORCE_INLINE_ int size() const { return _cowdata.size(); }
Error resize(int p_size) { return _cowdata.resize(p_size); }
_FORCE_INLINE_ 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_ const T &operator[](int p_index) const {
if (unlikely(p_index == _cowdata.size())) {
return _null;
}
return _cowdata.get(p_index);
}
_FORCE_INLINE_ CharProxy<T> operator[](int 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);
int 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);
};
template <>
const char *CharStringT<char>::get_data() const;
template <>
const char16_t *CharStringT<char16_t>::get_data() const;
template <>
const char32_t *CharStringT<char32_t>::get_data() const;
template <>
const wchar_t *CharStringT<wchar_t>::get_data() const;
typedef CharStringT<char> CharString;
typedef CharStringT<char16_t> Char16String;
typedef CharStringT<char32_t> Char32String;
typedef CharStringT<wchar_t> CharWideString;
} // namespace godot
#endif // GODOT_CHAR_STRING_HPP

View File

@@ -0,0 +1,90 @@
/**************************************************************************/
/* char_utils.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_CHAR_UTILS_HPP
#define GODOT_CHAR_UTILS_HPP
static _FORCE_INLINE_ bool is_ascii_upper_case(char32_t c) {
return (c >= 'A' && c <= 'Z');
}
static _FORCE_INLINE_ bool is_ascii_lower_case(char32_t c) {
return (c >= 'a' && c <= 'z');
}
static _FORCE_INLINE_ bool is_digit(char32_t c) {
return (c >= '0' && c <= '9');
}
static _FORCE_INLINE_ bool is_hex_digit(char32_t c) {
return (is_digit(c) || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F'));
}
static _FORCE_INLINE_ bool is_binary_digit(char32_t c) {
return (c == '0' || c == '1');
}
static _FORCE_INLINE_ bool is_ascii_char(char32_t c) {
return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z');
}
static _FORCE_INLINE_ bool is_ascii_alphanumeric_char(char32_t c) {
return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9');
}
static _FORCE_INLINE_ bool is_ascii_identifier_char(char32_t c) {
return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '_';
}
static _FORCE_INLINE_ bool is_symbol(char32_t c) {
return c != '_' && ((c >= '!' && c <= '/') || (c >= ':' && c <= '@') || (c >= '[' && c <= '`') || (c >= '{' && c <= '~') || c == '\t' || c == ' ');
}
static _FORCE_INLINE_ bool is_control(char32_t p_char) {
return (p_char <= 0x001f) || (p_char >= 0x007f && p_char <= 0x009f);
}
static _FORCE_INLINE_ bool is_whitespace(char32_t p_char) {
return (p_char == ' ') || (p_char == 0x00a0) || (p_char == 0x1680) || (p_char >= 0x2000 && p_char <= 0x200a) || (p_char == 0x202f) || (p_char == 0x205f) || (p_char == 0x3000) || (p_char == 0x2028) || (p_char == 0x2029) || (p_char >= 0x0009 && p_char <= 0x000d) || (p_char == 0x0085);
}
static _FORCE_INLINE_ bool is_linebreak(char32_t p_char) {
return (p_char >= 0x000a && p_char <= 0x000d) || (p_char == 0x0085) || (p_char == 0x2028) || (p_char == 0x2029);
}
static _FORCE_INLINE_ bool is_punct(char32_t p_char) {
return (p_char >= ' ' && p_char <= '/') || (p_char >= ':' && p_char <= '@') || (p_char >= '[' && p_char <= '^') || (p_char == '`') || (p_char >= '{' && p_char <= '~') || (p_char >= 0x2000 && p_char <= 0x206f) || (p_char >= 0x3000 && p_char <= 0x303f);
}
static _FORCE_INLINE_ bool is_underscore(char32_t p_char) {
return (p_char == '_');
}
#endif // GODOT_CHAR_UTILS_HPP

View File

@@ -0,0 +1,289 @@
/**************************************************************************/
/* color.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_COLOR_HPP
#define GODOT_COLOR_HPP
#include <godot_cpp/core/math.hpp>
namespace godot {
class String;
struct _NO_DISCARD_ Color {
union {
struct {
float r;
float g;
float b;
float a;
};
float components[4] = { 0, 0, 0, 1.0 };
};
uint32_t to_rgba32() const;
uint32_t to_argb32() const;
uint32_t to_abgr32() const;
uint64_t to_rgba64() const;
uint64_t to_argb64() const;
uint64_t to_abgr64() const;
String to_html(bool p_alpha = true) const;
float get_h() const;
float get_s() const;
float get_v() const;
void set_hsv(float p_h, float p_s, float p_v, float p_alpha = 1.0f);
_FORCE_INLINE_ float &operator[](int p_idx) {
return components[p_idx];
}
_FORCE_INLINE_ const float &operator[](int p_idx) const {
return components[p_idx];
}
bool operator==(const Color &p_color) const {
return (r == p_color.r && g == p_color.g && b == p_color.b && a == p_color.a);
}
bool operator!=(const Color &p_color) const {
return (r != p_color.r || g != p_color.g || b != p_color.b || a != p_color.a);
}
Color operator+(const Color &p_color) const;
void operator+=(const Color &p_color);
Color operator-() const;
Color operator-(const Color &p_color) const;
void operator-=(const Color &p_color);
Color operator*(const Color &p_color) const;
Color operator*(float p_scalar) const;
void operator*=(const Color &p_color);
void operator*=(float p_scalar);
Color operator/(const Color &p_color) const;
Color operator/(float p_scalar) const;
void operator/=(const Color &p_color);
void operator/=(float p_scalar);
bool is_equal_approx(const Color &p_color) const;
Color clamp(const Color &p_min = Color(0, 0, 0, 0), const Color &p_max = Color(1, 1, 1, 1)) const;
void invert();
Color inverted() const;
_FORCE_INLINE_ float get_luminance() const {
return 0.2126f * r + 0.7152f * g + 0.0722f * b;
}
_FORCE_INLINE_ Color lerp(const Color &p_to, float p_weight) const {
Color res = *this;
res.r += (p_weight * (p_to.r - r));
res.g += (p_weight * (p_to.g - g));
res.b += (p_weight * (p_to.b - b));
res.a += (p_weight * (p_to.a - a));
return res;
}
_FORCE_INLINE_ Color darkened(float p_amount) const {
Color res = *this;
res.r = res.r * (1.0f - p_amount);
res.g = res.g * (1.0f - p_amount);
res.b = res.b * (1.0f - p_amount);
return res;
}
_FORCE_INLINE_ Color lightened(float p_amount) const {
Color res = *this;
res.r = res.r + (1.0f - res.r) * p_amount;
res.g = res.g + (1.0f - res.g) * p_amount;
res.b = res.b + (1.0f - res.b) * p_amount;
return res;
}
_FORCE_INLINE_ uint32_t to_rgbe9995() const {
const float pow2to9 = 512.0f;
const float B = 15.0f;
const float N = 9.0f;
float sharedexp = 65408.000f; // Result of: ((pow2to9 - 1.0f) / pow2to9) * powf(2.0f, 31.0f - 15.0f)
float cRed = MAX(0.0f, MIN(sharedexp, r));
float cGreen = MAX(0.0f, MIN(sharedexp, g));
float cBlue = MAX(0.0f, MIN(sharedexp, b));
float cMax = MAX(cRed, MAX(cGreen, cBlue));
float expp = MAX(-B - 1.0f, floor(Math::log(cMax) / (real_t)Math_LN2)) + 1.0f + B;
float sMax = (float)floor((cMax / Math::pow(2.0f, expp - B - N)) + 0.5f);
float exps = expp + 1.0f;
if (0.0f <= sMax && sMax < pow2to9) {
exps = expp;
}
float sRed = Math::floor((cRed / pow(2.0f, exps - B - N)) + 0.5f);
float sGreen = Math::floor((cGreen / pow(2.0f, exps - B - N)) + 0.5f);
float sBlue = Math::floor((cBlue / pow(2.0f, exps - B - N)) + 0.5f);
return (uint32_t(Math::fast_ftoi(sRed)) & 0x1FF) | ((uint32_t(Math::fast_ftoi(sGreen)) & 0x1FF) << 9) | ((uint32_t(Math::fast_ftoi(sBlue)) & 0x1FF) << 18) | ((uint32_t(Math::fast_ftoi(exps)) & 0x1F) << 27);
}
_FORCE_INLINE_ Color blend(const Color &p_over) const {
Color res;
float sa = 1.0f - p_over.a;
res.a = a * sa + p_over.a;
if (res.a == 0) {
return Color(0, 0, 0, 0);
} else {
res.r = (r * a * sa + p_over.r * p_over.a) / res.a;
res.g = (g * a * sa + p_over.g * p_over.a) / res.a;
res.b = (b * a * sa + p_over.b * p_over.a) / res.a;
}
return res;
}
_FORCE_INLINE_ Color srgb_to_linear() const {
return Color(
r < 0.04045f ? r * (1.0f / 12.92f) : Math::pow((r + 0.055f) * (float)(1.0 / (1.0 + 0.055)), 2.4f),
g < 0.04045f ? g * (1.0f / 12.92f) : Math::pow((g + 0.055f) * (float)(1.0 / (1.0 + 0.055)), 2.4f),
b < 0.04045f ? b * (1.0f / 12.92f) : Math::pow((b + 0.055f) * (float)(1.0 / (1.0 + 0.055)), 2.4f),
a);
}
_FORCE_INLINE_ Color linear_to_srgb() const {
return Color(
r < 0.0031308f ? 12.92f * r : (1.0f + 0.055f) * Math::pow(r, 1.0f / 2.4f) - 0.055f,
g < 0.0031308f ? 12.92f * g : (1.0f + 0.055f) * Math::pow(g, 1.0f / 2.4f) - 0.055f,
b < 0.0031308f ? 12.92f * b : (1.0f + 0.055f) * Math::pow(b, 1.0f / 2.4f) - 0.055f, a);
}
static Color hex(uint32_t p_hex);
static Color hex64(uint64_t p_hex);
static Color html(const String &p_rgba);
static bool html_is_valid(const String &p_color);
static Color named(const String &p_name);
static Color named(const String &p_name, const Color &p_default);
static int find_named_color(const String &p_name);
static int get_named_color_count();
static String get_named_color_name(int p_idx);
static Color get_named_color(int p_idx);
static Color from_string(const String &p_string, const Color &p_default);
static Color from_hsv(float p_h, float p_s, float p_v, float p_alpha = 1.0f);
static Color from_rgbe9995(uint32_t p_rgbe);
_FORCE_INLINE_ bool operator<(const Color &p_color) const; // Used in set keys.
operator String() const;
// For the binder.
_FORCE_INLINE_ void set_r8(int32_t r8) { r = (CLAMP(r8, 0, 255) / 255.0f); }
_FORCE_INLINE_ int32_t get_r8() const { return int32_t(CLAMP(Math::round(r * 255.0f), 0.0f, 255.0f)); }
_FORCE_INLINE_ void set_g8(int32_t g8) { g = (CLAMP(g8, 0, 255) / 255.0f); }
_FORCE_INLINE_ int32_t get_g8() const { return int32_t(CLAMP(Math::round(g * 255.0f), 0.0f, 255.0f)); }
_FORCE_INLINE_ void set_b8(int32_t b8) { b = (CLAMP(b8, 0, 255) / 255.0f); }
_FORCE_INLINE_ int32_t get_b8() const { return int32_t(CLAMP(Math::round(b * 255.0f), 0.0f, 255.0f)); }
_FORCE_INLINE_ void set_a8(int32_t a8) { a = (CLAMP(a8, 0, 255) / 255.0f); }
_FORCE_INLINE_ int32_t get_a8() const { return int32_t(CLAMP(Math::round(a * 255.0f), 0.0f, 255.0f)); }
_FORCE_INLINE_ void set_h(float p_h) { set_hsv(p_h, get_s(), get_v(), a); }
_FORCE_INLINE_ void set_s(float p_s) { set_hsv(get_h(), p_s, get_v(), a); }
_FORCE_INLINE_ void set_v(float p_v) { set_hsv(get_h(), get_s(), p_v, a); }
_FORCE_INLINE_ Color() {}
/**
* RGBA construct parameters.
* Alpha is not optional as otherwise we can't bind the RGB version for scripting.
*/
_FORCE_INLINE_ Color(float p_r, float p_g, float p_b, float p_a) {
r = p_r;
g = p_g;
b = p_b;
a = p_a;
}
/**
* RGB construct parameters.
*/
_FORCE_INLINE_ Color(float p_r, float p_g, float p_b) {
r = p_r;
g = p_g;
b = p_b;
a = 1.0f;
}
/**
* Construct a Color from another Color, but with the specified alpha value.
*/
_FORCE_INLINE_ Color(const Color &p_c, float p_a) {
r = p_c.r;
g = p_c.g;
b = p_c.b;
a = p_a;
}
Color(const String &p_code) {
if (html_is_valid(p_code)) {
*this = html(p_code);
} else {
*this = named(p_code);
}
}
Color(const String &p_code, float p_a) {
*this = Color(p_code);
a = p_a;
}
};
bool Color::operator<(const Color &p_color) const {
if (r == p_color.r) {
if (g == p_color.g) {
if (b == p_color.b) {
return (a < p_color.a);
} else {
return (b < p_color.b);
}
} else {
return g < p_color.g;
}
} else {
return r < p_color.r;
}
}
_FORCE_INLINE_ Color operator*(float p_scalar, const Color &p_color) {
return p_color * p_scalar;
}
} // namespace godot
#endif // GODOT_COLOR_HPP

View File

@@ -0,0 +1,191 @@
/**************************************************************************/
/* color_names.inc.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. */
/**************************************************************************/
namespace godot {
// Names from https://en.wikipedia.org/wiki/X11_color_names
// Keep these in sync with the engine (both in core and in C#)
struct NamedColor {
const char *name;
Color color;
};
static NamedColor named_colors[] = {
{ "ALICE_BLUE", Color::hex(0xF0F8FFFF) },
{ "ANTIQUE_WHITE", Color::hex(0xFAEBD7FF) },
{ "AQUA", Color::hex(0x00FFFFFF) },
{ "AQUAMARINE", Color::hex(0x7FFFD4FF) },
{ "AZURE", Color::hex(0xF0FFFFFF) },
{ "BEIGE", Color::hex(0xF5F5DCFF) },
{ "BISQUE", Color::hex(0xFFE4C4FF) },
{ "BLACK", Color::hex(0x000000FF) },
{ "BLANCHED_ALMOND", Color::hex(0xFFEBCDFF) },
{ "BLUE", Color::hex(0x0000FFFF) },
{ "BLUE_VIOLET", Color::hex(0x8A2BE2FF) },
{ "BROWN", Color::hex(0xA52A2AFF) },
{ "BURLYWOOD", Color::hex(0xDEB887FF) },
{ "CADET_BLUE", Color::hex(0x5F9EA0FF) },
{ "CHARTREUSE", Color::hex(0x7FFF00FF) },
{ "CHOCOLATE", Color::hex(0xD2691EFF) },
{ "CORAL", Color::hex(0xFF7F50FF) },
{ "CORNFLOWER_BLUE", Color::hex(0x6495EDFF) },
{ "CORNSILK", Color::hex(0xFFF8DCFF) },
{ "CRIMSON", Color::hex(0xDC143CFF) },
{ "CYAN", Color::hex(0x00FFFFFF) },
{ "DARK_BLUE", Color::hex(0x00008BFF) },
{ "DARK_CYAN", Color::hex(0x008B8BFF) },
{ "DARK_GOLDENROD", Color::hex(0xB8860BFF) },
{ "DARK_GRAY", Color::hex(0xA9A9A9FF) },
{ "DARK_GREEN", Color::hex(0x006400FF) },
{ "DARK_KHAKI", Color::hex(0xBDB76BFF) },
{ "DARK_MAGENTA", Color::hex(0x8B008BFF) },
{ "DARK_OLIVE_GREEN", Color::hex(0x556B2FFF) },
{ "DARK_ORANGE", Color::hex(0xFF8C00FF) },
{ "DARK_ORCHID", Color::hex(0x9932CCFF) },
{ "DARK_RED", Color::hex(0x8B0000FF) },
{ "DARK_SALMON", Color::hex(0xE9967AFF) },
{ "DARK_SEA_GREEN", Color::hex(0x8FBC8FFF) },
{ "DARK_SLATE_BLUE", Color::hex(0x483D8BFF) },
{ "DARK_SLATE_GRAY", Color::hex(0x2F4F4FFF) },
{ "DARK_TURQUOISE", Color::hex(0x00CED1FF) },
{ "DARK_VIOLET", Color::hex(0x9400D3FF) },
{ "DEEP_PINK", Color::hex(0xFF1493FF) },
{ "DEEP_SKY_BLUE", Color::hex(0x00BFFFFF) },
{ "DIM_GRAY", Color::hex(0x696969FF) },
{ "DODGER_BLUE", Color::hex(0x1E90FFFF) },
{ "FIREBRICK", Color::hex(0xB22222FF) },
{ "FLORAL_WHITE", Color::hex(0xFFFAF0FF) },
{ "FOREST_GREEN", Color::hex(0x228B22FF) },
{ "FUCHSIA", Color::hex(0xFF00FFFF) },
{ "GAINSBORO", Color::hex(0xDCDCDCFF) },
{ "GHOST_WHITE", Color::hex(0xF8F8FFFF) },
{ "GOLD", Color::hex(0xFFD700FF) },
{ "GOLDENROD", Color::hex(0xDAA520FF) },
{ "GRAY", Color::hex(0xBEBEBEFF) },
{ "GREEN", Color::hex(0x00FF00FF) },
{ "GREEN_YELLOW", Color::hex(0xADFF2FFF) },
{ "HONEYDEW", Color::hex(0xF0FFF0FF) },
{ "HOT_PINK", Color::hex(0xFF69B4FF) },
{ "INDIAN_RED", Color::hex(0xCD5C5CFF) },
{ "INDIGO", Color::hex(0x4B0082FF) },
{ "IVORY", Color::hex(0xFFFFF0FF) },
{ "KHAKI", Color::hex(0xF0E68CFF) },
{ "LAVENDER", Color::hex(0xE6E6FAFF) },
{ "LAVENDER_BLUSH", Color::hex(0xFFF0F5FF) },
{ "LAWN_GREEN", Color::hex(0x7CFC00FF) },
{ "LEMON_CHIFFON", Color::hex(0xFFFACDFF) },
{ "LIGHT_BLUE", Color::hex(0xADD8E6FF) },
{ "LIGHT_CORAL", Color::hex(0xF08080FF) },
{ "LIGHT_CYAN", Color::hex(0xE0FFFFFF) },
{ "LIGHT_GOLDENROD", Color::hex(0xFAFAD2FF) },
{ "LIGHT_GRAY", Color::hex(0xD3D3D3FF) },
{ "LIGHT_GREEN", Color::hex(0x90EE90FF) },
{ "LIGHT_PINK", Color::hex(0xFFB6C1FF) },
{ "LIGHT_SALMON", Color::hex(0xFFA07AFF) },
{ "LIGHT_SEA_GREEN", Color::hex(0x20B2AAFF) },
{ "LIGHT_SKY_BLUE", Color::hex(0x87CEFAFF) },
{ "LIGHT_SLATE_GRAY", Color::hex(0x778899FF) },
{ "LIGHT_STEEL_BLUE", Color::hex(0xB0C4DEFF) },
{ "LIGHT_YELLOW", Color::hex(0xFFFFE0FF) },
{ "LIME", Color::hex(0x00FF00FF) },
{ "LIME_GREEN", Color::hex(0x32CD32FF) },
{ "LINEN", Color::hex(0xFAF0E6FF) },
{ "MAGENTA", Color::hex(0xFF00FFFF) },
{ "MAROON", Color::hex(0xB03060FF) },
{ "MEDIUM_AQUAMARINE", Color::hex(0x66CDAAFF) },
{ "MEDIUM_BLUE", Color::hex(0x0000CDFF) },
{ "MEDIUM_ORCHID", Color::hex(0xBA55D3FF) },
{ "MEDIUM_PURPLE", Color::hex(0x9370DBFF) },
{ "MEDIUM_SEA_GREEN", Color::hex(0x3CB371FF) },
{ "MEDIUM_SLATE_BLUE", Color::hex(0x7B68EEFF) },
{ "MEDIUM_SPRING_GREEN", Color::hex(0x00FA9AFF) },
{ "MEDIUM_TURQUOISE", Color::hex(0x48D1CCFF) },
{ "MEDIUM_VIOLET_RED", Color::hex(0xC71585FF) },
{ "MIDNIGHT_BLUE", Color::hex(0x191970FF) },
{ "MINT_CREAM", Color::hex(0xF5FFFAFF) },
{ "MISTY_ROSE", Color::hex(0xFFE4E1FF) },
{ "MOCCASIN", Color::hex(0xFFE4B5FF) },
{ "NAVAJO_WHITE", Color::hex(0xFFDEADFF) },
{ "NAVY_BLUE", Color::hex(0x000080FF) },
{ "OLD_LACE", Color::hex(0xFDF5E6FF) },
{ "OLIVE", Color::hex(0x808000FF) },
{ "OLIVE_DRAB", Color::hex(0x6B8E23FF) },
{ "ORANGE", Color::hex(0xFFA500FF) },
{ "ORANGE_RED", Color::hex(0xFF4500FF) },
{ "ORCHID", Color::hex(0xDA70D6FF) },
{ "PALE_GOLDENROD", Color::hex(0xEEE8AAFF) },
{ "PALE_GREEN", Color::hex(0x98FB98FF) },
{ "PALE_TURQUOISE", Color::hex(0xAFEEEEFF) },
{ "PALE_VIOLET_RED", Color::hex(0xDB7093FF) },
{ "PAPAYA_WHIP", Color::hex(0xFFEFD5FF) },
{ "PEACH_PUFF", Color::hex(0xFFDAB9FF) },
{ "PERU", Color::hex(0xCD853FFF) },
{ "PINK", Color::hex(0xFFC0CBFF) },
{ "PLUM", Color::hex(0xDDA0DDFF) },
{ "POWDER_BLUE", Color::hex(0xB0E0E6FF) },
{ "PURPLE", Color::hex(0xA020F0FF) },
{ "REBECCA_PURPLE", Color::hex(0x663399FF) },
{ "RED", Color::hex(0xFF0000FF) },
{ "ROSY_BROWN", Color::hex(0xBC8F8FFF) },
{ "ROYAL_BLUE", Color::hex(0x4169E1FF) },
{ "SADDLE_BROWN", Color::hex(0x8B4513FF) },
{ "SALMON", Color::hex(0xFA8072FF) },
{ "SANDY_BROWN", Color::hex(0xF4A460FF) },
{ "SEA_GREEN", Color::hex(0x2E8B57FF) },
{ "SEASHELL", Color::hex(0xFFF5EEFF) },
{ "SIENNA", Color::hex(0xA0522DFF) },
{ "SILVER", Color::hex(0xC0C0C0FF) },
{ "SKY_BLUE", Color::hex(0x87CEEBFF) },
{ "SLATE_BLUE", Color::hex(0x6A5ACDFF) },
{ "SLATE_GRAY", Color::hex(0x708090FF) },
{ "SNOW", Color::hex(0xFFFAFAFF) },
{ "SPRING_GREEN", Color::hex(0x00FF7FFF) },
{ "STEEL_BLUE", Color::hex(0x4682B4FF) },
{ "TAN", Color::hex(0xD2B48CFF) },
{ "TEAL", Color::hex(0x008080FF) },
{ "THISTLE", Color::hex(0xD8BFD8FF) },
{ "TOMATO", Color::hex(0xFF6347FF) },
{ "TRANSPARENT", Color::hex(0xFFFFFF00) },
{ "TURQUOISE", Color::hex(0x40E0D0FF) },
{ "VIOLET", Color::hex(0xEE82EEFF) },
{ "WEB_GRAY", Color::hex(0x808080FF) },
{ "WEB_GREEN", Color::hex(0x008000FF) },
{ "WEB_MAROON", Color::hex(0x800000FF) },
{ "WEB_PURPLE", Color::hex(0x800080FF) },
{ "WHEAT", Color::hex(0xF5DEB3FF) },
{ "WHITE", Color::hex(0xFFFFFFFF) },
{ "WHITE_SMOKE", Color::hex(0xF5F5F5FF) },
{ "YELLOW", Color::hex(0xFFFF00FF) },
{ "YELLOW_GREEN", Color::hex(0x9ACD32FF) },
{ nullptr, Color() },
};
} // namespace godot

View File

@@ -0,0 +1,140 @@
/**************************************************************************/
/* plane.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_PLANE_HPP
#define GODOT_PLANE_HPP
#include <godot_cpp/classes/global_constants.hpp>
#include <godot_cpp/variant/vector3.hpp>
namespace godot {
class Variant;
struct _NO_DISCARD_ Plane {
Vector3 normal;
real_t d = 0;
void set_normal(const Vector3 &p_normal);
_FORCE_INLINE_ Vector3 get_normal() const { return normal; }
void normalize();
Plane normalized() const;
/* Plane-Point operations */
_FORCE_INLINE_ Vector3 center() const { return normal * d; }
Vector3 get_any_perpendicular_normal() const;
_FORCE_INLINE_ bool is_point_over(const Vector3 &p_point) const; ///< Point is over plane
_FORCE_INLINE_ real_t distance_to(const Vector3 &p_point) const;
_FORCE_INLINE_ bool has_point(const Vector3 &p_point, real_t p_tolerance = CMP_EPSILON) const;
/* intersections */
bool intersect_3(const Plane &p_plane1, const Plane &p_plane2, Vector3 *r_result = nullptr) const;
bool intersects_ray(const Vector3 &p_from, const Vector3 &p_dir, Vector3 *p_intersection) const;
bool intersects_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 *p_intersection) const;
// For Variant bindings.
Variant intersect_3_bind(const Plane &p_plane1, const Plane &p_plane2) const;
Variant intersects_ray_bind(const Vector3 &p_from, const Vector3 &p_dir) const;
Variant intersects_segment_bind(const Vector3 &p_begin, const Vector3 &p_end) const;
_FORCE_INLINE_ Vector3 project(const Vector3 &p_point) const {
return p_point - normal * distance_to(p_point);
}
/* misc */
Plane operator-() const { return Plane(-normal, -d); }
bool is_equal_approx(const Plane &p_plane) const;
bool is_equal_approx_any_side(const Plane &p_plane) const;
_FORCE_INLINE_ bool operator==(const Plane &p_plane) const;
_FORCE_INLINE_ bool operator!=(const Plane &p_plane) const;
operator String() const;
_FORCE_INLINE_ Plane() {}
_FORCE_INLINE_ Plane(real_t p_a, real_t p_b, real_t p_c, real_t p_d) :
normal(p_a, p_b, p_c),
d(p_d) {}
_FORCE_INLINE_ Plane(const Vector3 &p_normal, real_t p_d = 0.0);
_FORCE_INLINE_ Plane(const Vector3 &p_normal, const Vector3 &p_point);
_FORCE_INLINE_ Plane(const Vector3 &p_point1, const Vector3 &p_point2, const Vector3 &p_point3, ClockDirection p_dir = CLOCKWISE);
};
bool Plane::is_point_over(const Vector3 &p_point) const {
return (normal.dot(p_point) > d);
}
real_t Plane::distance_to(const Vector3 &p_point) const {
return (normal.dot(p_point) - d);
}
bool Plane::has_point(const Vector3 &p_point, real_t p_tolerance) const {
real_t dist = normal.dot(p_point) - d;
dist = Math::abs(dist);
return (dist <= p_tolerance);
}
Plane::Plane(const Vector3 &p_normal, real_t p_d) :
normal(p_normal),
d(p_d) {
}
Plane::Plane(const Vector3 &p_normal, const Vector3 &p_point) :
normal(p_normal),
d(p_normal.dot(p_point)) {
}
Plane::Plane(const Vector3 &p_point1, const Vector3 &p_point2, const Vector3 &p_point3, ClockDirection p_dir) {
if (p_dir == CLOCKWISE) {
normal = (p_point1 - p_point3).cross(p_point1 - p_point2);
} else {
normal = (p_point1 - p_point2).cross(p_point1 - p_point3);
}
normal.normalize();
d = normal.dot(p_point1);
}
bool Plane::operator==(const Plane &p_plane) const {
return normal == p_plane.normal && d == p_plane.d;
}
bool Plane::operator!=(const Plane &p_plane) const {
return normal != p_plane.normal || d != p_plane.d;
}
} // namespace godot
#endif // GODOT_PLANE_HPP

View File

@@ -0,0 +1,171 @@
/**************************************************************************/
/* projection.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_PROJECTION_HPP
#define GODOT_PROJECTION_HPP
#include <godot_cpp/core/math.hpp>
#include <godot_cpp/variant/vector3.hpp>
#include <godot_cpp/variant/vector4.hpp>
namespace godot {
class Array;
struct AABB;
struct Plane;
struct Rect2;
struct Transform3D;
struct Vector2;
struct _NO_DISCARD_ Projection {
enum Planes {
PLANE_NEAR,
PLANE_FAR,
PLANE_LEFT,
PLANE_TOP,
PLANE_RIGHT,
PLANE_BOTTOM
};
Vector4 columns[4];
_FORCE_INLINE_ const Vector4 &operator[](const int p_axis) const {
DEV_ASSERT((unsigned int)p_axis < 4);
return columns[p_axis];
}
_FORCE_INLINE_ Vector4 &operator[](const int p_axis) {
DEV_ASSERT((unsigned int)p_axis < 4);
return columns[p_axis];
}
float determinant() const;
void set_identity();
void set_zero();
void set_light_bias();
void set_depth_correction(bool p_flip_y = true);
void set_light_atlas_rect(const Rect2 &p_rect);
void set_perspective(real_t p_fovy_degrees, real_t p_aspect, real_t p_z_near, real_t p_z_far, bool p_flip_fov = false);
void set_perspective(real_t p_fovy_degrees, real_t p_aspect, real_t p_z_near, real_t p_z_far, bool p_flip_fov, int p_eye, real_t p_intraocular_dist, real_t p_convergence_dist);
void set_for_hmd(int p_eye, real_t p_aspect, real_t p_intraocular_dist, real_t p_display_width, real_t p_display_to_lens, real_t p_oversample, real_t p_z_near, real_t p_z_far);
void set_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);
void set_orthogonal(real_t p_size, real_t p_aspect, real_t p_znear, real_t p_zfar, bool p_flip_fov = false);
void set_frustum(real_t p_left, real_t p_right, real_t p_bottom, real_t p_top, real_t p_near, real_t p_far);
void set_frustum(real_t p_size, real_t p_aspect, Vector2 p_offset, real_t p_near, real_t p_far, bool p_flip_fov = false);
void adjust_perspective_znear(real_t p_new_znear);
static Projection create_depth_correction(bool p_flip_y);
static Projection create_light_atlas_rect(const Rect2 &p_rect);
static Projection create_perspective(real_t p_fovy_degrees, real_t p_aspect, real_t p_z_near, real_t p_z_far, bool p_flip_fov = false);
static Projection create_perspective_hmd(real_t p_fovy_degrees, real_t p_aspect, real_t p_z_near, real_t p_z_far, bool p_flip_fov, int p_eye, real_t p_intraocular_dist, real_t p_convergence_dist);
static Projection create_for_hmd(int p_eye, real_t p_aspect, real_t p_intraocular_dist, real_t p_display_width, real_t p_display_to_lens, real_t p_oversample, real_t p_z_near, real_t p_z_far);
static 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);
static Projection create_orthogonal_aspect(real_t p_size, real_t p_aspect, real_t p_znear, real_t p_zfar, bool p_flip_fov = false);
static Projection create_frustum(real_t p_left, real_t p_right, real_t p_bottom, real_t p_top, real_t p_near, real_t p_far);
static Projection create_frustum_aspect(real_t p_size, real_t p_aspect, Vector2 p_offset, real_t p_near, real_t p_far, bool p_flip_fov = false);
static Projection create_fit_aabb(const AABB &p_aabb);
Projection perspective_znear_adjusted(real_t p_new_znear) const;
Plane get_projection_plane(Planes p_plane) const;
Projection flipped_y() const;
Projection jitter_offseted(const Vector2 &p_offset) const;
static real_t get_fovy(real_t p_fovx, real_t p_aspect) {
return Math::rad_to_deg(Math::atan(p_aspect * Math::tan(Math::deg_to_rad(p_fovx) * 0.5)) * 2.0);
}
real_t get_z_far() const;
real_t get_z_near() const;
real_t get_aspect() const;
real_t get_fov() const;
bool is_orthogonal() const;
Array get_projection_planes(const Transform3D &p_transform) const;
bool get_endpoints(const Transform3D &p_transform, Vector3 *p_8points) const;
Vector2 get_viewport_half_extents() const;
Vector2 get_far_plane_half_extents() const;
void invert();
Projection inverse() const;
Projection operator*(const Projection &p_matrix) const;
Plane xform4(const Plane &p_vec4) const;
_FORCE_INLINE_ Vector3 xform(const Vector3 &p_vec3) const;
Vector4 xform(const Vector4 &p_vec4) const;
Vector4 xform_inv(const Vector4 &p_vec4) const;
operator String() const;
void scale_translate_to_fit(const AABB &p_aabb);
void add_jitter_offset(const Vector2 &p_offset);
void make_scale(const Vector3 &p_scale);
int get_pixels_per_meter(int p_for_pixel_width) const;
operator Transform3D() const;
void flip_y();
bool operator==(const Projection &p_cam) const {
for (uint32_t i = 0; i < 4; i++) {
for (uint32_t j = 0; j < 4; j++) {
if (columns[i][j] != p_cam.columns[i][j]) {
return false;
}
}
}
return true;
}
bool operator!=(const Projection &p_cam) const {
return !(*this == p_cam);
}
float get_lod_multiplier() const;
Projection();
Projection(const Vector4 &p_x, const Vector4 &p_y, const Vector4 &p_z, const Vector4 &p_w);
Projection(const Transform3D &p_transform);
~Projection();
};
Vector3 Projection::xform(const Vector3 &p_vec3) const {
Vector3 ret;
ret.x = columns[0][0] * p_vec3.x + columns[1][0] * p_vec3.y + columns[2][0] * p_vec3.z + columns[3][0];
ret.y = columns[0][1] * p_vec3.x + columns[1][1] * p_vec3.y + columns[2][1] * p_vec3.z + columns[3][1];
ret.z = columns[0][2] * p_vec3.x + columns[1][2] * p_vec3.y + columns[2][2] * p_vec3.z + columns[3][2];
real_t w = columns[0][3] * p_vec3.x + columns[1][3] * p_vec3.y + columns[2][3] * p_vec3.z + columns[3][3];
return ret / w;
}
} // namespace godot
#endif // GODOT_PROJECTION_HPP

View File

@@ -0,0 +1,237 @@
/**************************************************************************/
/* quaternion.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_QUATERNION_HPP
#define GODOT_QUATERNION_HPP
#include <godot_cpp/core/math.hpp>
#include <godot_cpp/variant/vector3.hpp>
namespace godot {
struct _NO_DISCARD_ Quaternion {
union {
struct {
real_t x;
real_t y;
real_t z;
real_t w;
};
real_t components[4] = { 0, 0, 0, 1.0 };
};
_FORCE_INLINE_ real_t &operator[](int idx) {
return components[idx];
}
_FORCE_INLINE_ const real_t &operator[](int idx) const {
return components[idx];
}
_FORCE_INLINE_ real_t length_squared() const;
bool is_equal_approx(const Quaternion &p_quaternion) const;
real_t length() const;
void normalize();
Quaternion normalized() const;
bool is_normalized() const;
Quaternion inverse() const;
Quaternion log() const;
Quaternion exp() const;
_FORCE_INLINE_ real_t dot(const Quaternion &p_q) const;
real_t angle_to(const Quaternion &p_to) const;
Vector3 get_euler_xyz() const;
Vector3 get_euler_yxz() const;
Vector3 get_euler() const { return get_euler_yxz(); }
Quaternion slerp(const Quaternion &p_to, const real_t &p_weight) const;
Quaternion slerpni(const Quaternion &p_to, const real_t &p_weight) const;
Quaternion spherical_cubic_interpolate(const Quaternion &p_b, const Quaternion &p_pre_a, const Quaternion &p_post_b, const real_t &p_weight) const;
Quaternion spherical_cubic_interpolate_in_time(const Quaternion &p_b, const Quaternion &p_pre_a, const Quaternion &p_post_b, const real_t &p_weight, const real_t &p_b_t, const real_t &p_pre_a_t, const real_t &p_post_b_t) const;
Vector3 get_axis() const;
real_t get_angle() const;
_FORCE_INLINE_ void get_axis_angle(Vector3 &r_axis, real_t &r_angle) const {
r_angle = 2 * Math::acos(w);
real_t r = ((real_t)1) / Math::sqrt(1 - w * w);
r_axis.x = x * r;
r_axis.y = y * r;
r_axis.z = z * r;
}
void operator*=(const Quaternion &p_q);
Quaternion operator*(const Quaternion &p_q) const;
_FORCE_INLINE_ Vector3 xform(const Vector3 &v) const {
#ifdef MATH_CHECKS
ERR_FAIL_COND_V_MSG(!is_normalized(), v, "The quaternion must be normalized.");
#endif
Vector3 u(x, y, z);
Vector3 uv = u.cross(v);
return v + ((uv * w) + u.cross(uv)) * ((real_t)2);
}
_FORCE_INLINE_ Vector3 xform_inv(const Vector3 &v) const {
return inverse().xform(v);
}
_FORCE_INLINE_ void operator+=(const Quaternion &p_q);
_FORCE_INLINE_ void operator-=(const Quaternion &p_q);
_FORCE_INLINE_ void operator*=(const real_t &s);
_FORCE_INLINE_ void operator/=(const real_t &s);
_FORCE_INLINE_ Quaternion operator+(const Quaternion &q2) const;
_FORCE_INLINE_ Quaternion operator-(const Quaternion &q2) const;
_FORCE_INLINE_ Quaternion operator-() const;
_FORCE_INLINE_ Quaternion operator*(const real_t &s) const;
_FORCE_INLINE_ Quaternion operator/(const real_t &s) const;
_FORCE_INLINE_ bool operator==(const Quaternion &p_quaternion) const;
_FORCE_INLINE_ bool operator!=(const Quaternion &p_quaternion) const;
operator String() const;
_FORCE_INLINE_ Quaternion() {}
_FORCE_INLINE_ Quaternion(real_t p_x, real_t p_y, real_t p_z, real_t p_w) :
x(p_x),
y(p_y),
z(p_z),
w(p_w) {
}
Quaternion(const Vector3 &p_axis, real_t p_angle);
Quaternion(const Vector3 &p_euler);
Quaternion(const Quaternion &p_q) :
x(p_q.x),
y(p_q.y),
z(p_q.z),
w(p_q.w) {
}
void operator=(const Quaternion &p_q) {
x = p_q.x;
y = p_q.y;
z = p_q.z;
w = p_q.w;
}
Quaternion(const Vector3 &v0, const Vector3 &v1) { // Shortest arc.
Vector3 c = v0.cross(v1);
real_t d = v0.dot(v1);
if (d < -1.0f + (real_t)CMP_EPSILON) {
x = 0;
y = 1;
z = 0;
w = 0;
} else {
real_t s = Math::sqrt((1.0f + d) * 2.0f);
real_t rs = 1.0f / s;
x = c.x * rs;
y = c.y * rs;
z = c.z * rs;
w = s * 0.5f;
}
}
};
real_t Quaternion::dot(const Quaternion &p_q) const {
return x * p_q.x + y * p_q.y + z * p_q.z + w * p_q.w;
}
real_t Quaternion::length_squared() const {
return dot(*this);
}
void Quaternion::operator+=(const Quaternion &p_q) {
x += p_q.x;
y += p_q.y;
z += p_q.z;
w += p_q.w;
}
void Quaternion::operator-=(const Quaternion &p_q) {
x -= p_q.x;
y -= p_q.y;
z -= p_q.z;
w -= p_q.w;
}
void Quaternion::operator*=(const real_t &s) {
x *= s;
y *= s;
z *= s;
w *= s;
}
void Quaternion::operator/=(const real_t &s) {
*this *= 1.0f / s;
}
Quaternion Quaternion::operator+(const Quaternion &q2) const {
const Quaternion &q1 = *this;
return Quaternion(q1.x + q2.x, q1.y + q2.y, q1.z + q2.z, q1.w + q2.w);
}
Quaternion Quaternion::operator-(const Quaternion &q2) const {
const Quaternion &q1 = *this;
return Quaternion(q1.x - q2.x, q1.y - q2.y, q1.z - q2.z, q1.w - q2.w);
}
Quaternion Quaternion::operator-() const {
const Quaternion &q2 = *this;
return Quaternion(-q2.x, -q2.y, -q2.z, -q2.w);
}
Quaternion Quaternion::operator*(const real_t &s) const {
return Quaternion(x * s, y * s, z * s, w * s);
}
Quaternion Quaternion::operator/(const real_t &s) const {
return *this * (1.0f / s);
}
bool Quaternion::operator==(const Quaternion &p_quaternion) const {
return x == p_quaternion.x && y == p_quaternion.y && z == p_quaternion.z && w == p_quaternion.w;
}
bool Quaternion::operator!=(const Quaternion &p_quaternion) const {
return x != p_quaternion.x || y != p_quaternion.y || z != p_quaternion.z || w != p_quaternion.w;
}
_FORCE_INLINE_ Quaternion operator*(const real_t &p_real, const Quaternion &p_quaternion) {
return p_quaternion * p_real;
}
} // namespace godot
#endif // GODOT_QUATERNION_HPP

View File

@@ -0,0 +1,376 @@
/**************************************************************************/
/* rect2.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_RECT2_HPP
#define GODOT_RECT2_HPP
#include <godot_cpp/classes/global_constants.hpp>
#include <godot_cpp/variant/vector2.hpp>
namespace godot {
class String;
struct Rect2i;
struct Transform2D;
struct _NO_DISCARD_ Rect2 {
Point2 position;
Size2 size;
const Vector2 &get_position() const { return position; }
void set_position(const Vector2 &p_pos) { position = p_pos; }
const Vector2 &get_size() const { return size; }
void set_size(const Vector2 &p_size) { size = p_size; }
real_t get_area() const { return size.width * size.height; }
_FORCE_INLINE_ Vector2 get_center() const { return position + (size * 0.5f); }
inline bool intersects(const Rect2 &p_rect, const bool p_include_borders = false) const {
#ifdef MATH_CHECKS
if (unlikely(size.x < 0 || size.y < 0 || p_rect.size.x < 0 || p_rect.size.y < 0)) {
ERR_PRINT("Rect2 size is negative, this is not supported. Use Rect2.abs() to get a Rect2 with a positive size.");
}
#endif
if (p_include_borders) {
if (position.x > (p_rect.position.x + p_rect.size.width)) {
return false;
}
if ((position.x + size.width) < p_rect.position.x) {
return false;
}
if (position.y > (p_rect.position.y + p_rect.size.height)) {
return false;
}
if ((position.y + size.height) < p_rect.position.y) {
return false;
}
} else {
if (position.x >= (p_rect.position.x + p_rect.size.width)) {
return false;
}
if ((position.x + size.width) <= p_rect.position.x) {
return false;
}
if (position.y >= (p_rect.position.y + p_rect.size.height)) {
return false;
}
if ((position.y + size.height) <= p_rect.position.y) {
return false;
}
}
return true;
}
inline real_t distance_to(const Vector2 &p_point) const {
#ifdef MATH_CHECKS
if (unlikely(size.x < 0 || size.y < 0)) {
ERR_PRINT("Rect2 size is negative, this is not supported. Use Rect2.abs() to get a Rect2 with a positive size.");
}
#endif
real_t dist = 0.0;
bool inside = true;
if (p_point.x < position.x) {
real_t d = position.x - p_point.x;
dist = d;
inside = false;
}
if (p_point.y < position.y) {
real_t d = position.y - p_point.y;
dist = inside ? d : Math::min(dist, d);
inside = false;
}
if (p_point.x >= (position.x + size.x)) {
real_t d = p_point.x - (position.x + size.x);
dist = inside ? d : Math::min(dist, d);
inside = false;
}
if (p_point.y >= (position.y + size.y)) {
real_t d = p_point.y - (position.y + size.y);
dist = inside ? d : Math::min(dist, d);
inside = false;
}
if (inside) {
return 0;
} else {
return dist;
}
}
bool intersects_transformed(const Transform2D &p_xform, const Rect2 &p_rect) const;
bool intersects_segment(const Point2 &p_from, const Point2 &p_to, Point2 *r_pos = nullptr, Point2 *r_normal = nullptr) const;
inline bool encloses(const Rect2 &p_rect) const {
#ifdef MATH_CHECKS
if (unlikely(size.x < 0 || size.y < 0 || p_rect.size.x < 0 || p_rect.size.y < 0)) {
ERR_PRINT("Rect2 size is negative, this is not supported. Use Rect2.abs() to get a Rect2 with a positive size.");
}
#endif
return (p_rect.position.x >= position.x) && (p_rect.position.y >= position.y) &&
((p_rect.position.x + p_rect.size.x) <= (position.x + size.x)) &&
((p_rect.position.y + p_rect.size.y) <= (position.y + size.y));
}
_FORCE_INLINE_ bool has_area() const {
return size.x > 0.0f && size.y > 0.0f;
}
// Returns the instersection between two Rect2s or an empty Rect2 if there is no intersection
inline Rect2 intersection(const Rect2 &p_rect) const {
Rect2 new_rect = p_rect;
if (!intersects(new_rect)) {
return Rect2();
}
new_rect.position.x = Math::max(p_rect.position.x, position.x);
new_rect.position.y = Math::max(p_rect.position.y, position.y);
Point2 p_rect_end = p_rect.position + p_rect.size;
Point2 end = position + size;
new_rect.size.x = Math::min(p_rect_end.x, end.x) - new_rect.position.x;
new_rect.size.y = Math::min(p_rect_end.y, end.y) - new_rect.position.y;
return new_rect;
}
inline Rect2 merge(const Rect2 &p_rect) const { ///< return a merged rect
#ifdef MATH_CHECKS
if (unlikely(size.x < 0 || size.y < 0 || p_rect.size.x < 0 || p_rect.size.y < 0)) {
ERR_PRINT("Rect2 size is negative, this is not supported. Use Rect2.abs() to get a Rect2 with a positive size.");
}
#endif
Rect2 new_rect;
new_rect.position.x = Math::min(p_rect.position.x, position.x);
new_rect.position.y = Math::min(p_rect.position.y, position.y);
new_rect.size.x = Math::max(p_rect.position.x + p_rect.size.x, position.x + size.x);
new_rect.size.y = Math::max(p_rect.position.y + p_rect.size.y, position.y + size.y);
new_rect.size = new_rect.size - new_rect.position; // Make relative again.
return new_rect;
}
inline bool has_point(const Point2 &p_point) const {
#ifdef MATH_CHECKS
if (unlikely(size.x < 0 || size.y < 0)) {
ERR_PRINT("Rect2 size is negative, this is not supported. Use Rect2.abs() to get a Rect2 with a positive size.");
}
#endif
if (p_point.x < position.x) {
return false;
}
if (p_point.y < position.y) {
return false;
}
if (p_point.x >= (position.x + size.x)) {
return false;
}
if (p_point.y >= (position.y + size.y)) {
return false;
}
return true;
}
bool is_equal_approx(const Rect2 &p_rect) const;
bool operator==(const Rect2 &p_rect) const { return position == p_rect.position && size == p_rect.size; }
bool operator!=(const Rect2 &p_rect) const { return position != p_rect.position || size != p_rect.size; }
inline Rect2 grow(real_t p_amount) const {
Rect2 g = *this;
g.grow_by(p_amount);
return g;
}
inline void grow_by(real_t p_amount) {
position.x -= p_amount;
position.y -= p_amount;
size.width += p_amount * 2;
size.height += p_amount * 2;
}
inline Rect2 grow_side(Side p_side, real_t p_amount) const {
Rect2 g = *this;
g = g.grow_individual((SIDE_LEFT == p_side) ? p_amount : 0,
(SIDE_TOP == p_side) ? p_amount : 0,
(SIDE_RIGHT == p_side) ? p_amount : 0,
(SIDE_BOTTOM == p_side) ? p_amount : 0);
return g;
}
inline Rect2 grow_side_bind(uint32_t p_side, real_t p_amount) const {
return grow_side(Side(p_side), p_amount);
}
inline Rect2 grow_individual(real_t p_left, real_t p_top, real_t p_right, real_t p_bottom) const {
Rect2 g = *this;
g.position.x -= p_left;
g.position.y -= p_top;
g.size.width += p_left + p_right;
g.size.height += p_top + p_bottom;
return g;
}
_FORCE_INLINE_ Rect2 expand(const Vector2 &p_vector) const {
Rect2 r = *this;
r.expand_to(p_vector);
return r;
}
inline void expand_to(const Vector2 &p_vector) { // In place function for speed.
#ifdef MATH_CHECKS
if (unlikely(size.x < 0 || size.y < 0)) {
ERR_PRINT("Rect2 size is negative, this is not supported. Use Rect2.abs() to get a Rect2 with a positive size.");
}
#endif
Vector2 begin = position;
Vector2 end = position + size;
if (p_vector.x < begin.x) {
begin.x = p_vector.x;
}
if (p_vector.y < begin.y) {
begin.y = p_vector.y;
}
if (p_vector.x > end.x) {
end.x = p_vector.x;
}
if (p_vector.y > end.y) {
end.y = p_vector.y;
}
position = begin;
size = end - begin;
}
_FORCE_INLINE_ Rect2 abs() const {
return Rect2(Point2(position.x + Math::min(size.x, (real_t)0), position.y + Math::min(size.y, (real_t)0)), size.abs());
}
Vector2 get_support(const Vector2 &p_normal) const {
Vector2 half_extents = size * 0.5f;
Vector2 ofs = position + half_extents;
return Vector2(
(p_normal.x > 0) ? -half_extents.x : half_extents.x,
(p_normal.y > 0) ? -half_extents.y : half_extents.y) +
ofs;
}
_FORCE_INLINE_ bool intersects_filled_polygon(const Vector2 *p_points, int p_point_count) const {
Vector2 center = get_center();
int side_plus = 0;
int side_minus = 0;
Vector2 end = position + size;
int i_f = p_point_count - 1;
for (int i = 0; i < p_point_count; i++) {
const Vector2 &a = p_points[i_f];
const Vector2 &b = p_points[i];
i_f = i;
Vector2 r = (b - a);
float l = r.length();
if (l == 0.0f) {
continue;
}
// Check inside.
Vector2 tg = r.orthogonal();
float s = tg.dot(center) - tg.dot(a);
if (s < 0.0f) {
side_plus++;
} else {
side_minus++;
}
// Check ray box.
r /= l;
Vector2 ir(1.0f / r.x, 1.0f / r.y);
// lb is the corner of AABB with minimal coordinates - left bottom, rt is maximal corner
// r.org is origin of ray
Vector2 t13 = (position - a) * ir;
Vector2 t24 = (end - a) * ir;
float tmin = Math::max(Math::min(t13.x, t24.x), Math::min(t13.y, t24.y));
float tmax = Math::min(Math::max(t13.x, t24.x), Math::max(t13.y, t24.y));
// if tmax < 0, ray (line) is intersecting AABB, but the whole AABB is behind us
if (tmax < 0 || tmin > tmax || tmin >= l) {
continue;
}
return true;
}
if (side_plus * side_minus == 0) {
return true; // All inside.
} else {
return false;
}
}
_FORCE_INLINE_ void set_end(const Vector2 &p_end) {
size = p_end - position;
}
_FORCE_INLINE_ Vector2 get_end() const {
return position + size;
}
operator String() const;
operator Rect2i() const;
Rect2() {}
Rect2(real_t p_x, real_t p_y, real_t p_width, real_t p_height) :
position(Point2(p_x, p_y)),
size(Size2(p_width, p_height)) {
}
Rect2(const Point2 &p_pos, const Size2 &p_size) :
position(p_pos),
size(p_size) {
}
};
} // namespace godot
#endif // GODOT_RECT2_HPP

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